import type { Command } from "commander" ;
import { danger } from "../globals.js" ;
import { defaultRuntime } from "../runtime.js" ;
import { normalizeOptionalString } from "../shared/string-coerce.js" ;
import { formatDocsLink } from "../terminal/links.js" ;
import { theme } from "../terminal/theme.js" ;
import type { GatewayRpcOpts } from "./gateway-rpc.js" ;
import { addGatewayClientOptions, callGatewayFromCli } from "./gateway-rpc.js" ;
type SystemEventOpts = GatewayRpcOpts & { text?: string; mode?: string; json?: boolean };
type SystemGatewayOpts = GatewayRpcOpts & { json?: boolean };
const normalizeWakeMode = (raw: unknown) => {
const mode = normalizeOptionalString(raw) ?? "" ;
if (!mode) {
return "next-heartbeat" as const ;
}
if (mode === "now" || mode === "next-heartbeat" ) {
return mode;
}
throw new Error("--mode must be now or next-heartbeat" );
};
async function runSystemGatewayCommand(
opts: SystemGatewayOpts,
action: () => Promise<unknown>,
successText?: string,
): Promise<void > {
try {
const result = await action();
if (opts.json || successText === undefined) {
defaultRuntime.writeJson(result);
} else {
defaultRuntime.log(successText);
}
} catch (err) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1 );
}
}
export function registerSystemCli(program: Command) {
const system = program
.command("system" )
.description("System tools (events, heartbeat, presence)" )
.addHelpText(
"after" ,
() =>
`\n${theme.muted("Docs:" )} ${formatDocsLink("/cli/system" , "docs.openclaw.ai/cli/system" )}\n`,
);
addGatewayClientOptions(
system
.command("event" )
.description("Enqueue a system event and optionally trigger a heartbeat" )
.requiredOption("--text <text>" , "System event text" )
.option("--mode <mode>" , "Wake mode (now|next-heartbeat)" , "next-heartbeat" )
.option("--json" , "Output JSON" , false ),
).action(async (opts: SystemEventOpts) => {
await runSystemGatewayCommand(
opts,
async () => {
const text = normalizeOptionalString(opts.text) ?? "" ;
if (!text) {
throw new Error("--text is required" );
}
const mode = normalizeWakeMode(opts.mode);
return await callGatewayFromCli("wake" , opts, { mode, text }, { expectFinal: false });
},
"ok" ,
);
});
const heartbeat = system.command("heartbeat" ).description("Heartbeat controls" );
addGatewayClientOptions(
heartbeat
.command("last" )
.description("Show the last heartbeat event" )
.option("--json" , "Output JSON" , false ),
).action(async (opts: SystemGatewayOpts) => {
await runSystemGatewayCommand(opts, async () => {
return await callGatewayFromCli("last-heartbeat" , opts, undefined, {
expectFinal: false ,
});
});
});
addGatewayClientOptions(
heartbeat
.command("enable" )
.description("Enable heartbeats" )
.option("--json" , "Output JSON" , false ),
).action(async (opts: SystemGatewayOpts) => {
await runSystemGatewayCommand(opts, async () => {
return await callGatewayFromCli(
"set-heartbeats" ,
opts,
{ enabled: true },
{ expectFinal: false },
);
});
});
addGatewayClientOptions(
heartbeat
.command("disable" )
.description("Disable heartbeats" )
.option("--json" , "Output JSON" , false ),
).action(async (opts: SystemGatewayOpts) => {
await runSystemGatewayCommand(opts, async () => {
return await callGatewayFromCli(
"set-heartbeats" ,
opts,
{ enabled: false },
{ expectFinal: false },
);
});
});
addGatewayClientOptions(
system
.command("presence" )
.description("List system presence entries" )
.option("--json" , "Output JSON" , false ),
).action(async (opts: SystemGatewayOpts) => {
await runSystemGatewayCommand(opts, async () => {
return await callGatewayFromCli("system-presence" , opts, undefined, {
expectFinal: false ,
});
});
});
}
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-09)
¤
*© Formatika GbR, Deutschland