refactor: rename to openclaw

This commit is contained in:
Peter Steinberger
2026-01-30 03:15:10 +01:00
parent 4583f88626
commit 9a7160786a
2357 changed files with 16688 additions and 16788 deletions
+10 -10
View File
@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveOAuthDir } from "../config/paths.js";
import type { DmPolicy, GroupPolicy, WhatsAppAccountConfig } from "../config/types.js";
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
@@ -30,13 +30,13 @@ export type ResolvedWhatsAppAccount = {
debounceMs?: number;
};
function listConfiguredAccountIds(cfg: MoltbotConfig): string[] {
function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
const accounts = cfg.channels?.whatsapp?.accounts;
if (!accounts || typeof accounts !== "object") return [];
return Object.keys(accounts).filter(Boolean);
}
export function listWhatsAppAuthDirs(cfg: MoltbotConfig): string[] {
export function listWhatsAppAuthDirs(cfg: OpenClawConfig): string[] {
const oauthDir = resolveOAuthDir();
const whatsappDir = path.join(oauthDir, "whatsapp");
const authDirs = new Set<string>([oauthDir, path.join(whatsappDir, DEFAULT_ACCOUNT_ID)]);
@@ -59,24 +59,24 @@ export function listWhatsAppAuthDirs(cfg: MoltbotConfig): string[] {
return Array.from(authDirs);
}
export function hasAnyWhatsAppAuth(cfg: MoltbotConfig): boolean {
export function hasAnyWhatsAppAuth(cfg: OpenClawConfig): boolean {
return listWhatsAppAuthDirs(cfg).some((authDir) => hasWebCredsSync(authDir));
}
export function listWhatsAppAccountIds(cfg: MoltbotConfig): string[] {
export function listWhatsAppAccountIds(cfg: OpenClawConfig): string[] {
const ids = listConfiguredAccountIds(cfg);
if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
return ids.sort((a, b) => a.localeCompare(b));
}
export function resolveDefaultWhatsAppAccountId(cfg: MoltbotConfig): string {
export function resolveDefaultWhatsAppAccountId(cfg: OpenClawConfig): string {
const ids = listWhatsAppAccountIds(cfg);
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
return ids[0] ?? DEFAULT_ACCOUNT_ID;
}
function resolveAccountConfig(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
accountId: string,
): WhatsAppAccountConfig | undefined {
const accounts = cfg.channels?.whatsapp?.accounts;
@@ -102,7 +102,7 @@ function legacyAuthExists(authDir: string): boolean {
}
}
export function resolveWhatsAppAuthDir(params: { cfg: MoltbotConfig; accountId: string }): {
export function resolveWhatsAppAuthDir(params: { cfg: OpenClawConfig; accountId: string }): {
authDir: string;
isLegacy: boolean;
} {
@@ -125,7 +125,7 @@ export function resolveWhatsAppAuthDir(params: { cfg: MoltbotConfig; accountId:
}
export function resolveWhatsAppAccount(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
accountId?: string | null;
}): ResolvedWhatsAppAccount {
const rootCfg = params.cfg.channels?.whatsapp;
@@ -160,7 +160,7 @@ export function resolveWhatsAppAccount(params: {
};
}
export function listEnabledWhatsAppAccounts(cfg: MoltbotConfig): ResolvedWhatsAppAccount[] {
export function listEnabledWhatsAppAccounts(cfg: OpenClawConfig): ResolvedWhatsAppAccount[] {
return listWhatsAppAccountIds(cfg)
.map((accountId) => resolveWhatsAppAccount({ cfg, accountId }))
.filter((account) => account.enabled);
+6 -6
View File
@@ -15,16 +15,16 @@ describe("hasAnyWhatsAppAuth", () => {
};
beforeEach(() => {
previousOauthDir = process.env.CLAWDBOT_OAUTH_DIR;
tempOauthDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-oauth-"));
process.env.CLAWDBOT_OAUTH_DIR = tempOauthDir;
previousOauthDir = process.env.OPENCLAW_OAUTH_DIR;
tempOauthDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-oauth-"));
process.env.OPENCLAW_OAUTH_DIR = tempOauthDir;
});
afterEach(() => {
if (previousOauthDir === undefined) {
delete process.env.CLAWDBOT_OAUTH_DIR;
delete process.env.OPENCLAW_OAUTH_DIR;
} else {
process.env.CLAWDBOT_OAUTH_DIR = previousOauthDir;
process.env.OPENCLAW_OAUTH_DIR = previousOauthDir;
}
if (tempOauthDir) {
fs.rmSync(tempOauthDir, { recursive: true, force: true });
@@ -47,7 +47,7 @@ describe("hasAnyWhatsAppAuth", () => {
});
it("includes authDir overrides", () => {
const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-wa-auth-"));
const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-wa-auth-"));
try {
writeCreds(customDir);
const cfg = {
+1 -1
View File
@@ -43,7 +43,7 @@ export function requireActiveWebListener(accountId?: string | null): {
const listener = listeners.get(id) ?? null;
if (!listener) {
throw new Error(
`No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`moltbot channels login --channel whatsapp --account ${id}`)}.`,
`No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`openclaw channels login --channel whatsapp --account ${id}`)}.`,
);
}
return { accountId: id, listener };
+1 -1
View File
@@ -177,7 +177,7 @@ export async function pickWebChannel(
const hasWeb = await webAuthExists(authDir);
if (!hasWeb) {
throw new Error(
`No WhatsApp Web session found. Run \`${formatCliCommand("moltbot channels login --channel whatsapp --verbose")}\` to link.`,
`No WhatsApp Web session found. Run \`${formatCliCommand("openclaw channels login --channel whatsapp --verbose")}\` to link.`,
);
}
return choice;
@@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({
}));
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { monitorWebChannel } from "./auto-reply.js";
import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js";
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -104,7 +104,7 @@ describe("broadcast groups", () => {
strategy: "sequential",
"+1000": ["alfred", "baerbel"],
},
} satisfies MoltbotConfig);
} satisfies OpenClawConfig);
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);
@@ -158,7 +158,7 @@ describe("broadcast groups", () => {
strategy: "sequential",
"123@g.us": ["alfred", "baerbel"],
},
} satisfies MoltbotConfig);
} satisfies OpenClawConfig);
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);
@@ -269,7 +269,7 @@ describe("broadcast groups", () => {
strategy: "parallel",
"+1000": ["alfred", "baerbel"],
},
} satisfies MoltbotConfig);
} satisfies OpenClawConfig);
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);
@@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({
}));
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { monitorWebChannel } from "./auto-reply.js";
import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js";
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -103,7 +103,7 @@ describe("broadcast groups", () => {
broadcast: {
"+1000": ["alfred", "missing"],
},
} satisfies MoltbotConfig);
} satisfies OpenClawConfig);
const sendMedia = vi.fn();
const reply = vi.fn().mockResolvedValue(undefined);
@@ -16,7 +16,7 @@ vi.mock("../agents/pi-embedded.js", () => ({
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
import { getReplyFromConfig } from "../auto-reply/reply.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { monitorWebChannel } from "./auto-reply.js";
import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js";
@@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -63,7 +63,7 @@ afterEach(async () => {
const makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -102,7 +102,7 @@ describe("partial reply gating", () => {
const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" });
const mockConfig: MoltbotConfig = {
const mockConfig: OpenClawConfig = {
channels: { whatsapp: { allowFrom: ["*"] } },
};
@@ -145,7 +145,7 @@ describe("partial reply gating", () => {
const replyResolver = vi.fn().mockResolvedValue({ text: "final reply" });
const mockConfig: MoltbotConfig = {
const mockConfig: OpenClawConfig = {
channels: {
whatsapp: {
allowFrom: ["*"],
@@ -195,7 +195,7 @@ describe("partial reply gating", () => {
const replyResolver = vi.fn().mockResolvedValue(undefined);
const mockConfig: MoltbotConfig = {
const mockConfig: OpenClawConfig = {
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: store.storePath },
};
@@ -249,7 +249,7 @@ describe("partial reply gating", () => {
const replyResolver = vi.fn().mockResolvedValue(undefined);
const mockConfig: MoltbotConfig = {
const mockConfig: OpenClawConfig = {
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: store.storePath },
};
@@ -14,7 +14,7 @@ vi.mock("../agents/pi-embedded.js", () => ({
}));
import { resetInboundDedupe } from "../auto-reply/reply/inbound-dedupe.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { monitorWebChannel } from "./auto-reply.js";
import { resetLoadConfigMock, setLoadConfigMock } from "./test-helpers.js";
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -114,7 +114,7 @@ describe("typing controller idle", () => {
return { text: "final reply" };
});
const mockConfig: MoltbotConfig = {
const mockConfig: OpenClawConfig = {
channels: { whatsapp: { allowFrom: ["*"] } },
};
@@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -63,7 +63,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -47,7 +47,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -62,7 +62,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -47,7 +47,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -62,7 +62,7 @@ afterEach(async () => {
const makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -339,11 +339,11 @@ describe("web auto-reply", () => {
const firstPattern = escapeRegExp(firstTimestamp);
const secondPattern = escapeRegExp(secondTimestamp);
expect(firstArgs.Body).toMatch(
new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${firstPattern}\\] \\[moltbot\\] first`),
new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${firstPattern}\\] \\[openclaw\\] first`),
);
expect(firstArgs.Body).not.toContain("second");
expect(secondArgs.Body).toMatch(
new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${secondPattern}\\] \\[moltbot\\] second`),
new RegExp(`\\[WhatsApp \\+1 (\\+\\d+[smhd] )?${secondPattern}\\] \\[openclaw\\] second`),
);
expect(secondArgs.Body).not.toContain("first");
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -366,7 +366,7 @@ describe("web auto-reply", () => {
return { close: vi.fn() };
};
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wa-auth-"));
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wa-auth-"));
try {
await fs.writeFile(
@@ -444,7 +444,7 @@ describe("web auto-reply", () => {
return { close: vi.fn() };
};
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wa-auth-"));
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wa-auth-"));
try {
await fs.writeFile(
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -200,7 +200,7 @@ describe("web auto-reply", () => {
expect(resolver).toHaveBeenCalled();
const resolverArg = resolver.mock.calls[0][0];
expect(resolverArg.Body).toContain("[Richbot]");
expect(resolverArg.Body).not.toContain("[moltbot]");
expect(resolverArg.Body).not.toContain("[openclaw]");
resetLoadConfigMock();
});
it("does not derive responsePrefix from identity.name when unset", async () => {
@@ -48,7 +48,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -63,7 +63,7 @@ afterEach(async () => {
const makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -126,7 +126,7 @@ describe("web auto-reply", () => {
setLoadConfigMock(() => ({
messages: {
groupChat: { mentionPatterns: ["@clawd"] },
groupChat: { mentionPatterns: ["@openclaw"] },
},
session: { store: storePath },
}));
@@ -209,7 +209,7 @@ describe("web auto-reply", () => {
},
messages: {
groupChat: {
mentionPatterns: ["\\bclawd\\b"],
mentionPatterns: ["\\bopenclaw\\b"],
},
},
}));
@@ -248,9 +248,9 @@ describe("web auto-reply", () => {
expect(resolver).not.toHaveBeenCalled();
// Text-based mentionPatterns still work (user can type "clawd" explicitly).
// Text-based mentionPatterns still work (user can type "openclaw" explicitly).
await capturedOnMessage?.({
body: "clawd ping",
body: "openclaw ping",
from: "123@g.us",
conversationId: "123@g.us",
chatId: "123@g.us",
@@ -272,7 +272,7 @@ describe("web auto-reply", () => {
});
it("emits heartbeat logs with connection metadata", async () => {
vi.useFakeTimers();
const logPath = `/tmp/moltbot-heartbeat-${crypto.randomUUID()}.log`;
const logPath = `/tmp/openclaw-heartbeat-${crypto.randomUUID()}.log`;
setLoggerOverride({ level: "trace", file: logPath });
const runtime = {
@@ -313,7 +313,7 @@ describe("web auto-reply", () => {
expect(content).toMatch(/messagesHandled/);
});
it("logs outbound replies to file", async () => {
const logPath = `/tmp/moltbot-log-test-${crypto.randomUUID()}.log`;
const logPath = `/tmp/openclaw-log-test-${crypto.randomUUID()}.log`;
setLoggerOverride({ level: "trace", file: logPath });
let capturedOnMessage:
@@ -46,7 +46,7 @@ const rmDirWithRetries = async (dir: string): Promise<void> => {
beforeEach(async () => {
resetInboundDedupe();
previousHome = process.env.HOME;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-web-home-"));
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-home-"));
process.env.HOME = tempHome;
});
@@ -61,7 +61,7 @@ afterEach(async () => {
const _makeSessionStore = async (
entries: Record<string, unknown> = {},
): Promise<{ storePath: string; cleanup: () => Promise<void> }> => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-session-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-"));
const storePath = path.join(dir, "sessions.json");
await fs.writeFile(storePath, JSON.stringify(entries));
const cleanup = async () => {
@@ -200,7 +200,7 @@ describe("web auto-reply", () => {
groups: { "*": { requireMention: false } },
},
},
messages: { groupChat: { mentionPatterns: ["@clawd"] } },
messages: { groupChat: { mentionPatterns: ["@openclaw"] } },
}));
let capturedOnMessage:
@@ -248,7 +248,7 @@ describe("web auto-reply", () => {
groups: { "999@g.us": { requireMention: false } },
},
},
messages: { groupChat: { mentionPatterns: ["@clawd"] } },
messages: { groupChat: { mentionPatterns: ["@openclaw"] } },
}));
let capturedOnMessage:
@@ -265,7 +265,7 @@ describe("web auto-reply", () => {
expect(capturedOnMessage).toBeDefined();
await capturedOnMessage?.({
body: "@clawd hello",
body: "@openclaw hello",
from: "123@g.us",
conversationId: "123@g.us",
chatId: "123@g.us",
@@ -301,7 +301,7 @@ describe("web auto-reply", () => {
},
},
},
messages: { groupChat: { mentionPatterns: ["@clawd"] } },
messages: { groupChat: { mentionPatterns: ["@openclaw"] } },
}));
let capturedOnMessage:
+3 -3
View File
@@ -19,11 +19,11 @@ const makeMsg = (overrides: Partial<WebInboundMsg>): WebInboundMsg =>
}) as WebInboundMsg;
describe("isBotMentionedFromTargets", () => {
const mentionCfg = { mentionRegexes: [/\bclawd\b/i] };
const mentionCfg = { mentionRegexes: [/\bopenclaw\b/i] };
it("ignores regex matches when other mentions are present", () => {
const msg = makeMsg({
body: "@Clawd please help",
body: "@OpenClaw please help",
mentionedJids: ["19998887777@s.whatsapp.net"],
selfE164: "+15551234567",
selfJid: "15551234567@s.whatsapp.net",
@@ -45,7 +45,7 @@ describe("isBotMentionedFromTargets", () => {
it("falls back to regex when no mentions are present", () => {
const msg = makeMsg({
body: "clawd can you help?",
body: "openclaw can you help?",
selfE164: "+15551234567",
selfJid: "15551234567@s.whatsapp.net",
});
+1 -1
View File
@@ -376,7 +376,7 @@ export async function monitorWebChannel(
if (loggedOut) {
runtime.error(
`WhatsApp session logged out. Run \`${formatCliCommand("moltbot channels login --channel web")}\` to relink.`,
`WhatsApp session logged out. Run \`${formatCliCommand("openclaw channels login --channel web")}\` to relink.`,
);
await closeListener();
break;
@@ -9,7 +9,7 @@ const baseConfig = {
groups: { "*": { requireMention: true } },
},
},
session: { store: "/tmp/moltbot-sessions.json" },
session: { store: "/tmp/openclaw-sessions.json" },
} as const;
describe("applyGroupGating", () => {
@@ -6,7 +6,7 @@ describe("buildInboundLine", () => {
it("prefixes group messages with sender", () => {
const line = buildInboundLine({
cfg: {
agents: { defaults: { workspace: "/tmp/clawd" } },
agents: { defaults: { workspace: "/tmp/openclaw" } },
channels: { whatsapp: { messagePrefix: "" } },
} as never,
agentId: "main",
@@ -252,7 +252,7 @@ export async function processMessage(params: {
const responsePrefix =
prefixContext.responsePrefix ??
(configuredResponsePrefix === undefined && isSelfChat
? (resolveIdentityNamePrefix(params.cfg, params.route.agentId) ?? "[moltbot]")
? (resolveIdentityNamePrefix(params.cfg, params.route.agentId) ?? "[openclaw]")
: undefined);
const ctxPayload = finalizeInboundContext({
+1 -1
View File
@@ -12,7 +12,7 @@ describe("getSessionSnapshot", () => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 0, 18, 5, 0, 0));
try {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-snapshot-"));
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-snapshot-"));
const storePath = path.join(root, "sessions.json");
const sessionKey = "agent:main:whatsapp:dm:s1";
+1 -1
View File
@@ -43,7 +43,7 @@ vi.mock("../media/store.js", async (importOriginal) => {
};
});
const HOME = path.join(os.tmpdir(), `moltbot-inbound-media-${crypto.randomUUID()}`);
const HOME = path.join(os.tmpdir(), `openclaw-inbound-media-${crypto.randomUUID()}`);
process.env.HOME = HOME;
vi.mock("@whiskeysockets/baileys", async () => {
+1 -1
View File
@@ -57,7 +57,7 @@ export async function loginWeb(
});
console.error(
danger(
`WhatsApp reported the session is logged out. Cleared cached web session; please rerun ${formatCliCommand("moltbot channels login")} and scan the QR again.`,
`WhatsApp reported the session is logged out. Cleared cached web session; please rerun ${formatCliCommand("openclaw channels login")} and scan the QR again.`,
),
);
throw new Error("Session logged out; cache cleared. Re-run login.");
+1 -1
View File
@@ -13,7 +13,7 @@ const tmpFiles: string[] = [];
async function writeTempFile(buffer: Buffer, ext: string): Promise<string> {
const file = path.join(
os.tmpdir(),
`moltbot-media-${Date.now()}-${Math.random().toString(16).slice(2)}${ext}`,
`openclaw-media-${Date.now()}-${Math.random().toString(16).slice(2)}${ext}`,
);
tmpFiles.push(file);
await fs.writeFile(file, buffer);
@@ -88,7 +88,7 @@ describe("web monitor inbox", () => {
created: true,
});
resetWebInboundDedupe();
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-"));
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-"));
});
afterEach(() => {
@@ -88,7 +88,7 @@ describe("web monitor inbox", () => {
created: true,
});
resetWebInboundDedupe();
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-"));
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-"));
});
afterEach(() => {
@@ -88,7 +88,7 @@ describe("web monitor inbox", () => {
created: true,
});
resetWebInboundDedupe();
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-"));
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-"));
});
afterEach(() => {
@@ -171,7 +171,7 @@ describe("web monitor inbox", () => {
});
it("logs inbound bodies to file", async () => {
const logPath = path.join(os.tmpdir(), `moltbot-log-test-${crypto.randomUUID()}.log`);
const logPath = path.join(os.tmpdir(), `openclaw-log-test-${crypto.randomUUID()}.log`);
setLoggerOverride({ level: "trace", file: logPath });
const onMessage = vi.fn();
@@ -87,7 +87,7 @@ describe("web monitor inbox", () => {
created: true,
});
resetWebInboundDedupe();
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "moltbot-auth-"));
authDir = fsSync.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-"));
});
afterEach(() => {
+1 -1
View File
@@ -7,7 +7,7 @@ import { renderQrPngBase64 } from "./qr-image.js";
describe("renderQrPngBase64", () => {
it("renders a PNG data payload", async () => {
const b64 = await renderQrPngBase64("moltbot");
const b64 = await renderQrPngBase64("openclaw");
const buf = Buffer.from(b64, "base64");
expect(buf.subarray(0, 8).toString("hex")).toBe("89504e470d0a1a0a");
});
+2 -2
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import {
computeBackoff,
DEFAULT_HEARTBEAT_SECONDS,
@@ -11,7 +11,7 @@ import {
} from "./reconnect.js";
describe("web reconnect helpers", () => {
const cfg: MoltbotConfig = {};
const cfg: OpenClawConfig = {};
it("resolves sane reconnect defaults with clamps", () => {
const policy = resolveReconnectPolicy(cfg, {
+3 -3
View File
@@ -1,6 +1,6 @@
import { randomUUID } from "node:crypto";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { BackoffPolicy } from "../infra/backoff.js";
import { computeBackoff, sleepWithAbort } from "../infra/backoff.js";
@@ -19,14 +19,14 @@ export const DEFAULT_RECONNECT_POLICY: ReconnectPolicy = {
const clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val));
export function resolveHeartbeatSeconds(cfg: MoltbotConfig, overrideSeconds?: number): number {
export function resolveHeartbeatSeconds(cfg: OpenClawConfig, overrideSeconds?: number): number {
const candidate = overrideSeconds ?? cfg.web?.heartbeatSeconds;
if (typeof candidate === "number" && candidate > 0) return candidate;
return DEFAULT_HEARTBEAT_SECONDS;
}
export function resolveReconnectPolicy(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
overrides?: Partial<ReconnectPolicy>,
): ReconnectPolicy {
const reconnectOverrides = cfg.web?.reconnect ?? {};
+3 -3
View File
@@ -106,7 +106,7 @@ describe("web session", () => {
});
it("does not clobber creds backup when creds.json is corrupted", async () => {
const credsSuffix = path.join(".clawdbot", "credentials", "whatsapp", "default", "creds.json");
const credsSuffix = path.join(".openclaw", "credentials", "whatsapp", "default", "creds.json");
const copySpy = vi.spyOn(fsSync, "copyFileSync").mockImplementation(() => {});
const existsSpy = vi.spyOn(fsSync, "existsSync").mockImplementation((p) => {
@@ -182,9 +182,9 @@ describe("web session", () => {
});
it("rotates creds backup when creds.json is valid JSON", async () => {
const credsSuffix = path.join(".clawdbot", "credentials", "whatsapp", "default", "creds.json");
const credsSuffix = path.join(".openclaw", "credentials", "whatsapp", "default", "creds.json");
const backupSuffix = path.join(
".clawdbot",
".openclaw",
"credentials",
"whatsapp",
"default",
+2 -2
View File
@@ -114,7 +114,7 @@ export async function createWaSocket(
version,
logger,
printQRInTerminal: false,
browser: ["moltbot", "cli", VERSION],
browser: ["openclaw", "cli", VERSION],
syncFullHistory: false,
markOnlineOnConnect: false,
});
@@ -137,7 +137,7 @@ export async function createWaSocket(
if (status === DisconnectReason.loggedOut) {
console.error(
danger(
`WhatsApp session logged out. Run: ${formatCliCommand("moltbot channels login")}`,
`WhatsApp session logged out. Run: ${formatCliCommand("openclaw channels login")}`,
),
);
}
+4 -4
View File
@@ -4,7 +4,7 @@ import type { MockBaileysSocket } from "../../test/mocks/baileys.js";
import { createMockBaileys } from "../../test/mocks/baileys.js";
// Use globalThis to store the mock config so it survives vi.mock hoisting
const CONFIG_KEY = Symbol.for("moltbot:testConfigMock");
const CONFIG_KEY = Symbol.for("openclaw:testConfigMock");
const DEFAULT_CONFIG = {
channels: {
whatsapp: {
@@ -54,7 +54,7 @@ vi.mock("../media/store.js", () => ({
vi.mock("@whiskeysockets/baileys", () => {
const created = createMockBaileys();
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("moltbot:lastSocket")] =
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw:lastSocket")] =
created.lastSocket;
return created.mod;
});
@@ -74,7 +74,7 @@ export const baileys =
export function resetBaileysMocks() {
const recreated = createMockBaileys();
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("moltbot:lastSocket")] =
(globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw:lastSocket")] =
recreated.lastSocket;
baileys.makeWASocket.mockImplementation(recreated.mod.makeWASocket);
baileys.useMultiFileAuthState.mockImplementation(recreated.mod.useMultiFileAuthState);
@@ -83,7 +83,7 @@ export function resetBaileysMocks() {
}
export function getLastSocket(): MockBaileysSocket {
const getter = (globalThis as Record<PropertyKey, unknown>)[Symbol.for("moltbot:lastSocket")];
const getter = (globalThis as Record<PropertyKey, unknown>)[Symbol.for("openclaw:lastSocket")];
if (typeof getter === "function") return (getter as () => MockBaileysSocket)();
if (!getter) throw new Error("Baileys mock not initialized");
throw new Error("Invalid Baileys socket getter");