refactor: lazy load cli gateway helper runtimes

This commit is contained in:
Shakker 2026-04-01 21:08:14 +01:00 committed by Peter Steinberger
parent 58f1044ec0
commit 36c8282795
4 changed files with 65 additions and 26 deletions

View File

@ -0,0 +1 @@
export { buildGatewayConnectionDetails } from "../gateway/call.js";

View File

@ -1,6 +1,5 @@
import { setTimeout as delay } from "node:timers/promises";
import type { Command } from "commander";
import { buildGatewayConnectionDetails } from "../gateway/call.js";
import { parseLogLine } from "../logging/parse-log-line.js";
import { formatTimestamp, isValidTimeZone } from "../logging/timestamps.js";
import { formatDocsLink } from "../terminal/links.js";
@ -10,6 +9,15 @@ import { colorize, isRich, theme } from "../terminal/theme.js";
import { formatCliCommand } from "./command-format.js";
import { addGatewayClientOptions, callGatewayFromCli } from "./gateway-rpc.js";
type LogsCliRuntimeModule = typeof import("./logs-cli.runtime.js");
let logsCliRuntimePromise: Promise<LogsCliRuntimeModule> | undefined;
async function loadLogsCliRuntime(): Promise<LogsCliRuntimeModule> {
logsCliRuntimePromise ??= import("./logs-cli.runtime.js");
return logsCliRuntimePromise;
}
type LogsTailPayload = {
file?: string;
cursor?: number;
@ -149,7 +157,7 @@ function createLogWriters() {
};
}
function emitGatewayError(
async function emitGatewayError(
err: unknown,
opts: LogsCliOptions,
mode: "json" | "text",
@ -157,11 +165,12 @@ function emitGatewayError(
emitJsonLine: (payload: Record<string, unknown>, toStdErr?: boolean) => boolean,
errorLine: (text: string) => boolean,
) {
const details = buildGatewayConnectionDetails({ url: opts.url });
const runtime = await loadLogsCliRuntime();
const message = "Gateway not reachable. Is it running and accessible?";
const hint = `Hint: run \`${formatCliCommand("openclaw doctor")}\`.`;
const errorText = err instanceof Error ? err.message : String(err);
const details = runtime.buildGatewayConnectionDetails({ url: opts.url });
if (mode === "json") {
if (
!emitJsonLine(
@ -227,7 +236,14 @@ export function registerLogsCli(program: Command) {
try {
payload = await fetchLogs(opts, cursor, showProgress);
} catch (err) {
emitGatewayError(err, opts, jsonMode ? "json" : "text", rich, emitJsonLine, errorLine);
await emitGatewayError(
err,
opts,
jsonMode ? "json" : "text",
rich,
emitJsonLine,
errorLine,
);
process.exit(1);
return;
}

View File

@ -0,0 +1,29 @@
import { callGateway } from "../../gateway/call.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
import { withProgress } from "../progress.js";
import type { NodesRpcOpts } from "./types.js";
export async function callGatewayCliRuntime(
method: string,
opts: NodesRpcOpts,
params?: unknown,
callOpts?: { transportTimeoutMs?: number },
) {
return await withProgress(
{
label: `Nodes ${method}`,
indeterminate: true,
enabled: opts.json !== true,
},
async () =>
await callGateway({
url: opts.url,
token: opts.token,
method,
params,
timeoutMs: callOpts?.transportTimeoutMs ?? Number(opts.timeout ?? 10_000),
clientName: GATEWAY_CLIENT_NAMES.CLI,
mode: GATEWAY_CLIENT_MODES.CLI,
}),
);
}

View File

@ -1,11 +1,18 @@
import { randomUUID } from "node:crypto";
import type { Command } from "commander";
import { callGateway, randomIdempotencyKey } from "../../gateway/call.js";
import { resolveNodeFromNodeList } from "../../shared/node-resolve.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
import { withProgress } from "../progress.js";
import { parseNodeList, parsePairingList } from "./format.js";
import type { NodeListNode, NodesRpcOpts } from "./types.js";
type NodesCliRpcRuntimeModule = typeof import("./rpc.runtime.js");
let nodesCliRpcRuntimePromise: Promise<NodesCliRpcRuntimeModule> | undefined;
async function loadNodesCliRpcRuntime(): Promise<NodesCliRpcRuntimeModule> {
nodesCliRpcRuntimePromise ??= import("./rpc.runtime.js");
return nodesCliRpcRuntimePromise;
}
export const nodesCallOpts = (cmd: Command, defaults?: { timeoutMs?: number }) =>
cmd
.option("--url <url>", "Gateway WebSocket URL (defaults to gateway.remote.url when configured)")
@ -18,24 +25,10 @@ export const callGatewayCli = async (
opts: NodesRpcOpts,
params?: unknown,
callOpts?: { transportTimeoutMs?: number },
) =>
withProgress(
{
label: `Nodes ${method}`,
indeterminate: true,
enabled: opts.json !== true,
},
async () =>
await callGateway({
url: opts.url,
token: opts.token,
method,
params,
timeoutMs: callOpts?.transportTimeoutMs ?? Number(opts.timeout ?? 10_000),
clientName: GATEWAY_CLIENT_NAMES.CLI,
mode: GATEWAY_CLIENT_MODES.CLI,
}),
);
) => {
const runtime = await loadNodesCliRpcRuntime();
return await runtime.callGatewayCliRuntime(method, opts, params, callOpts);
};
export function buildNodeInvokeParams(params: {
nodeId: string;
@ -48,7 +41,7 @@ export function buildNodeInvokeParams(params: {
nodeId: params.nodeId,
command: params.command,
params: params.params,
idempotencyKey: params.idempotencyKey ?? randomIdempotencyKey(),
idempotencyKey: params.idempotencyKey ?? randomUUID(),
};
if (typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs)) {
invokeParams.timeoutMs = params.timeoutMs;