mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-28 17:43:05 +00:00
refactor: rename to openclaw
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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)?$/;
|
||||
|
||||
@@ -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("🦞")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>",
|
||||
|
||||
@@ -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",
|
||||
];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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"),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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`,
|
||||
);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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>",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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`);
|
||||
}
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")}`];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"],
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.",
|
||||
],
|
||||
])}
|
||||
|
||||
@@ -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>",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user