refactor: rename to openclaw

This commit is contained in:
Peter Steinberger
2026-01-30 03:15:10 +01:00
parent 4583f88626
commit 9a7160786a
2357 changed files with 16688 additions and 16788 deletions

View File

@@ -21,7 +21,7 @@ export function registerAcpCli(program: Command) {
.option("--verbose, -v", "Verbose logging to stderr", false)
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/acp", "docs.molt.bot/cli/acp")}\n`,
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/acp", "docs.openclaw.ai/cli/acp")}\n`,
)
.action((opts) => {
try {
@@ -46,7 +46,7 @@ export function registerAcpCli(program: Command) {
.command("client")
.description("Run an interactive ACP client against the local ACP bridge")
.option("--cwd <dir>", "Working directory for the ACP session")
.option("--server <command>", "ACP server command (default: moltbot)")
.option("--server <command>", "ACP server command (default: openclaw)")
.option("--server-args <args...>", "Extra arguments for the ACP server")
.option("--server-verbose", "Enable verbose logging on the ACP server", false)
.option("--verbose, -v", "Verbose client logging", false)

View File

@@ -15,117 +15,119 @@ import {
describe("argv helpers", () => {
it("detects help/version flags", () => {
expect(hasHelpOrVersion(["node", "moltbot", "--help"])).toBe(true);
expect(hasHelpOrVersion(["node", "moltbot", "-V"])).toBe(true);
expect(hasHelpOrVersion(["node", "moltbot", "status"])).toBe(false);
expect(hasHelpOrVersion(["node", "openclaw", "--help"])).toBe(true);
expect(hasHelpOrVersion(["node", "openclaw", "-V"])).toBe(true);
expect(hasHelpOrVersion(["node", "openclaw", "status"])).toBe(false);
});
it("extracts command path ignoring flags and terminator", () => {
expect(getCommandPath(["node", "moltbot", "status", "--json"], 2)).toEqual(["status"]);
expect(getCommandPath(["node", "moltbot", "agents", "list"], 2)).toEqual(["agents", "list"]);
expect(getCommandPath(["node", "moltbot", "status", "--", "ignored"], 2)).toEqual(["status"]);
expect(getCommandPath(["node", "openclaw", "status", "--json"], 2)).toEqual(["status"]);
expect(getCommandPath(["node", "openclaw", "agents", "list"], 2)).toEqual(["agents", "list"]);
expect(getCommandPath(["node", "openclaw", "status", "--", "ignored"], 2)).toEqual(["status"]);
});
it("returns primary command", () => {
expect(getPrimaryCommand(["node", "moltbot", "agents", "list"])).toBe("agents");
expect(getPrimaryCommand(["node", "moltbot"])).toBeNull();
expect(getPrimaryCommand(["node", "openclaw", "agents", "list"])).toBe("agents");
expect(getPrimaryCommand(["node", "openclaw"])).toBeNull();
});
it("parses boolean flags and ignores terminator", () => {
expect(hasFlag(["node", "moltbot", "status", "--json"], "--json")).toBe(true);
expect(hasFlag(["node", "moltbot", "--", "--json"], "--json")).toBe(false);
expect(hasFlag(["node", "openclaw", "status", "--json"], "--json")).toBe(true);
expect(hasFlag(["node", "openclaw", "--", "--json"], "--json")).toBe(false);
});
it("extracts flag values with equals and missing values", () => {
expect(getFlagValue(["node", "moltbot", "status", "--timeout", "5000"], "--timeout")).toBe(
expect(getFlagValue(["node", "openclaw", "status", "--timeout", "5000"], "--timeout")).toBe(
"5000",
);
expect(getFlagValue(["node", "moltbot", "status", "--timeout=2500"], "--timeout")).toBe("2500");
expect(getFlagValue(["node", "moltbot", "status", "--timeout"], "--timeout")).toBeNull();
expect(getFlagValue(["node", "moltbot", "status", "--timeout", "--json"], "--timeout")).toBe(
expect(getFlagValue(["node", "openclaw", "status", "--timeout=2500"], "--timeout")).toBe(
"2500",
);
expect(getFlagValue(["node", "openclaw", "status", "--timeout"], "--timeout")).toBeNull();
expect(getFlagValue(["node", "openclaw", "status", "--timeout", "--json"], "--timeout")).toBe(
null,
);
expect(getFlagValue(["node", "moltbot", "--", "--timeout=99"], "--timeout")).toBeUndefined();
expect(getFlagValue(["node", "openclaw", "--", "--timeout=99"], "--timeout")).toBeUndefined();
});
it("parses verbose flags", () => {
expect(getVerboseFlag(["node", "moltbot", "status", "--verbose"])).toBe(true);
expect(getVerboseFlag(["node", "moltbot", "status", "--debug"])).toBe(false);
expect(getVerboseFlag(["node", "moltbot", "status", "--debug"], { includeDebug: true })).toBe(
expect(getVerboseFlag(["node", "openclaw", "status", "--verbose"])).toBe(true);
expect(getVerboseFlag(["node", "openclaw", "status", "--debug"])).toBe(false);
expect(getVerboseFlag(["node", "openclaw", "status", "--debug"], { includeDebug: true })).toBe(
true,
);
});
it("parses positive integer flag values", () => {
expect(getPositiveIntFlagValue(["node", "moltbot", "status"], "--timeout")).toBeUndefined();
expect(getPositiveIntFlagValue(["node", "openclaw", "status"], "--timeout")).toBeUndefined();
expect(
getPositiveIntFlagValue(["node", "moltbot", "status", "--timeout"], "--timeout"),
getPositiveIntFlagValue(["node", "openclaw", "status", "--timeout"], "--timeout"),
).toBeNull();
expect(
getPositiveIntFlagValue(["node", "moltbot", "status", "--timeout", "5000"], "--timeout"),
getPositiveIntFlagValue(["node", "openclaw", "status", "--timeout", "5000"], "--timeout"),
).toBe(5000);
expect(
getPositiveIntFlagValue(["node", "moltbot", "status", "--timeout", "nope"], "--timeout"),
getPositiveIntFlagValue(["node", "openclaw", "status", "--timeout", "nope"], "--timeout"),
).toBeUndefined();
});
it("builds parse argv from raw args", () => {
const nodeArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node", "openclaw", "status"],
});
expect(nodeArgv).toEqual(["node", "moltbot", "status"]);
expect(nodeArgv).toEqual(["node", "openclaw", "status"]);
const versionedNodeArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node-22", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node-22", "openclaw", "status"],
});
expect(versionedNodeArgv).toEqual(["node-22", "moltbot", "status"]);
expect(versionedNodeArgv).toEqual(["node-22", "openclaw", "status"]);
const versionedNodeWindowsArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node-22.2.0.exe", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node-22.2.0.exe", "openclaw", "status"],
});
expect(versionedNodeWindowsArgv).toEqual(["node-22.2.0.exe", "moltbot", "status"]);
expect(versionedNodeWindowsArgv).toEqual(["node-22.2.0.exe", "openclaw", "status"]);
const versionedNodePatchlessArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node-22.2", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node-22.2", "openclaw", "status"],
});
expect(versionedNodePatchlessArgv).toEqual(["node-22.2", "moltbot", "status"]);
expect(versionedNodePatchlessArgv).toEqual(["node-22.2", "openclaw", "status"]);
const versionedNodeWindowsPatchlessArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node-22.2.exe", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node-22.2.exe", "openclaw", "status"],
});
expect(versionedNodeWindowsPatchlessArgv).toEqual(["node-22.2.exe", "moltbot", "status"]);
expect(versionedNodeWindowsPatchlessArgv).toEqual(["node-22.2.exe", "openclaw", "status"]);
const versionedNodeWithPathArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["/usr/bin/node-22.2.0", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["/usr/bin/node-22.2.0", "openclaw", "status"],
});
expect(versionedNodeWithPathArgv).toEqual(["/usr/bin/node-22.2.0", "moltbot", "status"]);
expect(versionedNodeWithPathArgv).toEqual(["/usr/bin/node-22.2.0", "openclaw", "status"]);
const nodejsArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["nodejs", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["nodejs", "openclaw", "status"],
});
expect(nodejsArgv).toEqual(["nodejs", "moltbot", "status"]);
expect(nodejsArgv).toEqual(["nodejs", "openclaw", "status"]);
const nonVersionedNodeArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["node-dev", "moltbot", "status"],
programName: "openclaw",
rawArgs: ["node-dev", "openclaw", "status"],
});
expect(nonVersionedNodeArgv).toEqual(["node", "moltbot", "node-dev", "moltbot", "status"]);
expect(nonVersionedNodeArgv).toEqual(["node", "openclaw", "node-dev", "openclaw", "status"]);
const directArgv = buildParseArgv({
programName: "moltbot",
rawArgs: ["moltbot", "status"],
programName: "openclaw",
rawArgs: ["openclaw", "status"],
});
expect(directArgv).toEqual(["node", "moltbot", "status"]);
expect(directArgv).toEqual(["node", "openclaw", "status"]);
const bunArgv = buildParseArgv({
programName: "moltbot",
programName: "openclaw",
rawArgs: ["bun", "src/entry.ts", "status"],
});
expect(bunArgv).toEqual(["bun", "src/entry.ts", "status"]);
@@ -133,20 +135,20 @@ describe("argv helpers", () => {
it("builds parse argv from fallback args", () => {
const fallbackArgv = buildParseArgv({
programName: "moltbot",
programName: "openclaw",
fallbackArgv: ["status"],
});
expect(fallbackArgv).toEqual(["node", "moltbot", "status"]);
expect(fallbackArgv).toEqual(["node", "openclaw", "status"]);
});
it("decides when to migrate state", () => {
expect(shouldMigrateState(["node", "moltbot", "status"])).toBe(false);
expect(shouldMigrateState(["node", "moltbot", "health"])).toBe(false);
expect(shouldMigrateState(["node", "moltbot", "sessions"])).toBe(false);
expect(shouldMigrateState(["node", "moltbot", "memory", "status"])).toBe(false);
expect(shouldMigrateState(["node", "moltbot", "agent", "--message", "hi"])).toBe(false);
expect(shouldMigrateState(["node", "moltbot", "agents", "list"])).toBe(true);
expect(shouldMigrateState(["node", "moltbot", "message", "send"])).toBe(true);
expect(shouldMigrateState(["node", "openclaw", "status"])).toBe(false);
expect(shouldMigrateState(["node", "openclaw", "health"])).toBe(false);
expect(shouldMigrateState(["node", "openclaw", "sessions"])).toBe(false);
expect(shouldMigrateState(["node", "openclaw", "memory", "status"])).toBe(false);
expect(shouldMigrateState(["node", "openclaw", "agent", "--message", "hi"])).toBe(false);
expect(shouldMigrateState(["node", "openclaw", "agents", "list"])).toBe(true);
expect(shouldMigrateState(["node", "openclaw", "message", "send"])).toBe(true);
});
it("reuses command path for migrate state decisions", () => {

View File

@@ -91,14 +91,14 @@ export function buildParseArgv(params: {
const normalizedArgv =
programName && baseArgv[0] === programName
? baseArgv.slice(1)
: baseArgv[0]?.endsWith("moltbot")
: baseArgv[0]?.endsWith("openclaw")
? baseArgv.slice(1)
: baseArgv;
const executable = (normalizedArgv[0]?.split(/[/\\]/).pop() ?? "").toLowerCase();
const looksLikeNode =
normalizedArgv.length >= 2 && (isNodeExecutable(executable) || isBunExecutable(executable));
if (looksLikeNode) return normalizedArgv;
return ["node", programName || "moltbot", ...normalizedArgv];
return ["node", programName || "openclaw", ...normalizedArgv];
}
const nodeExecutablePattern = /^node-\d+(?:\.\d+)*(?:\.exe)?$/;

View File

@@ -2,7 +2,6 @@ import { resolveCommitHash } from "../infra/git-commit.js";
import { visibleWidth } from "../terminal/ansi.js";
import { isRich, theme } from "../terminal/theme.js";
import { pickTagline, type TaglineOptions } from "./tagline.js";
import { resolveCliName } from "./cli-name.js";
type BannerOptions = TaglineOptions & {
argv?: string[];
@@ -38,8 +37,7 @@ export function formatCliBannerLine(version: string, options: BannerOptions = {}
const commitLabel = commit ?? "unknown";
const tagline = pickTagline(options);
const rich = options.richTty ?? isRich();
const cliName = resolveCliName(options.argv ?? process.argv, options.env);
const title = cliName === "moltbot" ? "🦞 Moltbot" : "🦞 Moltbot";
const title = "🦞 OpenClaw";
const prefix = "🦞 ";
const columns = options.columns ?? process.stdout.columns ?? 120;
const plainFullLine = `${title} ${version} (${commitLabel}) — ${tagline}`;
@@ -66,11 +64,11 @@ export function formatCliBannerLine(version: string, options: BannerOptions = {}
const LOBSTER_ASCII = [
"▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄",
"██░▄▀▄░██░▄▄▄░██░████▄▄░▄▄██░▄▄▀██░▄▄▄░█▄▄░▄▄██",
"██░█░█░█░███░██░██████░████░▄▄▀██░███░███░████",
"█████░██░▀▀▀░██░▀▀░███░████░▀▀░██░▀▀▀░███░████",
"█████░█████░█████░█░░░█░█████░█░░░░░░███░░█░░░█",
"█░░░█░█░░░█░███░░░██░░█░█░░░░░█░░░░░█░░░█░█░█░█",
"█████░████░░█████░█░░██░█████░█████░█████░████",
"▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀",
" 🦞 FRESH DAILY 🦞 ",
" 🦞 OPENCLAW 🦞 ",
" ",
];
@@ -86,11 +84,11 @@ export function formatCliBannerArt(options: BannerOptions = {}): string {
};
const colored = LOBSTER_ASCII.map((line) => {
if (line.includes("FRESH DAILY")) {
if (line.includes("OPENCLAW")) {
return (
theme.muted(" ") +
theme.accent("🦞") +
theme.info(" FRESH DAILY ") +
theme.info(" OPENCLAW ") +
theme.accent("🦞")
);
}

View File

@@ -57,7 +57,7 @@ export function registerBrowserFilesAndDownloadsCommands(
browser
.command("waitfordownload")
.description("Wait for the next download (and save it)")
.argument("[path]", "Save path (default: /tmp/moltbot/downloads/...)")
.argument("[path]", "Save path (default: /tmp/openclaw/downloads/...)")
.option("--target-id <id>", "CDP target id (or unique prefix)")
.option(
"--timeout-ms <ms>",

View File

@@ -1,34 +1,34 @@
export const browserCoreExamples = [
"moltbot browser status",
"moltbot browser start",
"moltbot browser stop",
"moltbot browser tabs",
"moltbot browser open https://example.com",
"moltbot browser focus abcd1234",
"moltbot browser close abcd1234",
"moltbot browser screenshot",
"moltbot browser screenshot --full-page",
"moltbot browser screenshot --ref 12",
"moltbot browser snapshot",
"moltbot browser snapshot --format aria --limit 200",
"moltbot browser snapshot --efficient",
"moltbot browser snapshot --labels",
"openclaw browser status",
"openclaw browser start",
"openclaw browser stop",
"openclaw browser tabs",
"openclaw browser open https://example.com",
"openclaw browser focus abcd1234",
"openclaw browser close abcd1234",
"openclaw browser screenshot",
"openclaw browser screenshot --full-page",
"openclaw browser screenshot --ref 12",
"openclaw browser snapshot",
"openclaw browser snapshot --format aria --limit 200",
"openclaw browser snapshot --efficient",
"openclaw browser snapshot --labels",
];
export const browserActionExamples = [
"moltbot browser navigate https://example.com",
"moltbot browser resize 1280 720",
"moltbot browser click 12 --double",
'moltbot browser type 23 "hello" --submit',
"moltbot browser press Enter",
"moltbot browser hover 44",
"moltbot browser drag 10 11",
"moltbot browser select 9 OptionA OptionB",
"moltbot browser upload /tmp/file.pdf",
'moltbot browser fill --fields \'[{"ref":"1","value":"Ada"}]\'',
"moltbot browser dialog --accept",
'moltbot browser wait --text "Done"',
"moltbot browser evaluate --fn '(el) => el.textContent' --ref 7",
"moltbot browser console --level error",
"moltbot browser pdf",
"openclaw browser navigate https://example.com",
"openclaw browser resize 1280 720",
"openclaw browser click 12 --double",
'openclaw browser type 23 "hello" --submit',
"openclaw browser press Enter",
"openclaw browser hover 44",
"openclaw browser drag 10 11",
"openclaw browser select 9 OptionA OptionB",
"openclaw browser upload /tmp/file.pdf",
'openclaw browser fill --fields \'[{"ref":"1","value":"Ada"}]\'',
"openclaw browser dialog --accept",
'openclaw browser wait --text "Done"',
"openclaw browser evaluate --fn '(el) => el.textContent' --ref 7",
"openclaw browser console --level error",
"openclaw browser pdf",
];

View File

@@ -21,7 +21,7 @@ vi.mock("../runtime.js", () => ({
describe("browser extension install", () => {
it("installs into the state dir (never node_modules)", async () => {
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-ext-"));
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ext-"));
const { installChromeExtension } = await import("./browser-cli-extension.js");
const sourceDir = path.resolve(process.cwd(), "assets/chrome-extension");
@@ -33,9 +33,9 @@ describe("browser extension install", () => {
});
it("copies extension path to clipboard", async () => {
const prev = process.env.CLAWDBOT_STATE_DIR;
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-ext-path-"));
process.env.CLAWDBOT_STATE_DIR = tmp;
const prev = process.env.OPENCLAW_STATE_DIR;
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ext-path-"));
process.env.OPENCLAW_STATE_DIR = tmp;
try {
copyToClipboard.mockReset();
@@ -63,8 +63,8 @@ describe("browser extension install", () => {
expect(copyToClipboard).toHaveBeenCalledWith(dir);
} finally {
if (prev === undefined) delete process.env.CLAWDBOT_STATE_DIR;
else process.env.CLAWDBOT_STATE_DIR = prev;
if (prev === undefined) delete process.env.OPENCLAW_STATE_DIR;
else process.env.OPENCLAW_STATE_DIR = prev;
}
});
});

View File

@@ -33,7 +33,7 @@ export async function installChromeExtension(opts?: {
}): Promise<{ path: string }> {
const src = opts?.sourceDir ?? bundledExtensionRootDir();
if (!hasManifest(src)) {
throw new Error("Bundled Chrome extension is missing. Reinstall Moltbot and try again.");
throw new Error("Bundled Chrome extension is missing. Reinstall OpenClaw and try again.");
}
const stateDir = opts?.stateDir ?? STATE_DIR;
@@ -88,9 +88,9 @@ export function registerBrowserExtensionCommands(
"Next:",
`- Chrome → chrome://extensions → enable “Developer mode”`,
`- “Load unpacked” → select: ${displayPath}`,
`- Pin “Moltbot Browser Relay”, then click it on the tab (badge shows ON)`,
`- Pin “OpenClaw Browser Relay”, then click it on the tab (badge shows ON)`,
"",
`${theme.muted("Docs:")} ${formatDocsLink("/tools/chrome-extension", "docs.molt.bot/tools/chrome-extension")}`,
`${theme.muted("Docs:")} ${formatDocsLink("/tools/chrome-extension", "docs.openclaw.ai/tools/chrome-extension")}`,
].join("\n"),
),
);
@@ -106,8 +106,8 @@ export function registerBrowserExtensionCommands(
defaultRuntime.error(
danger(
[
`Chrome extension is not installed. Run: "${formatCliCommand("moltbot browser extension install")}"`,
`Docs: ${formatDocsLink("/tools/chrome-extension", "docs.molt.bot/tools/chrome-extension")}`,
`Chrome extension is not installed. Run: "${formatCliCommand("openclaw browser extension install")}"`,
`Docs: ${formatDocsLink("/tools/chrome-extension", "docs.openclaw.ai/tools/chrome-extension")}`,
].join("\n"),
),
);

View File

@@ -49,7 +49,7 @@ export function registerBrowserManageCommands(
const detectedDisplay = detectedPath ? shortenHomePath(detectedPath) : "auto";
defaultRuntime.log(
[
`profile: ${status.profile ?? "clawd"}`,
`profile: ${status.profile ?? "openclaw"}`,
`enabled: ${status.enabled}`,
`running: ${status.running}`,
`cdpPort: ${status.cdpPort}`,
@@ -93,7 +93,7 @@ export function registerBrowserManageCommands(
defaultRuntime.log(JSON.stringify(status, null, 2));
return;
}
const name = status.profile ?? "clawd";
const name = status.profile ?? "openclaw";
defaultRuntime.log(info(`🦞 browser [${name}] running: ${status.running}`));
});
});
@@ -127,7 +127,7 @@ export function registerBrowserManageCommands(
defaultRuntime.log(JSON.stringify(status, null, 2));
return;
}
const name = status.profile ?? "clawd";
const name = status.profile ?? "openclaw";
defaultRuntime.log(info(`🦞 browser [${name}] running: ${status.running}`));
});
});
@@ -458,7 +458,7 @@ export function registerBrowserManageCommands(
.requiredOption("--name <name>", "Profile name (lowercase, numbers, hyphens)")
.option("--color <hex>", "Profile color (hex format, e.g. #0066CC)")
.option("--cdp-url <url>", "CDP URL for remote Chrome (http/https)")
.option("--driver <driver>", "Profile driver (clawd|extension). Default: clawd")
.option("--driver <driver>", "Profile driver (openclaw|extension). Default: openclaw")
.action(
async (opts: { name: string; color?: string; cdpUrl?: string; driver?: string }, cmd) => {
const parent = parentOpts(cmd);

View File

@@ -20,7 +20,7 @@ import { addGatewayClientOptions } from "./gateway-rpc.js";
export function registerBrowserCli(program: Command) {
const browser = program
.command("browser")
.description("Manage clawd's dedicated browser (Chrome/Chromium)")
.description("Manage OpenClaw's dedicated browser (Chrome/Chromium)")
.option("--browser-profile <name>", "Browser profile name (default from config)")
.option("--json", "Output machine-readable JSON", false)
.addHelpText(
@@ -31,13 +31,13 @@ export function registerBrowserCli(program: Command) {
true,
)}\n\n${theme.muted("Docs:")} ${formatDocsLink(
"/cli/browser",
"docs.molt.bot/cli/browser",
"docs.openclaw.ai/cli/browser",
)}\n`,
)
.action(() => {
browser.outputHelp();
defaultRuntime.error(
danger(`Missing subcommand. Try: "${formatCliCommand("moltbot browser status")}"`),
danger(`Missing subcommand. Try: "${formatCliCommand("openclaw browser status")}"`),
);
defaultRuntime.exit(1);
});

View File

@@ -18,7 +18,7 @@ function dedupe(values: string[]): string[] {
export function resolveCliChannelOptions(): string[] {
const catalog = listChannelPluginCatalogEntries().map((entry) => entry.id);
const base = dedupe([...CHAT_CHANNEL_ORDER, ...catalog]);
if (isTruthyEnvValue(process.env.CLAWDBOT_EAGER_CHANNEL_OPTIONS)) {
if (isTruthyEnvValue(process.env.OPENCLAW_EAGER_CHANNEL_OPTIONS)) {
ensurePluginRegistryLoaded();
const pluginIds = listChannelPlugins().map((plugin) => plugin.id);
return dedupe([...base, ...pluginIds]);

View File

@@ -76,7 +76,7 @@ export function registerChannelsCli(program: Command) {
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink(
"/cli/channels",
"docs.molt.bot/cli/channels",
"docs.openclaw.ai/cli/channels",
)}\n`,
);

View File

@@ -1,17 +1,11 @@
import path from "node:path";
export const DEFAULT_CLI_NAME = "moltbot";
export const LEGACY_CLI_NAME = "moltbot";
export const DEFAULT_CLI_NAME = "openclaw";
const KNOWN_CLI_NAMES = new Set([DEFAULT_CLI_NAME, LEGACY_CLI_NAME]);
const CLI_PREFIX_RE = /^(?:((?:pnpm|npm|bunx|npx)\s+))?(moltbot|moltbot)\b/;
const KNOWN_CLI_NAMES = new Set([DEFAULT_CLI_NAME]);
const CLI_PREFIX_RE = /^(?:((?:pnpm|npm|bunx|npx)\s+))?(openclaw)\b/;
export function resolveCliName(
argv: string[] = process.argv,
env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,
): string {
const override = env.MOLTBOT_CLI_NAME?.trim() || env.CLAWDBOT_CLI_NAME?.trim();
if (override) return override;
export function resolveCliName(argv: string[] = process.argv): string {
const argv1 = argv[1];
if (!argv1) return DEFAULT_CLI_NAME;
const base = path.basename(argv1).trim();

View File

@@ -1,7 +1,7 @@
import { normalizeProfileName } from "./profile-utils.js";
import { replaceCliName, resolveCliName } from "./cli-name.js";
const CLI_PREFIX_RE = /^(?:pnpm|npm|bunx|npx)\s+(?:moltbot|moltbot)\b|^(?:moltbot|moltbot)\b/;
const CLI_PREFIX_RE = /^(?:pnpm|npm|bunx|npx)\s+openclaw\b|^openclaw\b/;
const PROFILE_FLAG_RE = /(?:^|\s)--profile(?:\s|=|$)/;
const DEV_FLAG_RE = /(?:^|\s)--dev(?:\s|$)/;
@@ -9,9 +9,9 @@ export function formatCliCommand(
command: string,
env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,
): string {
const cliName = resolveCliName(undefined, env);
const cliName = resolveCliName();
const normalizedCommand = replaceCliName(command, cliName);
const profile = normalizeProfileName(env.CLAWDBOT_PROFILE);
const profile = normalizeProfileName(env.OPENCLAW_PROFILE);
if (!profile) return normalizedCommand;
if (!CLI_PREFIX_RE.test(normalizedCommand)) return normalizedCommand;
if (PROFILE_FLAG_RE.test(normalizedCommand) || DEV_FLAG_RE.test(normalizedCommand)) {

View File

@@ -173,7 +173,7 @@ async function loadValidConfig() {
for (const issue of snapshot.issues) {
defaultRuntime.error(`- ${issue.path || "<root>"}: ${issue.message}`);
}
defaultRuntime.error(`Run \`${formatCliCommand("moltbot doctor")}\` to repair, then retry.`);
defaultRuntime.error(`Run \`${formatCliCommand("openclaw doctor")}\` to repair, then retry.`);
defaultRuntime.exit(1);
return snapshot;
}
@@ -185,7 +185,7 @@ export function registerConfigCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/config", "docs.molt.bot/cli/config")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/config", "docs.openclaw.ai/cli/config")}\n`,
)
.option(
"--section <section>",

View File

@@ -15,7 +15,8 @@ export function registerCronCli(program: Command) {
.description("Manage cron jobs (via Gateway)")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/cron", "docs.molt.bot/cli/cron")}\n`,
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/cron", "docs.openclaw.ai/cli/cron")}\n`,
);
registerCronStatusCommand(cron);

View File

@@ -81,36 +81,36 @@ vi.mock("./progress.js", () => ({
describe("daemon-cli coverage", () => {
const originalEnv = {
CLAWDBOT_STATE_DIR: process.env.CLAWDBOT_STATE_DIR,
CLAWDBOT_CONFIG_PATH: process.env.CLAWDBOT_CONFIG_PATH,
CLAWDBOT_GATEWAY_PORT: process.env.CLAWDBOT_GATEWAY_PORT,
CLAWDBOT_PROFILE: process.env.CLAWDBOT_PROFILE,
OPENCLAW_STATE_DIR: process.env.OPENCLAW_STATE_DIR,
OPENCLAW_CONFIG_PATH: process.env.OPENCLAW_CONFIG_PATH,
OPENCLAW_GATEWAY_PORT: process.env.OPENCLAW_GATEWAY_PORT,
OPENCLAW_PROFILE: process.env.OPENCLAW_PROFILE,
};
beforeEach(() => {
process.env.CLAWDBOT_STATE_DIR = "/tmp/moltbot-cli-state";
process.env.CLAWDBOT_CONFIG_PATH = "/tmp/moltbot-cli-state/moltbot.json";
delete process.env.CLAWDBOT_GATEWAY_PORT;
delete process.env.CLAWDBOT_PROFILE;
process.env.OPENCLAW_STATE_DIR = "/tmp/openclaw-cli-state";
process.env.OPENCLAW_CONFIG_PATH = "/tmp/openclaw-cli-state/openclaw.json";
delete process.env.OPENCLAW_GATEWAY_PORT;
delete process.env.OPENCLAW_PROFILE;
serviceReadCommand.mockResolvedValue(null);
});
afterEach(() => {
if (originalEnv.CLAWDBOT_STATE_DIR !== undefined)
process.env.CLAWDBOT_STATE_DIR = originalEnv.CLAWDBOT_STATE_DIR;
else delete process.env.CLAWDBOT_STATE_DIR;
if (originalEnv.OPENCLAW_STATE_DIR !== undefined)
process.env.OPENCLAW_STATE_DIR = originalEnv.OPENCLAW_STATE_DIR;
else delete process.env.OPENCLAW_STATE_DIR;
if (originalEnv.CLAWDBOT_CONFIG_PATH !== undefined)
process.env.CLAWDBOT_CONFIG_PATH = originalEnv.CLAWDBOT_CONFIG_PATH;
else delete process.env.CLAWDBOT_CONFIG_PATH;
if (originalEnv.OPENCLAW_CONFIG_PATH !== undefined)
process.env.OPENCLAW_CONFIG_PATH = originalEnv.OPENCLAW_CONFIG_PATH;
else delete process.env.OPENCLAW_CONFIG_PATH;
if (originalEnv.CLAWDBOT_GATEWAY_PORT !== undefined)
process.env.CLAWDBOT_GATEWAY_PORT = originalEnv.CLAWDBOT_GATEWAY_PORT;
else delete process.env.CLAWDBOT_GATEWAY_PORT;
if (originalEnv.OPENCLAW_GATEWAY_PORT !== undefined)
process.env.OPENCLAW_GATEWAY_PORT = originalEnv.OPENCLAW_GATEWAY_PORT;
else delete process.env.OPENCLAW_GATEWAY_PORT;
if (originalEnv.CLAWDBOT_PROFILE !== undefined)
process.env.CLAWDBOT_PROFILE = originalEnv.CLAWDBOT_PROFILE;
else delete process.env.CLAWDBOT_PROFILE;
if (originalEnv.OPENCLAW_PROFILE !== undefined)
process.env.OPENCLAW_PROFILE = originalEnv.OPENCLAW_PROFILE;
else delete process.env.OPENCLAW_PROFILE;
});
it("probes gateway status by default", async () => {
@@ -140,10 +140,10 @@ describe("daemon-cli coverage", () => {
serviceReadCommand.mockResolvedValueOnce({
programArguments: ["/bin/node", "cli", "gateway", "--port", "19001"],
environment: {
CLAWDBOT_PROFILE: "dev",
CLAWDBOT_STATE_DIR: "/tmp/moltbot-daemon-state",
CLAWDBOT_CONFIG_PATH: "/tmp/moltbot-daemon-state/moltbot.json",
CLAWDBOT_GATEWAY_PORT: "19001",
OPENCLAW_PROFILE: "dev",
OPENCLAW_STATE_DIR: "/tmp/openclaw-daemon-state",
OPENCLAW_CONFIG_PATH: "/tmp/openclaw-daemon-state/openclaw.json",
OPENCLAW_GATEWAY_PORT: "19001",
},
sourcePath: "/tmp/bot.molt.gateway.plist",
});

View File

@@ -84,7 +84,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
if (!json) {
defaultRuntime.log(`Gateway service already ${service.loadedText}.`);
defaultRuntime.log(
`Reinstall with: ${formatCliCommand("moltbot gateway install --force")}`,
`Reinstall with: ${formatCliCommand("openclaw gateway install --force")}`,
);
}
return;
@@ -94,7 +94,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
env: process.env,
port,
token: opts.token || cfg.gateway?.auth?.token || process.env.CLAWDBOT_GATEWAY_TOKEN,
token: opts.token || cfg.gateway?.auth?.token || process.env.OPENCLAW_GATEWAY_TOKEN,
runtime: runtimeRaw,
warn: (message) => {
if (json) warnings.push(message);

View File

@@ -18,7 +18,7 @@ export function registerDaemonCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/gateway", "docs.molt.bot/cli/gateway")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/gateway", "docs.openclaw.ai/cli/gateway")}\n`,
);
daemon

View File

@@ -51,13 +51,11 @@ export function pickProbeHostForBind(
}
const SAFE_DAEMON_ENV_KEYS = [
"MOLTBOT_STATE_DIR",
"MOLTBOT_CONFIG_PATH",
"CLAWDBOT_PROFILE",
"CLAWDBOT_STATE_DIR",
"CLAWDBOT_CONFIG_PATH",
"CLAWDBOT_GATEWAY_PORT",
"CLAWDBOT_NIX_MODE",
"OPENCLAW_PROFILE",
"OPENCLAW_STATE_DIR",
"OPENCLAW_CONFIG_PATH",
"OPENCLAW_GATEWAY_PORT",
"OPENCLAW_NIX_MODE",
];
export function filterDaemonEnv(env: Record<string, string> | undefined): Record<string, string> {
@@ -131,7 +129,7 @@ export function renderRuntimeHints(
}
})();
if (runtime.missingUnit) {
hints.push(`Service not installed. Run: ${formatCliCommand("moltbot gateway install", env)}`);
hints.push(`Service not installed. Run: ${formatCliCommand("openclaw gateway install", env)}`);
if (fileLog) hints.push(`File logs: ${fileLog}`);
return hints;
}
@@ -142,10 +140,10 @@ export function renderRuntimeHints(
hints.push(`Launchd stdout (if installed): ${logs.stdoutPath}`);
hints.push(`Launchd stderr (if installed): ${logs.stderrPath}`);
} else if (process.platform === "linux") {
const unit = resolveGatewaySystemdServiceName(env.CLAWDBOT_PROFILE);
const unit = resolveGatewaySystemdServiceName(env.OPENCLAW_PROFILE);
hints.push(`Logs: journalctl --user -u ${unit}.service -n 200 --no-pager`);
} else if (process.platform === "win32") {
const task = resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
const task = resolveGatewayWindowsTaskName(env.OPENCLAW_PROFILE);
hints.push(`Logs: schtasks /Query /TN "${task}" /V /FO LIST`);
}
}
@@ -154,10 +152,10 @@ export function renderRuntimeHints(
export function renderGatewayServiceStartHints(env: NodeJS.ProcessEnv = process.env): string[] {
const base = [
formatCliCommand("moltbot gateway install", env),
formatCliCommand("moltbot gateway", env),
formatCliCommand("openclaw gateway install", env),
formatCliCommand("openclaw gateway", env),
];
const profile = env.CLAWDBOT_PROFILE;
const profile = env.OPENCLAW_PROFILE;
switch (process.platform) {
case "darwin": {
const label = resolveGatewayLaunchAgentLabel(profile);

View File

@@ -8,7 +8,6 @@ import type { GatewayBindMode, GatewayControlUiConfig } from "../../config/types
import { readLastGatewayErrorLine } from "../../daemon/diagnostics.js";
import type { FindExtraGatewayServicesOptions } from "../../daemon/inspect.js";
import { findExtraGatewayServices } from "../../daemon/inspect.js";
import { findLegacyGatewayServices } from "../../daemon/legacy.js";
import { resolveGatewayService } from "../../daemon/service.js";
import type { ServiceConfigAudit } from "../../daemon/service-audit.js";
import { auditGatewayServiceConfig } from "../../daemon/service-audit.js";
@@ -93,7 +92,6 @@ export type DaemonStatus = {
error?: string;
url?: string;
};
legacyServices: Array<{ label: string; detail: string }>;
extraServices: Array<{ label: string; detail: string; scope: string }>;
};
@@ -210,9 +208,6 @@ export async function gatherDaemonStatus(
}
: undefined;
const legacyServices = await findLegacyGatewayServices(
process.env as Record<string, string | undefined>,
).catch(() => []);
const extraServices = await findExtraGatewayServices(
process.env as Record<string, string | undefined>,
{ deep: Boolean(opts.deep) },
@@ -226,11 +221,11 @@ export async function gatherDaemonStatus(
url: probeUrl,
token:
opts.rpc.token ||
mergedDaemonEnv.CLAWDBOT_GATEWAY_TOKEN ||
mergedDaemonEnv.OPENCLAW_GATEWAY_TOKEN ||
daemonCfg.gateway?.auth?.token,
password:
opts.rpc.password ||
mergedDaemonEnv.CLAWDBOT_GATEWAY_PASSWORD ||
mergedDaemonEnv.OPENCLAW_GATEWAY_PASSWORD ||
daemonCfg.gateway?.auth?.password,
timeoutMs,
json: opts.rpc.json,
@@ -271,7 +266,6 @@ export async function gatherDaemonStatus(
...(portCliStatus ? { portCli: portCliStatus } : {}),
lastError,
...(rpc ? { rpc: { ...rpc, url: probeUrl } } : {}),
legacyServices,
extraServices,
};
}

View File

@@ -60,7 +60,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
const errorText = (value: string) => colorize(rich, theme.error, value);
const spacer = () => defaultRuntime.log("");
const { service, rpc, legacyServices, extraServices } = status;
const { service, rpc, extraServices } = status;
const serviceStatus = service.loaded
? okText(service.loadedText)
: warnText(service.notLoadedText);
@@ -100,7 +100,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
}
defaultRuntime.error(
warnText(
`Recommendation: run "${formatCliCommand("moltbot doctor")}" (or "${formatCliCommand("moltbot doctor --repair")}").`,
`Recommendation: run "${formatCliCommand("openclaw doctor")}" (or "${formatCliCommand("openclaw doctor --repair")}").`,
),
);
}
@@ -134,7 +134,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
);
defaultRuntime.error(
errorText(
`Fix: rerun \`${formatCliCommand("moltbot gateway install --force")}\` from the same --profile / CLAWDBOT_STATE_DIR you expect.`,
`Fix: rerun \`${formatCliCommand("openclaw gateway install --force")}\` from the same --profile / OPENCLAW_STATE_DIR you expect.`,
),
);
}
@@ -230,14 +230,14 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
if (service.runtime?.cachedLabel) {
const env = (service.command?.environment ?? process.env) as NodeJS.ProcessEnv;
const labelValue = resolveGatewayLaunchAgentLabel(env.CLAWDBOT_PROFILE);
const labelValue = resolveGatewayLaunchAgentLabel(env.OPENCLAW_PROFILE);
defaultRuntime.error(
errorText(
`LaunchAgent label cached but plist missing. Clear with: launchctl bootout gui/$UID/${labelValue}`,
),
);
defaultRuntime.error(
errorText(`Then reinstall: ${formatCliCommand("moltbot gateway install")}`),
errorText(`Then reinstall: ${formatCliCommand("openclaw gateway install")}`),
);
spacer();
}
@@ -273,7 +273,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
}
if (process.platform === "linux") {
const env = (service.command?.environment ?? process.env) as NodeJS.ProcessEnv;
const unit = resolveGatewaySystemdServiceName(env.CLAWDBOT_PROFILE);
const unit = resolveGatewaySystemdServiceName(env.OPENCLAW_PROFILE);
defaultRuntime.error(
errorText(`Logs: journalctl --user -u ${unit}.service -n 200 --no-pager`),
);
@@ -287,15 +287,6 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
spacer();
}
if (legacyServices.length > 0) {
defaultRuntime.error(errorText("Legacy gateway services detected:"));
for (const svc of legacyServices) {
defaultRuntime.error(`- ${errorText(svc.label)} (${svc.detail})`);
}
defaultRuntime.error(errorText(`Cleanup: ${formatCliCommand("moltbot doctor")}`));
spacer();
}
if (extraServices.length > 0) {
defaultRuntime.error(errorText("Other gateway-like services detected (best effort):"));
for (const svc of extraServices) {
@@ -307,7 +298,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
spacer();
}
if (legacyServices.length > 0 || extraServices.length > 0) {
if (extraServices.length > 0) {
defaultRuntime.error(
errorText(
"Recommendation: run a single gateway per machine for most setups. One gateway supports multiple agents (see docs: /gateway#multiple-gateways-same-host).",
@@ -321,6 +312,6 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean })
spacer();
}
defaultRuntime.log(`${label("Troubles:")} run ${formatCliCommand("moltbot status")}`);
defaultRuntime.log(`${label("Troubleshooting:")} https://docs.molt.bot/troubleshooting`);
defaultRuntime.log(`${label("Troubles:")} run ${formatCliCommand("openclaw status")}`);
defaultRuntime.log(`${label("Troubleshooting:")} https://docs.openclaw.ai/troubleshooting`);
}

View File

@@ -39,7 +39,7 @@ export function registerDirectoryCli(program: Command) {
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink(
"/cli/directory",
"docs.molt.bot/cli/directory",
"docs.openclaw.ai/cli/directory",
)}\n`,
)
.action(() => {

View File

@@ -6,9 +6,9 @@ describe("dns cli", () => {
it("prints setup info (no apply)", async () => {
const log = vi.spyOn(console, "log").mockImplementation(() => {});
const program = buildProgram();
await program.parseAsync(["dns", "setup"], { from: "user" });
await program.parseAsync(["dns", "setup", "--domain", "openclaw.internal"], { from: "user" });
const output = log.mock.calls.map((call) => call.join(" ")).join("\n");
expect(output).toContain("DNS setup");
expect(output).toContain("moltbot.internal");
expect(output).toContain("openclaw.internal");
});
});

View File

@@ -6,7 +6,7 @@ import type { Command } from "commander";
import { loadConfig } from "../config/config.js";
import { pickPrimaryTailnetIPv4, pickPrimaryTailnetIPv6 } from "../infra/tailnet.js";
import { getWideAreaZonePath, WIDE_AREA_DISCOVERY_DOMAIN } from "../infra/widearea-dns.js";
import { getWideAreaZonePath, resolveWideAreaDiscoveryDomain } from "../infra/widearea-dns.js";
import { defaultRuntime } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { renderTable } from "../terminal/table.js";
@@ -97,12 +97,15 @@ export function registerDnsCli(program: Command) {
.description("DNS helpers for wide-area discovery (Tailscale + CoreDNS)")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dns", "docs.molt.bot/cli/dns")}\n`,
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dns", "docs.openclaw.ai/cli/dns")}\n`,
);
dns
.command("setup")
.description("Set up CoreDNS to serve moltbot.internal for unicast DNS-SD (Wide-Area Bonjour)")
.description(
"Set up CoreDNS to serve your discovery domain for unicast DNS-SD (Wide-Area Bonjour)",
)
.option("--domain <domain>", "Wide-area discovery domain (e.g. openclaw.internal)")
.option(
"--apply",
"Install/update CoreDNS config and (re)start the service (requires sudo)",
@@ -112,7 +115,15 @@ export function registerDnsCli(program: Command) {
const cfg = loadConfig();
const tailnetIPv4 = pickPrimaryTailnetIPv4();
const tailnetIPv6 = pickPrimaryTailnetIPv6();
const zonePath = getWideAreaZonePath();
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
configDomain: (opts.domain as string | undefined) ?? cfg.discovery?.wideArea?.domain,
});
if (!wideAreaDomain) {
throw new Error(
"No wide-area domain configured. Set discovery.wideArea.domain or pass --domain.",
);
}
const zonePath = getWideAreaZonePath(wideAreaDomain);
const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
defaultRuntime.log(theme.heading("DNS setup"));
@@ -124,7 +135,7 @@ export function registerDnsCli(program: Command) {
{ key: "Value", header: "Value", minWidth: 24, flex: true },
],
rows: [
{ Key: "Domain", Value: WIDE_AREA_DISCOVERY_DOMAIN },
{ Key: "Domain", Value: wideAreaDomain },
{ Key: "Zone file", Value: zonePath },
{
Key: "Tailnet IP",
@@ -134,12 +145,12 @@ export function registerDnsCli(program: Command) {
}).trimEnd(),
);
defaultRuntime.log("");
defaultRuntime.log(theme.heading("Recommended ~/.clawdbot/moltbot.json:"));
defaultRuntime.log(theme.heading("Recommended ~/.openclaw/openclaw.json:"));
defaultRuntime.log(
JSON.stringify(
{
gateway: { bind: "auto" },
discovery: { wideArea: { enabled: true } },
discovery: { wideArea: { enabled: true, domain: wideAreaDomain } },
},
null,
2,
@@ -150,7 +161,9 @@ export function registerDnsCli(program: Command) {
defaultRuntime.log(
theme.muted(`- Add nameserver: ${tailnetIPv4 ?? "<this machine's tailnet IPv4>"}`),
);
defaultRuntime.log(theme.muted("- Restrict to domain (Split DNS): moltbot.internal"));
defaultRuntime.log(
theme.muted(`- Restrict to domain (Split DNS): ${wideAreaDomain.replace(/\.$/, "")}`),
);
if (!opts.apply) {
defaultRuntime.log("");
@@ -170,7 +183,7 @@ export function registerDnsCli(program: Command) {
const corefilePath = path.join(etcDir, "Corefile");
const confDir = path.join(etcDir, "conf.d");
const importGlob = path.join(confDir, "*.server");
const serverPath = path.join(confDir, "moltbot.internal.server");
const serverPath = path.join(confDir, `${wideAreaDomain.replace(/\.$/, "")}.server`);
run("brew", ["list", "coredns"], { allowFailure: true });
run("brew", ["install", "coredns"], {
@@ -189,7 +202,7 @@ export function registerDnsCli(program: Command) {
const bindArgs = [tailnetIPv4, tailnetIPv6].filter((v): v is string => Boolean(v?.trim()));
const server = [
`${WIDE_AREA_DISCOVERY_DOMAIN.replace(/\.$/, "")}:53 {`,
`${wideAreaDomain.replace(/\.$/, "")}:53 {`,
` bind ${bindArgs.join(" ")}`,
` file ${zonePath} {`,
` reload 10s`,
@@ -210,8 +223,8 @@ export function registerDnsCli(program: Command) {
const serial = `${y}${m}${d}01`;
const zoneLines = [
`; created by moltbot dns setup (will be overwritten by the gateway when wide-area discovery is enabled)`,
`$ORIGIN ${WIDE_AREA_DISCOVERY_DOMAIN}`,
`; created by openclaw dns setup (will be overwritten by the gateway when wide-area discovery is enabled)`,
`$ORIGIN ${wideAreaDomain}`,
`$TTL 60`,
`@ IN SOA ns1 hostmaster ${serial} 7200 3600 1209600 60`,
`@ IN NS ns1`,
@@ -233,7 +246,7 @@ export function registerDnsCli(program: Command) {
defaultRuntime.log("");
defaultRuntime.log(
theme.muted(
"Note: enable discovery.wideArea.enabled in ~/.clawdbot/moltbot.json on the gateway and restart the gateway so it writes the DNS-SD zone.",
"Note: enable discovery.wideArea.enabled in ~/.openclaw/openclaw.json on the gateway and restart the gateway so it writes the DNS-SD zone.",
),
);
}

View File

@@ -9,11 +9,12 @@ import { runCommandWithRuntime } from "./cli-utils.js";
export function registerDocsCli(program: Command) {
program
.command("docs")
.description("Search the live Moltbot docs")
.description("Search the live OpenClaw docs")
.argument("[query...]", "Search query")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/docs", "docs.molt.bot/cli/docs")}\n`,
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/docs", "docs.openclaw.ai/cli/docs")}\n`,
)
.action(async (queryParts: string[]) => {
await runCommandWithRuntime(defaultRuntime, async () => {

View File

@@ -233,7 +233,7 @@ export function registerExecApprovalsCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.molt.bot/cli/approvals")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.openclaw.ai/cli/approvals")}\n`,
);
const getCmd = approvals
@@ -326,18 +326,18 @@ export function registerExecApprovalsCli(program: Command) {
"after",
() =>
`\n${theme.heading("Examples:")}\n${formatExample(
'moltbot approvals allowlist add "~/Projects/**/bin/rg"',
'openclaw approvals allowlist add "~/Projects/**/bin/rg"',
"Allowlist a local binary pattern for the main agent.",
)}\n${formatExample(
'moltbot approvals allowlist add --agent main --node <id|name|ip> "/usr/bin/uptime"',
'openclaw approvals allowlist add --agent main --node <id|name|ip> "/usr/bin/uptime"',
"Allowlist on a specific node/agent.",
)}\n${formatExample(
'moltbot approvals allowlist add --agent "*" "/usr/bin/uname"',
'openclaw approvals allowlist add --agent "*" "/usr/bin/uname"',
"Allowlist for all agents (wildcard).",
)}\n${formatExample(
'moltbot approvals allowlist remove "~/Projects/**/bin/rg"',
'openclaw approvals allowlist remove "~/Projects/**/bin/rg"',
"Remove an allowlist pattern.",
)}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.molt.bot/cli/approvals")}\n`,
)}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.openclaw.ai/cli/approvals")}\n`,
);
const allowlistAdd = allowlist

View File

@@ -139,7 +139,7 @@ describe("gateway-cli coverage", () => {
discoverGatewayBeacons.mockReset();
discoverGatewayBeacons.mockResolvedValueOnce([
{
instanceName: "Studio (Moltbot)",
instanceName: "Studio (OpenClaw)",
displayName: "Studio",
domain: "local.",
host: "studio.local",
@@ -171,10 +171,10 @@ describe("gateway-cli coverage", () => {
discoverGatewayBeacons.mockReset();
discoverGatewayBeacons.mockResolvedValueOnce([
{
instanceName: "Studio (Moltbot)",
instanceName: "Studio (OpenClaw)",
displayName: "Studio",
domain: "moltbot.internal.",
host: "studio.clawdbot.internal",
domain: "openclaw.internal.",
host: "studio.openclaw.internal",
lanHost: "studio.local",
tailnetDns: "studio.tailnet.ts.net",
gatewayPort: 18789,
@@ -194,9 +194,9 @@ describe("gateway-cli coverage", () => {
const out = runtimeLogs.join("\n");
expect(out).toContain("Gateway Discovery");
expect(out).toContain("Found 1 gateway(s)");
expect(out).toContain("- Studio moltbot.internal.");
expect(out).toContain("- Studio openclaw.internal.");
expect(out).toContain(" tailnet: studio.tailnet.ts.net");
expect(out).toContain(" host: studio.clawdbot.internal");
expect(out).toContain(" host: studio.openclaw.internal");
expect(out).toContain(" ws: ws://studio.tailnet.ts.net:18789");
});
@@ -318,7 +318,7 @@ describe("gateway-cli coverage", () => {
});
it("uses env/config port when --port is omitted", async () => {
await withEnvOverride({ CLAWDBOT_GATEWAY_PORT: "19001" }, async () => {
await withEnvOverride({ OPENCLAW_GATEWAY_PORT: "19001" }, async () => {
runtimeLogs.length = 0;
runtimeErrors.length = 0;
startGatewayServer.mockClear();

View File

@@ -32,7 +32,7 @@ async function loadDevTemplate(name: string, fallback: string): Promise<string>
const resolveDevWorkspaceDir = (env: NodeJS.ProcessEnv = process.env): string => {
const baseDir = resolveDefaultAgentWorkspaceDir(env, os.homedir);
const profile = env.CLAWDBOT_PROFILE?.trim().toLowerCase();
const profile = env.OPENCLAW_PROFILE?.trim().toLowerCase();
if (profile === "dev") return baseDir;
return `${baseDir}-${DEV_AGENT_WORKSPACE_SUFFIX}`;
};
@@ -56,7 +56,7 @@ async function ensureDevWorkspace(dir: string) {
const [agents, soul, tools, identity, user] = await Promise.all([
loadDevTemplate(
"AGENTS.dev.md",
`# AGENTS.md - Moltbot Dev Workspace\n\nDefault dev workspace for moltbot gateway --dev.\n`,
`# AGENTS.md - OpenClaw Dev Workspace\n\nDefault dev workspace for openclaw gateway --dev.\n`,
),
loadDevTemplate(
"SOUL.dev.md",

View File

@@ -1,9 +1,10 @@
import type { Command } from "commander";
import { gatewayStatusCommand } from "../../commands/gateway-status.js";
import { formatHealthChannelLines, type HealthSummary } from "../../commands/health.js";
import { loadConfig } from "../../config/config.js";
import { discoverGatewayBeacons } from "../../infra/bonjour-discovery.js";
import type { CostUsageSummary } from "../../infra/session-cost-usage.js";
import { WIDE_AREA_DISCOVERY_DOMAIN } from "../../infra/widearea-dns.js";
import { resolveWideAreaDiscoveryDomain } from "../../infra/widearea-dns.js";
import { defaultRuntime } from "../../runtime.js";
import { formatDocsLink } from "../../terminal/links.js";
import { colorize, isRich, theme } from "../../terminal/theme.js";
@@ -103,7 +104,7 @@ export function registerGatewayCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/gateway", "docs.molt.bot/cli/gateway")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/gateway", "docs.openclaw.ai/cli/gateway")}\n`,
),
);
@@ -266,14 +267,17 @@ export function registerGatewayCli(program: Command) {
gateway
.command("discover")
.description(
`Discover gateways via Bonjour (multicast local. + unicast ${WIDE_AREA_DISCOVERY_DOMAIN})`,
)
.description("Discover gateways via Bonjour (local + wide-area if configured)")
.option("--timeout <ms>", "Per-command timeout in ms", "2000")
.option("--json", "Output JSON", false)
.action(async (opts: GatewayDiscoverOpts) => {
await runGatewayCommand(async () => {
const cfg = loadConfig();
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
configDomain: cfg.discovery?.wideArea?.domain,
});
const timeoutMs = parseDiscoverTimeoutMs(opts.timeout, 2000);
const domains = ["local.", ...(wideAreaDomain ? [wideAreaDomain] : [])];
const beacons = await withProgress(
{
label: "Scanning for gateways…",
@@ -281,7 +285,7 @@ export function registerGatewayCli(program: Command) {
enabled: opts.json !== true,
delayMs: 0,
},
async () => await discoverGatewayBeacons({ timeoutMs }),
async () => await discoverGatewayBeacons({ timeoutMs, wideAreaDomain }),
);
const deduped = dedupeBeacons(beacons).sort((a, b) =>
@@ -300,7 +304,7 @@ export function registerGatewayCli(program: Command) {
JSON.stringify(
{
timeoutMs,
domains: ["local.", WIDE_AREA_DISCOVERY_DOMAIN],
domains,
count: enriched.length,
beacons: enriched,
},
@@ -317,7 +321,7 @@ export function registerGatewayCli(program: Command) {
colorize(
rich,
theme.muted,
`Found ${deduped.length} gateway(s) · domains: local., ${WIDE_AREA_DISCOVERY_DOMAIN}`,
`Found ${deduped.length} gateway(s) · domains: ${domains.join(", ")}`,
),
);
if (deduped.length === 0) return;

View File

@@ -53,7 +53,7 @@ type GatewayRunOpts = {
const gatewayLog = createSubsystemLogger("gateway");
async function runGatewayCommand(opts: GatewayRunOpts) {
const isDevProfile = process.env.CLAWDBOT_PROFILE?.trim().toLowerCase() === "dev";
const isDevProfile = process.env.OPENCLAW_PROFILE?.trim().toLowerCase() === "dev";
const devMode = Boolean(opts.dev) || isDevProfile;
if (opts.reset && !devMode) {
defaultRuntime.error("Use --reset with --dev.");
@@ -65,7 +65,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
setVerbose(Boolean(opts.verbose));
if (opts.claudeCliLogs) {
setConsoleSubsystemFilter(["agent/claude-cli"]);
process.env.CLAWDBOT_CLAUDE_CLI_LOG_OUTPUT = "1";
process.env.OPENCLAW_CLAUDE_CLI_LOG_OUTPUT = "1";
}
const wsLogRaw = (opts.compact ? "compact" : opts.wsLog) as string | undefined;
const wsLogStyle: GatewayWsLogStyle =
@@ -82,11 +82,11 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
setGatewayWsLogStyle(wsLogStyle);
if (opts.rawStream) {
process.env.CLAWDBOT_RAW_STREAM = "1";
process.env.OPENCLAW_RAW_STREAM = "1";
}
const rawStreamPath = toOptionString(opts.rawStreamPath);
if (rawStreamPath) {
process.env.CLAWDBOT_RAW_STREAM_PATH = rawStreamPath;
process.env.OPENCLAW_RAW_STREAM_PATH = rawStreamPath;
}
if (devMode) {
@@ -134,7 +134,9 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
}
if (opts.token) {
const token = toOptionString(opts.token);
if (token) process.env.CLAWDBOT_GATEWAY_TOKEN = token;
if (token) {
process.env.OPENCLAW_GATEWAY_TOKEN = token;
}
}
const authModeRaw = toOptionString(opts.auth);
const authMode: GatewayAuthMode | null =
@@ -163,7 +165,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
if (!opts.allowUnconfigured && mode !== "local") {
if (!configExists) {
defaultRuntime.error(
`Missing config. Run \`${formatCliCommand("moltbot setup")}\` or set gateway.mode=local (or pass --allow-unconfigured).`,
`Missing config. Run \`${formatCliCommand("openclaw setup")}\` or set gateway.mode=local (or pass --allow-unconfigured).`,
);
} else {
defaultRuntime.error(
@@ -220,7 +222,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
defaultRuntime.error(
[
"Gateway auth is set to token, but no token is configured.",
"Set gateway.auth.token (or CLAWDBOT_GATEWAY_TOKEN), or pass --token.",
"Set gateway.auth.token (or OPENCLAW_GATEWAY_TOKEN), or pass --token.",
...authHints,
]
.filter(Boolean)
@@ -233,7 +235,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
defaultRuntime.error(
[
"Gateway auth is set to password, but no password is configured.",
"Set gateway.auth.password (or CLAWDBOT_GATEWAY_PASSWORD), or pass --password.",
"Set gateway.auth.password (or OPENCLAW_GATEWAY_PASSWORD), or pass --password.",
...authHints,
]
.filter(Boolean)
@@ -246,7 +248,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
defaultRuntime.error(
[
`Refusing to bind gateway to ${bind} without auth.`,
"Set gateway.auth.token/password (or CLAWDBOT_GATEWAY_TOKEN/CLAWDBOT_GATEWAY_PASSWORD) or pass --token/--password.",
"Set gateway.auth.token/password (or OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD) or pass --token/--password.",
...authHints,
]
.filter(Boolean)
@@ -286,7 +288,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
) {
const errMessage = describeUnknownError(err);
defaultRuntime.error(
`Gateway failed to start: ${errMessage}\nIf the gateway is supervised, stop it with: ${formatCliCommand("moltbot gateway stop")}`,
`Gateway failed to start: ${errMessage}\nIf the gateway is supervised, stop it with: ${formatCliCommand("openclaw gateway stop")}`,
);
try {
const diagnostics = await inspectPortUsage(port);
@@ -316,7 +318,7 @@ export function addGatewayRunCommand(cmd: Command): Command {
)
.option(
"--token <token>",
"Shared token required in connect.params.auth.token (default: CLAWDBOT_GATEWAY_TOKEN env if set)",
"Shared token required in connect.params.auth.token (default: OPENCLAW_GATEWAY_TOKEN env if set)",
)
.option("--auth <mode>", 'Gateway auth mode ("token"|"password")')
.option("--password <password>", "Password for auth mode=password")

View File

@@ -64,25 +64,25 @@ export function extractGatewayMiskeys(parsed: unknown): {
}
export function renderGatewayServiceStopHints(env: NodeJS.ProcessEnv = process.env): string[] {
const profile = env.CLAWDBOT_PROFILE;
const profile = env.OPENCLAW_PROFILE;
switch (process.platform) {
case "darwin":
return [
`Tip: ${formatCliCommand("moltbot gateway stop")}`,
`Tip: ${formatCliCommand("openclaw gateway stop")}`,
`Or: launchctl bootout gui/$UID/${resolveGatewayLaunchAgentLabel(profile)}`,
];
case "linux":
return [
`Tip: ${formatCliCommand("moltbot gateway stop")}`,
`Tip: ${formatCliCommand("openclaw gateway stop")}`,
`Or: systemctl --user stop ${resolveGatewaySystemdServiceName(profile)}.service`,
];
case "win32":
return [
`Tip: ${formatCliCommand("moltbot gateway stop")}`,
`Tip: ${formatCliCommand("openclaw gateway stop")}`,
`Or: schtasks /End /TN "${resolveGatewayWindowsTaskName(profile)}"`,
];
default:
return [`Tip: ${formatCliCommand("moltbot gateway stop")}`];
return [`Tip: ${formatCliCommand("openclaw gateway stop")}`];
}
}

View File

@@ -77,22 +77,22 @@ describe("gateway SIGTERM", () => {
});
it("exits 0 on SIGTERM", { timeout: 180_000 }, async () => {
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-gateway-test-"));
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-gateway-test-"));
const out: string[] = [];
const err: string[] = [];
const nodeBin = process.execPath;
const env = {
...process.env,
CLAWDBOT_NO_RESPAWN: "1",
CLAWDBOT_STATE_DIR: stateDir,
CLAWDBOT_SKIP_CHANNELS: "1",
CLAWDBOT_SKIP_GMAIL_WATCHER: "1",
CLAWDBOT_SKIP_CRON: "1",
CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER: "1",
CLAWDBOT_SKIP_CANVAS_HOST: "1",
OPENCLAW_NO_RESPAWN: "1",
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_SKIP_CHANNELS: "1",
OPENCLAW_SKIP_GMAIL_WATCHER: "1",
OPENCLAW_SKIP_CRON: "1",
OPENCLAW_SKIP_BROWSER_CONTROL_SERVER: "1",
OPENCLAW_SKIP_CANVAS_HOST: "1",
};
const bootstrapPath = path.join(stateDir, "moltbot-entry-bootstrap.mjs");
const bootstrapPath = path.join(stateDir, "openclaw-entry-bootstrap.mjs");
const runLoopPath = path.resolve("src/cli/gateway-cli/run-loop.ts");
const runtimePath = path.resolve("src/runtime.ts");
fs.writeFileSync(

View File

@@ -9,14 +9,14 @@ const report: HookStatusReport = {
{
name: "session-memory",
description: "Save session context to memory",
source: "moltbot-bundled",
source: "openclaw-bundled",
pluginId: undefined,
filePath: "/tmp/hooks/session-memory/HOOK.md",
baseDir: "/tmp/hooks/session-memory",
handlerPath: "/tmp/hooks/session-memory/handler.js",
hookKey: "session-memory",
emoji: "💾",
homepage: "https://docs.molt.bot/hooks#session-memory",
homepage: "https://docs.openclaw.ai/hooks#session-memory",
events: ["command:new"],
always: false,
disabled: false,
@@ -62,7 +62,7 @@ describe("hooks cli formatting", () => {
{
name: "plugin-hook",
description: "Hook from plugin",
source: "moltbot-plugin",
source: "openclaw-plugin",
pluginId: "voice-call",
filePath: "/tmp/hooks/plugin-hook/HOOK.md",
baseDir: "/tmp/hooks/plugin-hook",

View File

@@ -3,7 +3,7 @@ import fsp from "node:fs/promises";
import path from "node:path";
import type { Command } from "commander";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveArchiveKind } from "../infra/archive.js";
import {
buildWorkspaceHookStatus,
@@ -57,7 +57,7 @@ function mergeHookEntries(pluginEntries: HookEntry[], workspaceEntries: HookEntr
return Array.from(merged.values());
}
function buildHooksReport(config: MoltbotConfig): HookStatusReport {
function buildHooksReport(config: OpenClawConfig): HookStatusReport {
const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config));
const workspaceEntries = loadWorkspaceHookEntries(workspaceDir, { config });
const pluginReport = buildPluginStatusReport({ config, workspaceDir });
@@ -141,7 +141,7 @@ export function formatHooksList(report: HookStatusReport, opts: HooksListOptions
if (hooks.length === 0) {
const message = opts.eligible
? `No eligible hooks found. Run \`${formatCliCommand("moltbot hooks list")}\` to see all hooks.`
? `No eligible hooks found. Run \`${formatCliCommand("openclaw hooks list")}\` to see all hooks.`
: "No hooks found.";
return message;
}
@@ -197,7 +197,7 @@ export function formatHookInfo(
if (opts.json) {
return JSON.stringify({ error: "not found", hook: hookName }, null, 2);
}
return `Hook "${hookName}" not found. Run \`${formatCliCommand("moltbot hooks list")}\` to see available hooks.`;
return `Hook "${hookName}" not found. Run \`${formatCliCommand("openclaw hooks list")}\` to see available hooks.`;
}
if (opts.json) {
@@ -424,7 +424,7 @@ export function registerHooksCli(program: Command): void {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/hooks", "docs.molt.bot/cli/hooks")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/hooks", "docs.openclaw.ai/cli/hooks")}\n`,
);
hooks
@@ -533,7 +533,7 @@ export function registerHooksCli(program: Command): void {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
hooks: {
...cfg.hooks,
@@ -594,7 +594,7 @@ export function registerHooksCli(program: Command): void {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
hooks: {
...cfg.hooks,
@@ -674,7 +674,7 @@ export function registerHooksCli(program: Command): void {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
hooks: {
...cfg.hooks,

View File

@@ -18,7 +18,7 @@ describe("logs cli", () => {
it("writes output directly to stdout/stderr", async () => {
callGatewayFromCli.mockResolvedValueOnce({
file: "/tmp/moltbot.log",
file: "/tmp/openclaw.log",
cursor: 1,
size: 123,
lines: ["raw line"],
@@ -55,7 +55,7 @@ describe("logs cli", () => {
it("warns when the output pipe closes", async () => {
callGatewayFromCli.mockResolvedValueOnce({
file: "/tmp/moltbot.log",
file: "/tmp/openclaw.log",
lines: ["line one"],
});

View File

@@ -113,7 +113,7 @@ function createLogWriters() {
onBrokenPipe: (err, stream) => {
const code = err.code ?? "EPIPE";
const target = stream === process.stdout ? "stdout" : "stderr";
const message = `moltbot logs: output ${target} closed (${code}). Stopping tail.`;
const message = `openclaw logs: output ${target} closed (${code}). Stopping tail.`;
try {
clearActiveProgressLine();
process.stderr.write(`${message}\n`);
@@ -141,7 +141,7 @@ function emitGatewayError(
) {
const details = buildGatewayConnectionDetails({ url: opts.url });
const message = "Gateway not reachable. Is it running and accessible?";
const hint = `Hint: run \`${formatCliCommand("moltbot doctor")}\`.`;
const hint = `Hint: run \`${formatCliCommand("openclaw doctor")}\`.`;
const errorText = err instanceof Error ? err.message : String(err);
if (mode === "json") {
@@ -180,7 +180,8 @@ export function registerLogsCli(program: Command) {
.option("--no-color", "Disable ANSI colors")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/logs", "docs.molt.bot/cli/logs")}\n`,
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/logs", "docs.openclaw.ai/cli/logs")}\n`,
);
addGatewayClientOptions(logs);

View File

@@ -37,7 +37,7 @@ describe("memory cli", () => {
files: 2,
chunks: 5,
dirty: false,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",
@@ -82,7 +82,7 @@ describe("memory cli", () => {
files: 0,
chunks: 0,
dirty: true,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",
@@ -121,7 +121,7 @@ describe("memory cli", () => {
files: 1,
chunks: 1,
dirty: false,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",
@@ -154,7 +154,7 @@ describe("memory cli", () => {
files: 0,
chunks: 0,
dirty: false,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",
@@ -186,7 +186,7 @@ describe("memory cli", () => {
files: 1,
chunks: 1,
dirty: false,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",
@@ -224,7 +224,7 @@ describe("memory cli", () => {
files: 1,
chunks: 1,
dirty: false,
workspaceDir: "/tmp/clawd",
workspaceDir: "/tmp/openclaw",
dbPath: "/tmp/memory.sqlite",
provider: "openai",
model: "text-embedding-3-small",

View File

@@ -455,7 +455,7 @@ export function registerMemoryCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/memory", "docs.molt.bot/cli/memory")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/memory", "docs.openclaw.ai/cli/memory")}\n`,
);
memory

View File

@@ -44,7 +44,7 @@ export function registerModelsCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/models", "docs.molt.bot/cli/models")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/models", "docs.openclaw.ai/cli/models")}\n`,
);
models

View File

@@ -47,7 +47,7 @@ type NodeDaemonStatusOptions = {
};
function renderNodeServiceStartHints(): string[] {
const base = [formatCliCommand("moltbot node install"), formatCliCommand("moltbot node start")];
const base = [formatCliCommand("openclaw node install"), formatCliCommand("openclaw node start")];
switch (process.platform) {
case "darwin":
return [
@@ -169,7 +169,7 @@ export async function runNodeDaemonInstall(opts: NodeDaemonInstallOptions) {
});
if (!json) {
defaultRuntime.log(`Node service already ${service.loadedText}.`);
defaultRuntime.log(`Reinstall with: ${formatCliCommand("moltbot node install --force")}`);
defaultRuntime.log(`Reinstall with: ${formatCliCommand("openclaw node install --force")}`);
}
return;
}
@@ -561,7 +561,7 @@ export async function runNodeDaemonStatus(opts: NodeDaemonStatusOptions = {}) {
};
const hintEnv = {
...baseEnv,
CLAWDBOT_LOG_PREFIX: baseEnv.CLAWDBOT_LOG_PREFIX ?? "node",
OPENCLAW_LOG_PREFIX: baseEnv.OPENCLAW_LOG_PREFIX ?? "node",
} as NodeJS.ProcessEnv;
if (runtime?.missingUnit) {

View File

@@ -23,7 +23,8 @@ export function registerNodeCli(program: Command) {
.description("Run a headless node host (system.run/system.which)")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/node", "docs.molt.bot/cli/node")}\n`,
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/node", "docs.openclaw.ai/cli/node")}\n`,
);
node

View File

@@ -51,11 +51,11 @@ describe("nodes camera helpers", () => {
tmpDir: "/tmp",
id: "id1",
});
expect(p).toBe(path.join("/tmp", "moltbot-camera-snap-front-id1.jpg"));
expect(p).toBe(path.join("/tmp", "openclaw-camera-snap-front-id1.jpg"));
});
it("writes base64 to file", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-test-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-"));
const out = path.join(dir, "x.bin");
await writeBase64ToFile(out, "aGk=");
await expect(fs.readFile(out, "utf8")).resolves.toBe("hi");

View File

@@ -221,7 +221,7 @@ export function registerNodesCanvasCommands(nodes: Command) {
const { version, messageCount } = validateA2UIJsonl(jsonl);
if (version === "v0.9") {
throw new Error(
"Detected A2UI v0.9 JSONL (createSurface). Moltbot currently supports v0.8 only.",
"Detected A2UI v0.9 JSONL (createSurface). OpenClaw currently supports v0.8 only.",
);
}
await invokeCanvas(opts, "canvas.a2ui.pushJSONL", { jsonl });

View File

@@ -17,7 +17,7 @@ export function registerNodesCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/nodes", "docs.molt.bot/cli/nodes")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/nodes", "docs.openclaw.ai/cli/nodes")}\n`,
);
registerNodesStatusCommands(nodes);

View File

@@ -33,6 +33,6 @@ describe("nodes screen helpers", () => {
tmpDir: "/tmp",
id: "id1",
});
expect(p).toBe(path.join("/tmp", "moltbot-screen-record-id1.mp4"));
expect(p).toBe(path.join("/tmp", "openclaw-screen-record-id1.mp4"));
});
});

View File

@@ -42,7 +42,7 @@ export function screenRecordTempPath(opts: { ext: string; tmpDir?: string; id?:
const tmpDir = opts.tmpDir ?? os.tmpdir();
const id = opts.id ?? randomUUID();
const ext = opts.ext.startsWith(".") ? opts.ext : `.${opts.ext}`;
return path.join(tmpDir, `moltbot-screen-record-${id}${ext}`);
return path.join(tmpDir, `openclaw-screen-record-${id}${ext}`);
}
export async function writeScreenRecordToFile(filePath: string, base64: string) {

View File

@@ -53,7 +53,7 @@ export function registerPairingCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/pairing", "docs.molt.bot/cli/pairing")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/pairing", "docs.openclaw.ai/cli/pairing")}\n`,
);
pairing
@@ -115,12 +115,12 @@ export function registerPairingCli(program: Command) {
const resolvedCode = opts.channel ? codeOrChannel : code;
if (!opts.channel && !code) {
throw new Error(
`Usage: ${formatCliCommand("moltbot pairing approve <channel> <code>")} (or: ${formatCliCommand("moltbot pairing approve --channel <channel> <code>")})`,
`Usage: ${formatCliCommand("openclaw pairing approve <channel> <code>")} (or: ${formatCliCommand("openclaw pairing approve --channel <channel> <code>")})`,
);
}
if (opts.channel && code != null) {
throw new Error(
`Too many arguments. Use: ${formatCliCommand("moltbot pairing approve --channel <channel> <code>")}`,
`Too many arguments. Use: ${formatCliCommand("openclaw pairing approve --channel <channel> <code>")}`,
);
}
const channel = parseChannel(channelRaw, channels);

View File

@@ -1,7 +1,7 @@
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { loadConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging.js";
import { loadMoltbotPlugins } from "../plugins/loader.js";
import { loadOpenClawPlugins } from "../plugins/loader.js";
import type { PluginLogger } from "../plugins/types.js";
const log = createSubsystemLogger("plugins");
@@ -17,7 +17,7 @@ export function ensurePluginRegistryLoaded(): void {
error: (msg) => log.error(msg),
debug: (msg) => log.debug(msg),
};
loadMoltbotPlugins({
loadOpenClawPlugins({
config,
workspaceDir,
logger,

View File

@@ -3,7 +3,7 @@ import path from "node:path";
import type { Command } from "commander";
import { loadConfig, writeConfigFile } from "../config/config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveArchiveKind } from "../infra/archive.js";
import { installPluginFromNpmSpec, installPluginFromPath } from "../plugins/install.js";
import { recordPluginInstall } from "../plugins/installs.js";
@@ -67,9 +67,9 @@ function formatPluginLine(plugin: PluginRecord, verbose = false): string {
}
function applySlotSelectionForPlugin(
config: MoltbotConfig,
config: OpenClawConfig,
pluginId: string,
): { config: MoltbotConfig; warnings: string[] } {
): { config: OpenClawConfig; warnings: string[] } {
const report = buildPluginStatusReport({ config });
const plugin = report.plugins.find((entry) => entry.id === pluginId);
if (!plugin) {
@@ -94,11 +94,11 @@ function logSlotWarnings(warnings: string[]) {
export function registerPluginsCli(program: Command) {
const plugins = program
.command("plugins")
.description("Manage Moltbot plugins/extensions")
.description("Manage OpenClaw plugins/extensions")
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/plugins", "docs.molt.bot/cli/plugins")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/plugins", "docs.openclaw.ai/cli/plugins")}\n`,
);
plugins
@@ -246,7 +246,7 @@ export function registerPluginsCli(program: Command) {
.argument("<id>", "Plugin id")
.action(async (id: string) => {
const cfg = loadConfig();
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
plugins: {
...cfg.plugins,
@@ -308,7 +308,7 @@ export function registerPluginsCli(program: Command) {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
plugins: {
...cfg.plugins,
@@ -353,7 +353,7 @@ export function registerPluginsCli(program: Command) {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
plugins: {
...cfg.plugins,
@@ -417,7 +417,7 @@ export function registerPluginsCli(program: Command) {
process.exit(1);
}
let next: MoltbotConfig = {
let next: OpenClawConfig = {
...cfg,
plugins: {
...cfg.plugins,
@@ -521,7 +521,7 @@ export function registerPluginsCli(program: Command) {
lines.push(`- ${target}${diag.message}`);
}
}
const docs = formatDocsLink("/plugin", "docs.molt.bot/plugin");
const docs = formatDocsLink("/plugin", "docs.openclaw.ai/plugin");
lines.push("");
lines.push(`${theme.muted("Docs:")} ${docs}`);
defaultRuntime.log(lines.join("\n"));

View File

@@ -7,42 +7,42 @@ describe("parseCliProfileArgs", () => {
it("leaves gateway --dev for subcommands", () => {
const res = parseCliProfileArgs([
"node",
"moltbot",
"openclaw",
"gateway",
"--dev",
"--allow-unconfigured",
]);
if (!res.ok) throw new Error(res.error);
expect(res.profile).toBeNull();
expect(res.argv).toEqual(["node", "moltbot", "gateway", "--dev", "--allow-unconfigured"]);
expect(res.argv).toEqual(["node", "openclaw", "gateway", "--dev", "--allow-unconfigured"]);
});
it("still accepts global --dev before subcommand", () => {
const res = parseCliProfileArgs(["node", "moltbot", "--dev", "gateway"]);
const res = parseCliProfileArgs(["node", "openclaw", "--dev", "gateway"]);
if (!res.ok) throw new Error(res.error);
expect(res.profile).toBe("dev");
expect(res.argv).toEqual(["node", "moltbot", "gateway"]);
expect(res.argv).toEqual(["node", "openclaw", "gateway"]);
});
it("parses --profile value and strips it", () => {
const res = parseCliProfileArgs(["node", "moltbot", "--profile", "work", "status"]);
const res = parseCliProfileArgs(["node", "openclaw", "--profile", "work", "status"]);
if (!res.ok) throw new Error(res.error);
expect(res.profile).toBe("work");
expect(res.argv).toEqual(["node", "moltbot", "status"]);
expect(res.argv).toEqual(["node", "openclaw", "status"]);
});
it("rejects missing profile value", () => {
const res = parseCliProfileArgs(["node", "moltbot", "--profile"]);
const res = parseCliProfileArgs(["node", "openclaw", "--profile"]);
expect(res.ok).toBe(false);
});
it("rejects combining --dev with --profile (dev first)", () => {
const res = parseCliProfileArgs(["node", "moltbot", "--dev", "--profile", "work", "status"]);
const res = parseCliProfileArgs(["node", "openclaw", "--dev", "--profile", "work", "status"]);
expect(res.ok).toBe(false);
});
it("rejects combining --dev with --profile (profile first)", () => {
const res = parseCliProfileArgs(["node", "moltbot", "--profile", "work", "--dev", "status"]);
const res = parseCliProfileArgs(["node", "openclaw", "--profile", "work", "--dev", "status"]);
expect(res.ok).toBe(false);
});
});
@@ -55,85 +55,85 @@ describe("applyCliProfileEnv", () => {
env,
homedir: () => "/home/peter",
});
const expectedStateDir = path.join("/home/peter", ".clawdbot-dev");
expect(env.CLAWDBOT_PROFILE).toBe("dev");
expect(env.CLAWDBOT_STATE_DIR).toBe(expectedStateDir);
expect(env.CLAWDBOT_CONFIG_PATH).toBe(path.join(expectedStateDir, "moltbot.json"));
expect(env.CLAWDBOT_GATEWAY_PORT).toBe("19001");
const expectedStateDir = path.join("/home/peter", ".openclaw-dev");
expect(env.OPENCLAW_PROFILE).toBe("dev");
expect(env.OPENCLAW_STATE_DIR).toBe(expectedStateDir);
expect(env.OPENCLAW_CONFIG_PATH).toBe(path.join(expectedStateDir, "openclaw.json"));
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19001");
});
it("does not override explicit env values", () => {
const env: Record<string, string | undefined> = {
CLAWDBOT_STATE_DIR: "/custom",
CLAWDBOT_GATEWAY_PORT: "19099",
OPENCLAW_STATE_DIR: "/custom",
OPENCLAW_GATEWAY_PORT: "19099",
};
applyCliProfileEnv({
profile: "dev",
env,
homedir: () => "/home/peter",
});
expect(env.CLAWDBOT_STATE_DIR).toBe("/custom");
expect(env.CLAWDBOT_GATEWAY_PORT).toBe("19099");
expect(env.CLAWDBOT_CONFIG_PATH).toBe(path.join("/custom", "moltbot.json"));
expect(env.OPENCLAW_STATE_DIR).toBe("/custom");
expect(env.OPENCLAW_GATEWAY_PORT).toBe("19099");
expect(env.OPENCLAW_CONFIG_PATH).toBe(path.join("/custom", "openclaw.json"));
});
});
describe("formatCliCommand", () => {
it("returns command unchanged when no profile is set", () => {
expect(formatCliCommand("moltbot doctor --fix", {})).toBe("moltbot doctor --fix");
expect(formatCliCommand("openclaw doctor --fix", {})).toBe("openclaw doctor --fix");
});
it("returns command unchanged when profile is default", () => {
expect(formatCliCommand("moltbot doctor --fix", { CLAWDBOT_PROFILE: "default" })).toBe(
"moltbot doctor --fix",
expect(formatCliCommand("openclaw doctor --fix", { OPENCLAW_PROFILE: "default" })).toBe(
"openclaw doctor --fix",
);
});
it("returns command unchanged when profile is Default (case-insensitive)", () => {
expect(formatCliCommand("moltbot doctor --fix", { CLAWDBOT_PROFILE: "Default" })).toBe(
"moltbot doctor --fix",
expect(formatCliCommand("openclaw doctor --fix", { OPENCLAW_PROFILE: "Default" })).toBe(
"openclaw doctor --fix",
);
});
it("returns command unchanged when profile is invalid", () => {
expect(formatCliCommand("moltbot doctor --fix", { CLAWDBOT_PROFILE: "bad profile" })).toBe(
"moltbot doctor --fix",
expect(formatCliCommand("openclaw doctor --fix", { OPENCLAW_PROFILE: "bad profile" })).toBe(
"openclaw doctor --fix",
);
});
it("returns command unchanged when --profile is already present", () => {
expect(
formatCliCommand("moltbot --profile work doctor --fix", { CLAWDBOT_PROFILE: "work" }),
).toBe("moltbot --profile work doctor --fix");
formatCliCommand("openclaw --profile work doctor --fix", { OPENCLAW_PROFILE: "work" }),
).toBe("openclaw --profile work doctor --fix");
});
it("returns command unchanged when --dev is already present", () => {
expect(formatCliCommand("moltbot --dev doctor", { CLAWDBOT_PROFILE: "dev" })).toBe(
"moltbot --dev doctor",
expect(formatCliCommand("openclaw --dev doctor", { OPENCLAW_PROFILE: "dev" })).toBe(
"openclaw --dev doctor",
);
});
it("inserts --profile flag when profile is set", () => {
expect(formatCliCommand("moltbot doctor --fix", { CLAWDBOT_PROFILE: "work" })).toBe(
"moltbot --profile work doctor --fix",
expect(formatCliCommand("openclaw doctor --fix", { OPENCLAW_PROFILE: "work" })).toBe(
"openclaw --profile work doctor --fix",
);
});
it("trims whitespace from profile", () => {
expect(formatCliCommand("moltbot doctor --fix", { CLAWDBOT_PROFILE: " jbclawd " })).toBe(
"moltbot --profile jbclawd doctor --fix",
expect(formatCliCommand("openclaw doctor --fix", { OPENCLAW_PROFILE: " jbopenclaw " })).toBe(
"openclaw --profile jbopenclaw doctor --fix",
);
});
it("handles command with no args after moltbot", () => {
expect(formatCliCommand("moltbot", { CLAWDBOT_PROFILE: "test" })).toBe(
"moltbot --profile test",
it("handles command with no args after openclaw", () => {
expect(formatCliCommand("openclaw", { OPENCLAW_PROFILE: "test" })).toBe(
"openclaw --profile test",
);
});
it("handles pnpm wrapper", () => {
expect(formatCliCommand("pnpm moltbot doctor", { CLAWDBOT_PROFILE: "work" })).toBe(
"pnpm moltbot --profile work doctor",
expect(formatCliCommand("pnpm openclaw doctor", { OPENCLAW_PROFILE: "work" })).toBe(
"pnpm openclaw --profile work doctor",
);
});
});

View File

@@ -82,7 +82,7 @@ export function parseCliProfileArgs(argv: string[]): CliProfileParseResult {
function resolveProfileStateDir(profile: string, homedir: () => string): string {
const suffix = profile.toLowerCase() === "default" ? "" : `-${profile}`;
return path.join(homedir(), `.clawdbot${suffix}`);
return path.join(homedir(), `.openclaw${suffix}`);
}
export function applyCliProfileEnv(params: {
@@ -96,16 +96,16 @@ export function applyCliProfileEnv(params: {
if (!profile) return;
// Convenience only: fill defaults, never override explicit env values.
env.CLAWDBOT_PROFILE = profile;
env.OPENCLAW_PROFILE = profile;
const stateDir = env.CLAWDBOT_STATE_DIR?.trim() || resolveProfileStateDir(profile, homedir);
if (!env.CLAWDBOT_STATE_DIR?.trim()) env.CLAWDBOT_STATE_DIR = stateDir;
const stateDir = env.OPENCLAW_STATE_DIR?.trim() || resolveProfileStateDir(profile, homedir);
if (!env.OPENCLAW_STATE_DIR?.trim()) env.OPENCLAW_STATE_DIR = stateDir;
if (!env.CLAWDBOT_CONFIG_PATH?.trim()) {
env.CLAWDBOT_CONFIG_PATH = path.join(stateDir, "moltbot.json");
if (!env.OPENCLAW_CONFIG_PATH?.trim()) {
env.OPENCLAW_CONFIG_PATH = path.join(stateDir, "openclaw.json");
}
if (profile === "dev" && !env.CLAWDBOT_GATEWAY_PORT?.trim()) {
env.CLAWDBOT_GATEWAY_PORT = "19001";
if (profile === "dev" && !env.OPENCLAW_GATEWAY_PORT?.trim()) {
env.OPENCLAW_GATEWAY_PORT = "19001";
}
}

View File

@@ -174,7 +174,7 @@ describe("cli program (nodes media)", () => {
const out = String(runtime.log.mock.calls[0]?.[0] ?? "");
const mediaPath = out.replace(/^MEDIA:/, "").trim();
expect(mediaPath).toMatch(/moltbot-camera-clip-front-.*\.mp4$/);
expect(mediaPath).toMatch(/openclaw-camera-clip-front-.*\.mp4$/);
try {
await expect(fs.readFile(mediaPath, "utf8")).resolves.toBe("hi");
@@ -421,7 +421,7 @@ describe("cli program (nodes media)", () => {
const out = String(runtime.log.mock.calls[0]?.[0] ?? "");
const mediaPath = out.replace(/^MEDIA:/, "").trim();
expect(mediaPath).toMatch(/moltbot-canvas-snapshot-.*\.png$/);
expect(mediaPath).toMatch(/openclaw-canvas-snapshot-.*\.png$/);
try {
await expect(fs.readFile(mediaPath, "utf8")).resolves.toBe("hi");

View File

@@ -71,7 +71,9 @@ export async function ensureConfigReady(params: {
params.runtime.error(legacyIssues.map((issue) => ` ${error(issue)}`).join("\n"));
}
params.runtime.error("");
params.runtime.error(`${muted("Run:")} ${commandText(formatCliCommand("moltbot doctor --fix"))}`);
params.runtime.error(
`${muted("Run:")} ${commandText(formatCliCommand("openclaw doctor --fix"))}`,
);
if (!allowInvalid) {
params.runtime.exit(1);
}

View File

@@ -8,21 +8,24 @@ import type { ProgramContext } from "./context.js";
const CLI_NAME = resolveCliName();
const EXAMPLES = [
["moltbot channels login --verbose", "Link personal WhatsApp Web and show QR + connection logs."],
[
'moltbot message send --target +15555550123 --message "Hi" --json',
"openclaw channels login --verbose",
"Link personal WhatsApp Web and show QR + connection logs.",
],
[
'openclaw message send --target +15555550123 --message "Hi" --json',
"Send via your web session and print JSON result.",
],
["moltbot gateway --port 18789", "Run the WebSocket Gateway locally."],
["moltbot --dev gateway", "Run a dev Gateway (isolated state/config) on ws://127.0.0.1:19001."],
["moltbot gateway --force", "Kill anything bound to the default gateway port, then start it."],
["moltbot gateway ...", "Gateway control via WebSocket."],
["openclaw gateway --port 18789", "Run the WebSocket Gateway locally."],
["openclaw --dev gateway", "Run a dev Gateway (isolated state/config) on ws://127.0.0.1:19001."],
["openclaw gateway --force", "Kill anything bound to the default gateway port, then start it."],
["openclaw gateway ...", "Gateway control via WebSocket."],
[
'moltbot agent --to +15555550123 --message "Run summary" --deliver',
'openclaw agent --to +15555550123 --message "Run summary" --deliver',
"Talk directly to the agent using the Gateway; optionally send the WhatsApp reply.",
],
[
'moltbot message send --channel telegram --target @mychat --message "Hi"',
'openclaw message send --channel telegram --target @mychat --message "Hi"',
"Send via your Telegram bot.",
],
] as const;
@@ -34,11 +37,11 @@ export function configureProgramHelp(program: Command, ctx: ProgramContext) {
.version(ctx.programVersion)
.option(
"--dev",
"Dev profile: isolate state under ~/.clawdbot-dev, default gateway port 19001, and shift derived ports (browser/canvas)",
"Dev profile: isolate state under ~/.openclaw-dev, default gateway port 19001, and shift derived ports (browser/canvas)",
)
.option(
"--profile <name>",
"Use a named profile (isolates CLAWDBOT_STATE_DIR/CLAWDBOT_CONFIG_PATH under ~/.clawdbot-<name>)",
"Use a named profile (isolates OPENCLAW_STATE_DIR/OPENCLAW_CONFIG_PATH under ~/.openclaw-<name>)",
);
program.option("--no-color", "Disable ANSI colors", false);
@@ -82,7 +85,7 @@ export function configureProgramHelp(program: Command, ctx: ProgramContext) {
program.addHelpText("afterAll", ({ command }) => {
if (command !== program) return "";
const docs = formatDocsLink("/cli", "docs.molt.bot/cli");
const docs = formatDocsLink("/cli", "docs.openclaw.ai/cli");
return `\n${theme.heading("Examples:")}\n${fmtExamples}\n\n${theme.muted("Docs:")} ${docs}\n`;
});
}

View File

@@ -29,7 +29,7 @@ export function registerPreActionHooks(program: Command, programVersion: string)
if (hasHelpOrVersion(argv)) return;
const commandPath = getCommandPath(argv, 2);
const hideBanner =
isTruthyEnvValue(process.env.CLAWDBOT_HIDE_BANNER) ||
isTruthyEnvValue(process.env.OPENCLAW_HIDE_BANNER) ||
commandPath[0] === "update" ||
(commandPath[0] === "plugins" && commandPath[1] === "update");
if (!hideBanner) {

View File

@@ -51,24 +51,24 @@ export function registerAgentCommands(program: Command, args: { agentChannelOpti
`
${theme.heading("Examples:")}
${formatHelpExamples([
['moltbot agent --to +15555550123 --message "status update"', "Start a new session."],
['moltbot agent --agent ops --message "Summarize logs"', "Use a specific agent."],
['openclaw agent --to +15555550123 --message "status update"', "Start a new session."],
['openclaw agent --agent ops --message "Summarize logs"', "Use a specific agent."],
[
'moltbot agent --session-id 1234 --message "Summarize inbox" --thinking medium',
'openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium',
"Target a session with explicit thinking level.",
],
[
'moltbot agent --to +15555550123 --message "Trace logs" --verbose on --json',
'openclaw agent --to +15555550123 --message "Trace logs" --verbose on --json',
"Enable verbose logging and JSON output.",
],
['moltbot agent --to +15555550123 --message "Summon reply" --deliver', "Deliver reply."],
['openclaw agent --to +15555550123 --message "Summon reply" --deliver', "Deliver reply."],
[
'moltbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"',
'openclaw agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"',
"Send reply to a different channel/target.",
],
])}
${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.molt.bot/cli/agent")}`,
${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.openclaw.ai/cli/agent")}`,
)
.action(async (opts) => {
const verboseLevel = typeof opts.verbose === "string" ? opts.verbose.toLowerCase() : "";
@@ -86,7 +86,7 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.molt.bot/cli/agent"
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/agents", "docs.molt.bot/cli/agents")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/agents", "docs.openclaw.ai/cli/agents")}\n`,
);
agents
@@ -155,11 +155,14 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.molt.bot/cli/agent"
`
${theme.heading("Examples:")}
${formatHelpExamples([
['moltbot agents set-identity --agent main --name "Clawd" --emoji "🦞"', "Set name + emoji."],
["moltbot agents set-identity --agent main --avatar avatars/clawd.png", "Set avatar path."],
["moltbot agents set-identity --workspace ~/clawd --from-identity", "Load from IDENTITY.md."],
['openclaw agents set-identity --agent main --name "OpenClaw" --emoji "🦞"', "Set name + emoji."],
["openclaw agents set-identity --agent main --avatar avatars/openclaw.png", "Set avatar path."],
[
"moltbot agents set-identity --identity-file ~/clawd/IDENTITY.md --agent main",
"openclaw agents set-identity --workspace ~/.openclaw/workspace --from-identity",
"Load from IDENTITY.md.",
],
[
"openclaw agents set-identity --identity-file ~/.openclaw/workspace/IDENTITY.md --agent main",
"Use a specific IDENTITY.md.",
],
])}

View File

@@ -16,7 +16,7 @@ export function registerConfigureCommand(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/configure", "docs.molt.bot/cli/configure")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/configure", "docs.openclaw.ai/cli/configure")}\n`,
)
.option(
"--section <section>",

View File

@@ -15,7 +15,7 @@ export function registerMaintenanceCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/doctor", "docs.molt.bot/cli/doctor")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/doctor", "docs.openclaw.ai/cli/doctor")}\n`,
)
.option("--no-workspace-suggestions", "Disable workspace memory system suggestions", false)
.option("--yes", "Accept defaults without prompting", false)
@@ -45,7 +45,7 @@ export function registerMaintenanceCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dashboard", "docs.molt.bot/cli/dashboard")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dashboard", "docs.openclaw.ai/cli/dashboard")}\n`,
)
.option("--no-open", "Print URL but do not launch a browser", false)
.action(async (opts) => {
@@ -62,7 +62,7 @@ export function registerMaintenanceCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/reset", "docs.molt.bot/cli/reset")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/reset", "docs.openclaw.ai/cli/reset")}\n`,
)
.option("--scope <scope>", "config|config+creds+sessions|full (default: interactive prompt)")
.option("--yes", "Skip confirmation prompts", false)
@@ -85,7 +85,7 @@ export function registerMaintenanceCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/uninstall", "docs.molt.bot/cli/uninstall")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/uninstall", "docs.openclaw.ai/cli/uninstall")}\n`,
)
.option("--service", "Remove the gateway service", false)
.option("--state", "Remove state + config", false)

View File

@@ -31,22 +31,22 @@ export function registerMessageCommands(program: Command, ctx: ProgramContext) {
`
${theme.heading("Examples:")}
${formatHelpExamples([
['moltbot message send --target +15555550123 --message "Hi"', "Send a text message."],
['openclaw message send --target +15555550123 --message "Hi"', "Send a text message."],
[
'moltbot message send --target +15555550123 --message "Hi" --media photo.jpg',
'openclaw message send --target +15555550123 --message "Hi" --media photo.jpg',
"Send a message with media.",
],
[
'moltbot message poll --channel discord --target channel:123 --poll-question "Snack?" --poll-option Pizza --poll-option Sushi',
'openclaw message poll --channel discord --target channel:123 --poll-question "Snack?" --poll-option Pizza --poll-option Sushi',
"Create a Discord poll.",
],
[
'moltbot message react --channel discord --target 123 --message-id 456 --emoji "✅"',
'openclaw message react --channel discord --target 123 --message-id 456 --emoji "✅"',
"React to a message.",
],
])}
${theme.muted("Docs:")} ${formatDocsLink("/cli/message", "docs.molt.bot/cli/message")}`,
${theme.muted("Docs:")} ${formatDocsLink("/cli/message", "docs.openclaw.ai/cli/message")}`,
)
.action(() => {
message.help({ error: true });

View File

@@ -38,9 +38,9 @@ export function registerOnboardCommand(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/onboard", "docs.molt.bot/cli/onboard")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/onboard", "docs.openclaw.ai/cli/onboard")}\n`,
)
.option("--workspace <dir>", "Agent workspace directory (default: ~/clawd)")
.option("--workspace <dir>", "Agent workspace directory (default: ~/.openclaw/workspace)")
.option("--reset", "Reset config + credentials + sessions + workspace before running wizard")
.option("--non-interactive", "Run without prompts", false)
.option(

View File

@@ -10,15 +10,15 @@ import { runCommandWithRuntime } from "../cli-utils.js";
export function registerSetupCommand(program: Command) {
program
.command("setup")
.description("Initialize ~/.clawdbot/moltbot.json and the agent workspace")
.description("Initialize ~/.openclaw/openclaw.json and the agent workspace")
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/setup", "docs.molt.bot/cli/setup")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/setup", "docs.openclaw.ai/cli/setup")}\n`,
)
.option(
"--workspace <dir>",
"Agent workspace directory (default: ~/clawd; stored as agents.defaults.workspace)",
"Agent workspace directory (default: ~/.openclaw/workspace; stored as agents.defaults.workspace)",
)
.option("--wizard", "Run the interactive onboarding wizard", false)
.option("--non-interactive", "Run the wizard without prompts", false)

View File

@@ -39,21 +39,21 @@ export function registerStatusHealthSessionsCommands(program: Command) {
"after",
() =>
`\n${theme.heading("Examples:")}\n${formatHelpExamples([
["moltbot status", "Show channel health + session summary."],
["moltbot status --all", "Full diagnosis (read-only)."],
["moltbot status --json", "Machine-readable output."],
["moltbot status --usage", "Show model provider usage/quota snapshots."],
["openclaw status", "Show channel health + session summary."],
["openclaw status --all", "Full diagnosis (read-only)."],
["openclaw status --json", "Machine-readable output."],
["openclaw status --usage", "Show model provider usage/quota snapshots."],
[
"moltbot status --deep",
"openclaw status --deep",
"Run channel probes (WA + Telegram + Discord + Slack + Signal).",
],
["moltbot status --deep --timeout 5000", "Tighten probe timeout."],
["openclaw status --deep --timeout 5000", "Tighten probe timeout."],
])}`,
)
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/status", "docs.molt.bot/cli/status")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/status", "docs.openclaw.ai/cli/status")}\n`,
)
.action(async (opts) => {
const verbose = resolveVerbose(opts);
@@ -87,7 +87,7 @@ export function registerStatusHealthSessionsCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/health", "docs.molt.bot/cli/health")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/health", "docs.openclaw.ai/cli/health")}\n`,
)
.action(async (opts) => {
const verbose = resolveVerbose(opts);
@@ -119,10 +119,10 @@ export function registerStatusHealthSessionsCommands(program: Command) {
"after",
() =>
`\n${theme.heading("Examples:")}\n${formatHelpExamples([
["moltbot sessions", "List all sessions."],
["moltbot sessions --active 120", "Only last 2 hours."],
["moltbot sessions --json", "Machine-readable output."],
["moltbot sessions --store ./tmp/sessions.json", "Use a specific session store."],
["openclaw sessions", "List all sessions."],
["openclaw sessions --active 120", "Only last 2 hours."],
["openclaw sessions --json", "Machine-readable output."],
["openclaw sessions --store ./tmp/sessions.json", "Use a specific session store."],
])}\n\n${theme.muted(
"Shows token usage per session when the agent reports it; set agents.defaults.contextTokens to see % of your model window.",
)}`,
@@ -130,7 +130,7 @@ export function registerStatusHealthSessionsCommands(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sessions", "docs.molt.bot/cli/sessions")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sessions", "docs.openclaw.ai/cli/sessions")}\n`,
)
.action(async (opts) => {
setVerbose(Boolean(opts.verbose));

View File

@@ -29,7 +29,7 @@ describe("registerSubCliCommands", () => {
beforeEach(() => {
process.env = { ...originalEnv };
delete process.env.CLAWDBOT_DISABLE_LAZY_SUBCOMMANDS;
delete process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS;
registerAcpCli.mockClear();
acpAction.mockClear();
registerNodesCli.mockClear();
@@ -42,7 +42,7 @@ describe("registerSubCliCommands", () => {
});
it("registers only the primary placeholder and dispatches", async () => {
process.argv = ["node", "moltbot", "acp"];
process.argv = ["node", "openclaw", "acp"];
const program = new Command();
registerSubCliCommands(program, process.argv);
@@ -55,7 +55,7 @@ describe("registerSubCliCommands", () => {
});
it("registers placeholders for all subcommands when no primary", () => {
process.argv = ["node", "moltbot"];
process.argv = ["node", "openclaw"];
const program = new Command();
registerSubCliCommands(program, process.argv);
@@ -66,9 +66,9 @@ describe("registerSubCliCommands", () => {
});
it("re-parses argv for lazy subcommands", async () => {
process.argv = ["node", "moltbot", "nodes", "list"];
process.argv = ["node", "openclaw", "nodes", "list"];
const program = new Command();
program.name("moltbot");
program.name("openclaw");
registerSubCliCommands(program, process.argv);
expect(program.commands.map((cmd) => cmd.name())).toEqual(["nodes"]);
@@ -80,9 +80,9 @@ describe("registerSubCliCommands", () => {
});
it("replaces placeholder when registering a subcommand by name", async () => {
process.argv = ["node", "moltbot", "acp", "--help"];
process.argv = ["node", "openclaw", "acp", "--help"];
const program = new Command();
program.name("moltbot");
program.name("openclaw");
registerSubCliCommands(program, process.argv);
await registerSubCliByName(program, "acp");
@@ -90,7 +90,7 @@ describe("registerSubCliCommands", () => {
const names = program.commands.map((cmd) => cmd.name());
expect(names.filter((name) => name === "acp")).toHaveLength(1);
await program.parseAsync(["node", "moltbot", "acp"], { from: "user" });
await program.parseAsync(["node", "openclaw", "acp"], { from: "user" });
expect(registerAcpCli).toHaveBeenCalledTimes(1);
expect(acpAction).toHaveBeenCalledTimes(1);
});

View File

@@ -1,5 +1,5 @@
import type { Command } from "commander";
import type { MoltbotConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/config.js";
import { isTruthyEnvValue } from "../../infra/env.js";
import { buildParseArgv, getPrimaryCommand, hasHelpOrVersion } from "../argv.js";
import { resolveActionArgs } from "./helpers.js";
@@ -13,16 +13,16 @@ type SubCliEntry = {
};
const shouldRegisterPrimaryOnly = (argv: string[]) => {
if (isTruthyEnvValue(process.env.CLAWDBOT_DISABLE_LAZY_SUBCOMMANDS)) return false;
if (isTruthyEnvValue(process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS)) return false;
if (hasHelpOrVersion(argv)) return false;
return true;
};
const shouldEagerRegisterSubcommands = (_argv: string[]) => {
return isTruthyEnvValue(process.env.CLAWDBOT_DISABLE_LAZY_SUBCOMMANDS);
return isTruthyEnvValue(process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS);
};
const loadConfig = async (): Promise<MoltbotConfig> => {
const loadConfig = async (): Promise<OpenClawConfig> => {
const mod = await import("../../config/config.js");
return mod.loadConfig();
};

View File

@@ -20,7 +20,7 @@ async function prepareRoutedCommand(params: {
}
export async function tryRouteCli(argv: string[]): Promise<boolean> {
if (isTruthyEnvValue(process.env.CLAWDBOT_DISABLE_ROUTE_FIRST)) return false;
if (isTruthyEnvValue(process.env.OPENCLAW_DISABLE_ROUTE_FIRST)) return false;
if (hasHelpOrVersion(argv)) return false;
const path = getCommandPath(argv, 2);

View File

@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
import { loadDotEnv } from "../infra/dotenv.js";
import { normalizeEnv } from "../infra/env.js";
import { isMainModule } from "../infra/is-main.js";
import { ensureMoltbotCliOnPath } from "../infra/path-env.js";
import { ensureOpenClawCliOnPath } from "../infra/path-env.js";
import { assertSupportedRuntime } from "../infra/runtime-guard.js";
import { formatUncaughtError } from "../infra/errors.js";
import { installUnhandledRejectionHandler } from "../infra/unhandled-rejections.js";
@@ -27,7 +27,7 @@ export async function runCli(argv: string[] = process.argv) {
const normalizedArgv = stripWindowsNodeExec(argv);
loadDotEnv({ quiet: true });
normalizeEnv();
ensureMoltbotCliOnPath();
ensureOpenClawCliOnPath();
// Enforce the minimum supported runtime before doing any work.
assertSupportedRuntime();
@@ -45,7 +45,7 @@ export async function runCli(argv: string[] = process.argv) {
installUnhandledRejectionHandler();
process.on("uncaughtException", (error) => {
console.error("[moltbot] Uncaught exception:", formatUncaughtError(error));
console.error("[openclaw] Uncaught exception:", formatUncaughtError(error));
process.exit(1);
});

View File

@@ -15,30 +15,30 @@ type CommandOptions = Record<string, unknown>;
const SANDBOX_EXAMPLES = {
main: [
["moltbot sandbox list", "List all sandbox containers."],
["moltbot sandbox list --browser", "List only browser containers."],
["moltbot sandbox recreate --all", "Recreate all containers."],
["moltbot sandbox recreate --session main", "Recreate a specific session."],
["moltbot sandbox recreate --agent mybot", "Recreate agent containers."],
["moltbot sandbox explain", "Explain effective sandbox config."],
["openclaw sandbox list", "List all sandbox containers."],
["openclaw sandbox list --browser", "List only browser containers."],
["openclaw sandbox recreate --all", "Recreate all containers."],
["openclaw sandbox recreate --session main", "Recreate a specific session."],
["openclaw sandbox recreate --agent mybot", "Recreate agent containers."],
["openclaw sandbox explain", "Explain effective sandbox config."],
],
list: [
["moltbot sandbox list", "List all sandbox containers."],
["moltbot sandbox list --browser", "List only browser containers."],
["moltbot sandbox list --json", "JSON output."],
["openclaw sandbox list", "List all sandbox containers."],
["openclaw sandbox list --browser", "List only browser containers."],
["openclaw sandbox list --json", "JSON output."],
],
recreate: [
["moltbot sandbox recreate --all", "Recreate all containers."],
["moltbot sandbox recreate --session main", "Recreate a specific session."],
["moltbot sandbox recreate --agent mybot", "Recreate a specific agent (includes sub-agents)."],
["moltbot sandbox recreate --browser --all", "Recreate only browser containers."],
["moltbot sandbox recreate --all --force", "Skip confirmation."],
["openclaw sandbox recreate --all", "Recreate all containers."],
["openclaw sandbox recreate --session main", "Recreate a specific session."],
["openclaw sandbox recreate --agent mybot", "Recreate a specific agent (includes sub-agents)."],
["openclaw sandbox recreate --browser --all", "Recreate only browser containers."],
["openclaw sandbox recreate --all --force", "Skip confirmation."],
],
explain: [
["moltbot sandbox explain", "Show effective sandbox config."],
["moltbot sandbox explain --session agent:main:main", "Explain a specific session."],
["moltbot sandbox explain --agent work", "Explain an agent sandbox."],
["moltbot sandbox explain --json", "JSON output."],
["openclaw sandbox explain", "Show effective sandbox config."],
["openclaw sandbox explain --session agent:main:main", "Explain a specific session."],
["openclaw sandbox explain --agent work", "Explain an agent sandbox."],
["openclaw sandbox explain --json", "JSON output."],
],
} as const;
@@ -68,7 +68,7 @@ export function registerSandboxCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sandbox", "docs.molt.bot/cli/sandbox")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sandbox", "docs.openclaw.ai/cli/sandbox")}\n`,
)
.action(() => {
sandbox.help({ error: true });

View File

@@ -34,7 +34,7 @@ export function registerSecurityCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/security", "docs.molt.bot/cli/security")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/security", "docs.openclaw.ai/cli/security")}\n`,
);
security
@@ -66,12 +66,12 @@ export function registerSecurityCli(program: Command) {
const muted = (text: string) => (rich ? theme.muted(text) : text);
const lines: string[] = [];
lines.push(heading("Moltbot security audit"));
lines.push(heading("OpenClaw security audit"));
lines.push(muted(`Summary: ${formatSummary(report.summary)}`));
lines.push(muted(`Run deeper: ${formatCliCommand("moltbot security audit --deep")}`));
lines.push(muted(`Run deeper: ${formatCliCommand("openclaw security audit --deep")}`));
if (opts.fix) {
lines.push(muted(`Fix: ${formatCliCommand("moltbot security audit --fix")}`));
lines.push(muted(`Fix: ${formatCliCommand("openclaw security audit --fix")}`));
if (!fixResult) {
lines.push(muted("Fixes: failed to apply (unexpected error)"));
} else if (

View File

@@ -92,7 +92,7 @@ export function formatSkillsList(report: SkillStatusReport, opts: SkillsListOpti
if (skills.length === 0) {
const message = opts.eligible
? `No eligible skills found. Run \`${formatCliCommand("moltbot skills list")}\` to see all skills.`
? `No eligible skills found. Run \`${formatCliCommand("openclaw skills list")}\` to see all skills.`
: "No skills found.";
return appendClawdHubHint(message, opts.json);
}
@@ -150,7 +150,7 @@ export function formatSkillInfo(
return JSON.stringify({ error: "not found", skill: skillName }, null, 2);
}
return appendClawdHubHint(
`Skill "${skillName}" not found. Run \`${formatCliCommand("moltbot skills list")}\` to see available skills.`,
`Skill "${skillName}" not found. Run \`${formatCliCommand("openclaw skills list")}\` to see available skills.`,
opts.json,
);
}
@@ -337,7 +337,7 @@ export function registerSkillsCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/skills", "docs.molt.bot/cli/skills")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/skills", "docs.openclaw.ai/cli/skills")}\n`,
);
skills

View File

@@ -23,7 +23,7 @@ export function registerSystemCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/system", "docs.molt.bot/cli/system")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/system", "docs.openclaw.ai/cli/system")}\n`,
);
addGatewayClientOptions(

View File

@@ -1,4 +1,4 @@
const DEFAULT_TAGLINE = "All your chats, one Moltbot.";
const DEFAULT_TAGLINE = "All your chats, one OpenClaw.";
const HOLIDAY_TAGLINES = {
newYear:
@@ -241,7 +241,7 @@ export function activeTaglines(options: TaglineOptions = {}): string[] {
export function pickTagline(options: TaglineOptions = {}): string {
const env = options.env ?? process.env;
const override = env?.CLAWDBOT_TAGLINE_INDEX;
const override = env?.OPENCLAW_TAGLINE_INDEX;
if (override !== undefined) {
const parsed = Number.parseInt(override, 10);
if (!Number.isNaN(parsed) && parsed >= 0) {

View File

@@ -20,7 +20,7 @@ export function registerTuiCli(program: Command) {
.option("--history-limit <n>", "History entries to load", "200")
.addHelpText(
"after",
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/tui", "docs.molt.bot/cli/tui")}\n`,
() => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/tui", "docs.openclaw.ai/cli/tui")}\n`,
)
.action(async (opts) => {
try {

View File

@@ -22,8 +22,8 @@ vi.mock("../infra/update-runner.js", () => ({
runGatewayUpdate: vi.fn(),
}));
vi.mock("../infra/moltbot-root.js", () => ({
resolveMoltbotPackageRoot: vi.fn(),
vi.mock("../infra/openclaw-root.js", () => ({
resolveOpenClawPackageRoot: vi.fn(),
}));
vi.mock("../config/config.js", () => ({
@@ -88,12 +88,12 @@ describe("update-cli", () => {
beforeEach(async () => {
vi.clearAllMocks();
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { readConfigFileSnapshot } = await import("../config/config.js");
const { checkUpdateStatus, fetchNpmTagVersion, resolveNpmChannelTag } =
await import("../infra/update-check.js");
const { runCommandWithTimeout } = await import("../process/exec.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(process.cwd());
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(process.cwd());
vi.mocked(readConfigFileSnapshot).mockResolvedValue(baseSnapshot);
vi.mocked(fetchNpmTagVersion).mockResolvedValue({
tag: "latest",
@@ -185,7 +185,7 @@ describe("update-cli", () => {
await updateStatusCommand({ json: false });
const logs = vi.mocked(defaultRuntime.log).mock.calls.map((call) => call[0]);
expect(logs.join("\n")).toContain("Moltbot update status");
expect(logs.join("\n")).toContain("OpenClaw update status");
});
it("updateStatusCommand emits JSON", async () => {
@@ -218,20 +218,20 @@ describe("update-cli", () => {
});
it("defaults to stable channel for package installs when unset", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-"));
try {
await fs.writeFile(
path.join(tempDir, "package.json"),
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
JSON.stringify({ name: "openclaw", version: "1.0.0" }),
"utf-8",
);
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
const { checkUpdateStatus } = await import("../infra/update-check.js");
const { updateCommand } = await import("./update-cli.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(tempDir);
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(tempDir);
vi.mocked(checkUpdateStatus).mockResolvedValue({
root: tempDir,
installKind: "package",
@@ -283,22 +283,22 @@ describe("update-cli", () => {
});
it("falls back to latest when beta tag is older than release", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-"));
try {
await fs.writeFile(
path.join(tempDir, "package.json"),
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
JSON.stringify({ name: "openclaw", version: "1.0.0" }),
"utf-8",
);
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { readConfigFileSnapshot } = await import("../config/config.js");
const { resolveNpmChannelTag } = await import("../infra/update-check.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
const { updateCommand } = await import("./update-cli.js");
const { checkUpdateStatus } = await import("../infra/update-check.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(tempDir);
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(tempDir);
vi.mocked(readConfigFileSnapshot).mockResolvedValue({
...baseSnapshot,
config: { update: { channel: "beta" } },
@@ -336,19 +336,19 @@ describe("update-cli", () => {
});
it("honors --tag override", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-"));
try {
await fs.writeFile(
path.join(tempDir, "package.json"),
JSON.stringify({ name: "moltbot", version: "1.0.0" }),
JSON.stringify({ name: "openclaw", version: "1.0.0" }),
"utf-8",
);
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
const { updateCommand } = await import("./update-cli.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(tempDir);
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(tempDir);
vi.mocked(runGatewayUpdate).mockResolvedValue({
status: "ok",
mode: "npm",
@@ -514,23 +514,23 @@ describe("update-cli", () => {
});
it("requires confirmation on downgrade when non-interactive", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-"));
try {
setTty(false);
await fs.writeFile(
path.join(tempDir, "package.json"),
JSON.stringify({ name: "moltbot", version: "2.0.0" }),
JSON.stringify({ name: "openclaw", version: "2.0.0" }),
"utf-8",
);
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { resolveNpmChannelTag } = await import("../infra/update-check.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
const { defaultRuntime } = await import("../runtime.js");
const { updateCommand } = await import("./update-cli.js");
const { checkUpdateStatus } = await import("../infra/update-check.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(tempDir);
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(tempDir);
vi.mocked(checkUpdateStatus).mockResolvedValue({
root: tempDir,
installKind: "package",
@@ -567,23 +567,23 @@ describe("update-cli", () => {
});
it("allows downgrade with --yes in non-interactive mode", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-"));
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-"));
try {
setTty(false);
await fs.writeFile(
path.join(tempDir, "package.json"),
JSON.stringify({ name: "moltbot", version: "2.0.0" }),
JSON.stringify({ name: "openclaw", version: "2.0.0" }),
"utf-8",
);
const { resolveMoltbotPackageRoot } = await import("../infra/moltbot-root.js");
const { resolveOpenClawPackageRoot } = await import("../infra/openclaw-root.js");
const { resolveNpmChannelTag } = await import("../infra/update-check.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
const { defaultRuntime } = await import("../runtime.js");
const { updateCommand } = await import("./update-cli.js");
const { checkUpdateStatus } = await import("../infra/update-check.js");
vi.mocked(resolveMoltbotPackageRoot).mockResolvedValue(tempDir);
vi.mocked(resolveOpenClawPackageRoot).mockResolvedValue(tempDir);
vi.mocked(checkUpdateStatus).mockResolvedValue({
root: tempDir,
installKind: "package",
@@ -636,11 +636,11 @@ describe("update-cli", () => {
});
it("updateWizardCommand offers dev checkout and forwards selections", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-update-wizard-"));
const previousGitDir = process.env.CLAWDBOT_GIT_DIR;
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-wizard-"));
const previousGitDir = process.env.OPENCLAW_GIT_DIR;
try {
setTty(true);
process.env.CLAWDBOT_GIT_DIR = tempDir;
process.env.OPENCLAW_GIT_DIR = tempDir;
const { checkUpdateStatus } = await import("../infra/update-check.js");
const { runGatewayUpdate } = await import("../infra/update-runner.js");
@@ -671,7 +671,7 @@ describe("update-cli", () => {
const call = vi.mocked(runGatewayUpdate).mock.calls[0]?.[0];
expect(call?.channel).toBe("dev");
} finally {
process.env.CLAWDBOT_GIT_DIR = previousGitDir;
process.env.OPENCLAW_GIT_DIR = previousGitDir;
await fs.rm(tempDir, { recursive: true, force: true });
}
});

View File

@@ -5,7 +5,7 @@ import path from "node:path";
import type { Command } from "commander";
import { readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
import { resolveMoltbotPackageRoot } from "../infra/moltbot-root.js";
import { resolveOpenClawPackageRoot } from "../infra/openclaw-root.js";
import {
checkUpdateStatus,
compareSemverStrings,
@@ -81,7 +81,7 @@ const STEP_LABELS: Record<string, string> = {
"deps install": "Installing dependencies",
build: "Building",
"ui:build": "Building UI",
"moltbot doctor": "Running doctor checks",
"openclaw doctor": "Running doctor checks",
"git rev-parse HEAD (after)": "Verifying update",
"global update": "Updating via package manager",
"global install": "Installing global package",
@@ -111,17 +111,17 @@ const UPDATE_QUIPS = [
];
const MAX_LOG_CHARS = 8000;
const DEFAULT_PACKAGE_NAME = "moltbot";
const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME, "moltbot"]);
const DEFAULT_PACKAGE_NAME = "openclaw";
const CORE_PACKAGE_NAMES = new Set([DEFAULT_PACKAGE_NAME]);
const CLI_NAME = resolveCliName();
const CLAWDBOT_REPO_URL = "https://github.com/moltbot/moltbot.git";
const DEFAULT_GIT_DIR = path.join(os.homedir(), "moltbot");
const OPENCLAW_REPO_URL = "https://github.com/openclaw/openclaw.git";
const DEFAULT_GIT_DIR = path.join(os.homedir(), ".openclaw");
function normalizeTag(value?: string | null): string | null {
if (!value) return null;
const trimmed = value.trim();
if (!trimmed) return null;
if (trimmed.startsWith("moltbot@")) return trimmed.slice("moltbot@".length);
if (trimmed.startsWith("openclaw@")) return trimmed.slice("openclaw@".length);
if (trimmed.startsWith(`${DEFAULT_PACKAGE_NAME}@`)) {
return trimmed.slice(`${DEFAULT_PACKAGE_NAME}@`.length);
}
@@ -200,8 +200,12 @@ async function isEmptyDir(targetPath: string): Promise<boolean> {
}
function resolveGitInstallDir(): string {
const override = process.env.CLAWDBOT_GIT_DIR?.trim();
const override = process.env.OPENCLAW_GIT_DIR?.trim();
if (override) return path.resolve(override);
return resolveDefaultGitDir();
}
function resolveDefaultGitDir(): string {
return DEFAULT_GIT_DIR;
}
@@ -261,7 +265,7 @@ async function ensureGitCheckout(params: {
if (!dirExists) {
return await runUpdateStep({
name: "git clone",
argv: ["git", "clone", CLAWDBOT_REPO_URL, params.dir],
argv: ["git", "clone", OPENCLAW_REPO_URL, params.dir],
timeoutMs: params.timeoutMs,
progress: params.progress,
});
@@ -271,12 +275,12 @@ async function ensureGitCheckout(params: {
const empty = await isEmptyDir(params.dir);
if (!empty) {
throw new Error(
`CLAWDBOT_GIT_DIR points at a non-git directory: ${params.dir}. Set CLAWDBOT_GIT_DIR to an empty folder or a moltbot checkout.`,
`OPENCLAW_GIT_DIR points at a non-git directory: ${params.dir}. Set OPENCLAW_GIT_DIR to an empty folder or an openclaw checkout.`,
);
}
return await runUpdateStep({
name: "git clone",
argv: ["git", "clone", CLAWDBOT_REPO_URL, params.dir],
argv: ["git", "clone", OPENCLAW_REPO_URL, params.dir],
cwd: params.dir,
timeoutMs: params.timeoutMs,
progress: params.progress,
@@ -284,7 +288,7 @@ async function ensureGitCheckout(params: {
}
if (!(await isCorePackage(params.dir))) {
throw new Error(`CLAWDBOT_GIT_DIR does not look like a core checkout: ${params.dir}.`);
throw new Error(`OPENCLAW_GIT_DIR does not look like a core checkout: ${params.dir}.`);
}
return null;
@@ -336,7 +340,7 @@ export async function updateStatusCommand(opts: UpdateStatusOptions): Promise<vo
}
const root =
(await resolveMoltbotPackageRoot({
(await resolveOpenClawPackageRoot({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
@@ -411,7 +415,7 @@ export async function updateStatusCommand(opts: UpdateStatusOptions): Promise<vo
},
];
defaultRuntime.log(theme.heading("Moltbot update status"));
defaultRuntime.log(theme.heading("OpenClaw update status"));
defaultRuntime.log("");
defaultRuntime.log(
renderTable({
@@ -576,7 +580,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
}
const root =
(await resolveMoltbotPackageRoot({
(await resolveOpenClawPackageRoot({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
@@ -685,7 +689,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
const showProgress = !opts.json && process.stdout.isTTY;
if (!opts.json) {
defaultRuntime.log(theme.heading("Updating Moltbot..."));
defaultRuntime.log(theme.heading("Updating OpenClaw..."));
defaultRuntime.log("");
}
@@ -823,12 +827,12 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
if (result.reason === "not-git-install") {
defaultRuntime.log(
theme.warn(
`Skipped: this Moltbot install isn't a git checkout, and the package manager couldn't be detected. Update via your package manager, then run \`${replaceCliName(formatCliCommand("moltbot doctor"), CLI_NAME)}\` and \`${replaceCliName(formatCliCommand("moltbot gateway restart"), CLI_NAME)}\`.`,
`Skipped: this OpenClaw install isn't a git checkout, and the package manager couldn't be detected. Update via your package manager, then run \`${replaceCliName(formatCliCommand("openclaw doctor"), CLI_NAME)}\` and \`${replaceCliName(formatCliCommand("openclaw gateway restart"), CLI_NAME)}\`.`,
),
);
defaultRuntime.log(
theme.muted(
`Examples: \`${replaceCliName("npm i -g moltbot@latest", CLI_NAME)}\` or \`${replaceCliName("pnpm add -g moltbot@latest", CLI_NAME)}\``,
`Examples: \`${replaceCliName("npm i -g openclaw@latest", CLI_NAME)}\` or \`${replaceCliName("pnpm add -g openclaw@latest", CLI_NAME)}\``,
),
);
}
@@ -929,7 +933,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
if (!opts.json && restarted) {
defaultRuntime.log(theme.success("Daemon restarted successfully."));
defaultRuntime.log("");
process.env.CLAWDBOT_UPDATE_IN_PROGRESS = "1";
process.env.OPENCLAW_UPDATE_IN_PROGRESS = "1";
try {
const { doctorCommand } = await import("../commands/doctor.js");
const interactiveDoctor = Boolean(process.stdin.isTTY) && !opts.json && opts.yes !== true;
@@ -937,7 +941,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
} catch (err) {
defaultRuntime.log(theme.warn(`Doctor failed: ${String(err)}`));
} finally {
delete process.env.CLAWDBOT_UPDATE_IN_PROGRESS;
delete process.env.OPENCLAW_UPDATE_IN_PROGRESS;
}
}
} catch (err) {
@@ -945,7 +949,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
defaultRuntime.log(theme.warn(`Daemon restart failed: ${String(err)}`));
defaultRuntime.log(
theme.muted(
`You may need to restart the service manually: ${replaceCliName(formatCliCommand("moltbot gateway restart"), CLI_NAME)}`,
`You may need to restart the service manually: ${replaceCliName(formatCliCommand("openclaw gateway restart"), CLI_NAME)}`,
),
);
}
@@ -955,13 +959,13 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
if (result.mode === "npm" || result.mode === "pnpm") {
defaultRuntime.log(
theme.muted(
`Tip: Run \`${replaceCliName(formatCliCommand("moltbot doctor"), CLI_NAME)}\`, then \`${replaceCliName(formatCliCommand("moltbot gateway restart"), CLI_NAME)}\` to apply updates to a running gateway.`,
`Tip: Run \`${replaceCliName(formatCliCommand("openclaw doctor"), CLI_NAME)}\`, then \`${replaceCliName(formatCliCommand("openclaw gateway restart"), CLI_NAME)}\` to apply updates to a running gateway.`,
),
);
} else {
defaultRuntime.log(
theme.muted(
`Tip: Run \`${replaceCliName(formatCliCommand("moltbot gateway restart"), CLI_NAME)}\` to apply updates to a running gateway.`,
`Tip: Run \`${replaceCliName(formatCliCommand("openclaw gateway restart"), CLI_NAME)}\` to apply updates to a running gateway.`,
),
);
}
@@ -975,7 +979,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promise<void> {
if (!process.stdin.isTTY) {
defaultRuntime.error(
"Update wizard requires a TTY. Use `moltbot update --channel <stable|beta|dev>` instead.",
"Update wizard requires a TTY. Use `openclaw update --channel <stable|beta|dev>` instead.",
);
defaultRuntime.exit(1);
return;
@@ -989,7 +993,7 @@ export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promi
}
const root =
(await resolveMoltbotPackageRoot({
(await resolveOpenClawPackageRoot({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
@@ -1066,7 +1070,7 @@ export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promi
const empty = await isEmptyDir(gitDir);
if (!empty) {
defaultRuntime.error(
`CLAWDBOT_GIT_DIR points at a non-git directory: ${gitDir}. Set CLAWDBOT_GIT_DIR to an empty folder or a moltbot checkout.`,
`OPENCLAW_GIT_DIR points at a non-git directory: ${gitDir}. Set OPENCLAW_GIT_DIR to an empty folder or an openclaw checkout.`,
);
defaultRuntime.exit(1);
return;
@@ -1074,7 +1078,7 @@ export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promi
}
const ok = await confirm({
message: stylePromptMessage(
`Create a git checkout at ${gitDir}? (override via CLAWDBOT_GIT_DIR)`,
`Create a git checkout at ${gitDir}? (override via OPENCLAW_GIT_DIR)`,
),
initialValue: true,
});
@@ -1111,7 +1115,7 @@ export async function updateWizardCommand(opts: UpdateWizardOptions = {}): Promi
export function registerUpdateCli(program: Command) {
const update = program
.command("update")
.description("Update Moltbot to the latest version")
.description("Update OpenClaw to the latest version")
.option("--json", "Output result as JSON", false)
.option("--no-restart", "Skip restarting the gateway service after a successful update")
.option("--channel <stable|beta|dev>", "Persist update channel (git + npm)")
@@ -1120,15 +1124,15 @@ export function registerUpdateCli(program: Command) {
.option("--yes", "Skip confirmation prompts (non-interactive)", false)
.addHelpText("after", () => {
const examples = [
["moltbot update", "Update a source checkout (git)"],
["moltbot update --channel beta", "Switch to beta channel (git + npm)"],
["moltbot update --channel dev", "Switch to dev channel (git + npm)"],
["moltbot update --tag beta", "One-off update to a dist-tag or version"],
["moltbot update --no-restart", "Update without restarting the service"],
["moltbot update --json", "Output result as JSON"],
["moltbot update --yes", "Non-interactive (accept downgrade prompts)"],
["moltbot update wizard", "Interactive update wizard"],
["moltbot --update", "Shorthand for moltbot update"],
["openclaw update", "Update a source checkout (git)"],
["openclaw update --channel beta", "Switch to beta channel (git + npm)"],
["openclaw update --channel dev", "Switch to dev channel (git + npm)"],
["openclaw update --tag beta", "One-off update to a dist-tag or version"],
["openclaw update --no-restart", "Update without restarting the service"],
["openclaw update --json", "Output result as JSON"],
["openclaw update --yes", "Non-interactive (accept downgrade prompts)"],
["openclaw update wizard", "Interactive update wizard"],
["openclaw --update", "Shorthand for openclaw update"],
] as const;
const fmtExamples = examples
.map(([cmd, desc]) => ` ${theme.command(cmd)} ${theme.muted(`# ${desc}`)}`)
@@ -1140,7 +1144,7 @@ ${theme.heading("What this does:")}
${theme.heading("Switch channels:")}
- Use --channel stable|beta|dev to persist the update channel in config
- Run moltbot update status to see the active channel and source
- Run openclaw update status to see the active channel and source
- Use --tag <dist-tag|version> for a one-off npm update without persisting
${theme.heading("Non-interactive:")}
@@ -1156,7 +1160,7 @@ ${theme.heading("Notes:")}
- Downgrades require confirmation (can break configuration)
- Skips update if the working directory has uncommitted changes
${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.molt.bot/cli/update")}`;
${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/update")}`;
})
.action(async (opts) => {
try {
@@ -1180,7 +1184,7 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.molt.bot/cli/updat
.option("--timeout <seconds>", "Timeout for each update step in seconds (default: 1200)")
.addHelpText(
"after",
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.molt.bot/cli/update")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/update")}\n`,
)
.action(async (opts) => {
try {
@@ -1200,14 +1204,14 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.molt.bot/cli/updat
"after",
() =>
`\n${theme.heading("Examples:")}\n${formatHelpExamples([
["moltbot update status", "Show channel + version status."],
["moltbot update status --json", "JSON output."],
["moltbot update status --timeout 10", "Custom timeout."],
["openclaw update status", "Show channel + version status."],
["openclaw update status --json", "JSON output."],
["openclaw update status --timeout 10", "Custom timeout."],
])}\n\n${theme.heading("Notes:")}\n${theme.muted(
"- Shows current update channel (stable/beta/dev) and source",
)}\n${theme.muted("- Includes git tag/branch/SHA for source checkouts")}\n\n${theme.muted(
"Docs:",
)} ${formatDocsLink("/cli/update", "docs.molt.bot/cli/update")}`,
)} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/update")}`,
)
.action(async (opts) => {
try {

View File

@@ -28,21 +28,21 @@ export function registerWebhooksCli(program: Command) {
.addHelpText(
"after",
() =>
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/webhooks", "docs.molt.bot/cli/webhooks")}\n`,
`\n${theme.muted("Docs:")} ${formatDocsLink("/cli/webhooks", "docs.openclaw.ai/cli/webhooks")}\n`,
);
const gmail = webhooks.command("gmail").description("Gmail Pub/Sub hooks (via gogcli)");
gmail
.command("setup")
.description("Configure Gmail watch + Pub/Sub + Moltbot hooks")
.description("Configure Gmail watch + Pub/Sub + OpenClaw hooks")
.requiredOption("--account <email>", "Gmail account to watch")
.option("--project <id>", "GCP project id (OAuth client owner)")
.option("--topic <name>", "Pub/Sub topic name", DEFAULT_GMAIL_TOPIC)
.option("--subscription <name>", "Pub/Sub subscription name", DEFAULT_GMAIL_SUBSCRIPTION)
.option("--label <label>", "Gmail label to watch", DEFAULT_GMAIL_LABEL)
.option("--hook-url <url>", "Moltbot hook URL")
.option("--hook-token <token>", "Moltbot hook token")
.option("--hook-url <url>", "OpenClaw hook URL")
.option("--hook-token <token>", "OpenClaw hook token")
.option("--push-token <token>", "Push token for gog watch serve")
.option("--bind <host>", "gog watch serve bind host", DEFAULT_GMAIL_SERVE_BIND)
.option("--port <port>", "gog watch serve port", String(DEFAULT_GMAIL_SERVE_PORT))
@@ -79,8 +79,8 @@ export function registerWebhooksCli(program: Command) {
.option("--topic <topic>", "Pub/Sub topic path (projects/.../topics/..)")
.option("--subscription <name>", "Pub/Sub subscription name")
.option("--label <label>", "Gmail label to watch")
.option("--hook-url <url>", "Moltbot hook URL")
.option("--hook-token <token>", "Moltbot hook token")
.option("--hook-url <url>", "OpenClaw hook URL")
.option("--hook-token <token>", "OpenClaw hook token")
.option("--push-token <token>", "Push token for gog watch serve")
.option("--bind <host>", "gog watch serve bind host")
.option("--port <port>", "gog watch serve port")