openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
126 lines (125 loc) • 7.95 kB
JavaScript
import { a as writeRuntimeJson, r as defaultRuntime } from "./runtime-DlO3PTAd.mjs";
import { r as theme } from "./theme-DzaUZY4q.mjs";
import { t as formatDocsLink } from "./links-4Bgsoz0M.mjs";
import { n as inheritOptionFromParent } from "./command-options-BDuSHeWG.mjs";
import { l as publicKeyRawBase64UrlFromEd25519Pem } from "./ed25519-signature-D_xiObSW.mjs";
import "./device-identity-KmxGQO-v.mjs";
import { t as loadDeviceIdentityIfPresentAsync } from "./device-identity-async-CWlunAqt.mjs";
import { r as formatInvalidPortOption } from "./error-format-BaRMqGR7.mjs";
import { n as createNodeWorkerCommand, t as addNodeCommandOptions } from "./command-options-5SoYNuSl.mjs";
import { a as loadNodeHostConfig } from "./config-D52z6ftm.mjs";
import { n as formatHelpExamples } from "./help-format-xds_bDSp.mjs";
import { n as resolveNodePairGatewayOptions, t as resolveNodeGatewayOptions } from "./gateway-options-BVm6Fuf0.mjs";
import { Option } from "commander";
//#region src/cli/node-cli/identity.ts
/**
* Read-only by design: the SSH-verified pairing probe calls this remotely and
* must never mint a fresh identity on a host that has not run the node host.
*/
async function runNodeIdentityShow(opts) {
const identity = await loadDeviceIdentityIfPresentAsync();
if (!identity) {
defaultRuntime.error("no node device identity found (start the node host once with `openclaw node run` or `openclaw node install`)");
defaultRuntime.exit(1);
return;
}
const payload = {
deviceId: identity.deviceId,
publicKey: publicKeyRawBase64UrlFromEd25519Pem(identity.publicKeyPem)
};
if (opts.json) {
writeRuntimeJson(defaultRuntime, payload, 0);
return;
}
defaultRuntime.log(`deviceId: ${payload.deviceId}`);
defaultRuntime.log(`publicKey: ${payload.publicKey}`);
}
//#endregion
//#region src/cli/node-cli/register.ts
function addNodeGatewayOptions(command) {
return command.option("--host <host>", "Gateway host").option("--port <port>", "Gateway port").option("--context-path <path>", "Gateway WebSocket context path (e.g. /openclaw-gw)").option("--tls", "Use TLS for the gateway connection").option("--no-tls", "Disable TLS for the gateway connection").option("--tls-fingerprint <sha256>", "Expected TLS certificate fingerprint (sha256)").option("--node-id <id>", "Override the generated node instance id").option("--display-name <name>", "Override node display name");
}
function registerNodeCli(program) {
const node = addNodeCommandOptions(program.command("node").description("Run and manage the headless node host service")).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
["openclaw node run --host 127.0.0.1 --port 18789", "Run the node host in the foreground."],
["openclaw node status", "Check node host service status."],
["openclaw node install", "Install the node host service."],
["openclaw node start", "Start the installed node host service."],
["openclaw node restart", "Restart the installed node host service."]
])}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/node", "docs.openclaw.ai/cli/node")}\n`);
node.addCommand(createNodeWorkerCommand().action(async (opts) => {
const { runNodeHostWorker } = await import("./worker-B4k4s_bN.mjs");
await runNodeHostWorker({ desktopSharingEnabled: opts.desktopSharing });
}), { hidden: true });
addNodeGatewayOptions(addNodeCommandOptions(node.command("run").description("Run the headless node host (foreground)")).option("--pair <code-or-url>", "Pair with a setup code or oc-pair URL; explicit gateway flags take precedence").addOption(new Option("--pair-if-needed <code-or-url>", "Use the saved device token when available; otherwise pair with this setup code").conflicts("pair"))).option("--session-host", "Host worker sessions for this foreground process").addOption(new Option("--ephemeral").hideHelp()).addOption(new Option("--desktop-sharing").hideHelp()).addOption(new Option("--no-desktop-sharing").hideHelp()).addOption(new Option("--auth-from-env").hideHelp()).addOption(new Option("--parent-stdin").hideHelp()).option("--share-installed-apps", "Share installed macOS applications with the Gateway").option("--no-share-installed-apps", "Disable installed application sharing").action(async (opts, command) => {
let pair;
let gatewayOptions;
try {
const setupCode = opts.pair ?? opts.pairIfNeeded;
pair = setupCode ? resolveNodePairGatewayOptions(setupCode, { allowExpired: opts.pairIfNeeded !== void 0 }) : void 0;
const existing = await loadNodeHostConfig();
gatewayOptions = resolveNodeGatewayOptions(opts, existing, pair);
} catch (error) {
defaultRuntime.error(error instanceof Error ? error.message : String(error));
defaultRuntime.exit(1);
return;
}
const { host, port, contextPath, tls, tlsFingerprint, cloudflareAccess, gatewayCandidates } = gatewayOptions;
if (port === null) {
defaultRuntime.error(formatInvalidPortOption("--port"));
defaultRuntime.exit(1);
return;
}
if (opts.tls === false && opts.tlsFingerprint !== void 0) {
defaultRuntime.error("--no-tls cannot be combined with --tls-fingerprint");
defaultRuntime.exit(1);
return;
}
const { runNodeHost } = await import("./runner-we1vyYSU.mjs");
await runNodeHost({
gatewayHost: host,
gatewayPort: port,
gatewayTls: tls,
gatewayTlsFingerprint: tlsFingerprint,
gatewayContextPath: contextPath,
gatewayCloudflareAccess: cloudflareAccess,
gatewayCandidates,
gatewayBootstrapToken: pair?.bootstrapToken,
gatewayBootstrapExpiresAtMs: pair?.expiresAtMs,
preferGatewayBootstrapToken: opts.pair !== void 0,
...opts.ephemeral === true || opts.sessionHost === true ? { forceWorkerRuns: true } : {},
...opts.ephemeral === true ? { ephemeral: true } : {},
nodeId: opts.nodeId,
displayName: opts.displayName,
installedAppsSharing: opts.shareInstalledApps,
desktopSharingEnabled: opts.desktopSharing,
gatewayAuthFromEnv: opts.authFromEnv,
parentStdin: opts.parentStdin,
commands: opts.commands ?? inheritOptionFromParent(command, "commands"),
allCommands: opts.allCommands ?? inheritOptionFromParent(command, "allCommands")
});
});
node.command("status").description("Show node host status").option("--json", "Output JSON", false).action(async (opts) => {
const { runNodeDaemonStatus } = await import("./daemon-D8aSo5Vr.mjs");
await runNodeDaemonStatus(opts);
});
node.command("identity").description("Print the node host device identity (device id + public key)").option("--json", "Output JSON", false).action(runNodeIdentityShow);
addNodeGatewayOptions(addNodeCommandOptions(node.command("install").description("Install the node host service (launchd/systemd/schtasks)"))).option("--share-installed-apps", "Share installed macOS applications with the Gateway").option("--no-share-installed-apps", "Disable installed application sharing").option("--runtime <runtime>", "Service runtime (node|bun). Default: node").option("--runtime-path <path>", "Pin an absolute Node/Bun executable path").option("--force", "Reinstall/overwrite if already installed", false).option("--json", "Output JSON", false).action(async (opts, command) => {
const { runNodeDaemonInstall } = await import("./daemon-D8aSo5Vr.mjs");
await runNodeDaemonInstall({
...opts,
commands: opts.commands ?? inheritOptionFromParent(command, "commands"),
allCommands: opts.allCommands ?? inheritOptionFromParent(command, "allCommands")
});
});
for (const [name, action] of [
["uninstall", "runNodeDaemonUninstall"],
["stop", "runNodeDaemonStop"],
["start", "runNodeDaemonStart"],
["restart", "runNodeDaemonRestart"]
]) node.command(name).description(`${name.charAt(0).toUpperCase()}${name.slice(1)} the node host service (launchd/systemd/schtasks)`).option("--json", "Output JSON", false).action(async (opts) => {
await (await import("./daemon-D8aSo5Vr.mjs"))[action](opts);
});
}
//#endregion
export { registerNodeCli };