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
+6 -6
View File
@@ -1,11 +1,11 @@
import { describe, expect, it } from "vitest";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { DEFAULT_ASSISTANT_IDENTITY, resolveAssistantIdentity } from "./assistant-identity.js";
describe("resolveAssistantIdentity avatar normalization", () => {
it("drops sentence-like avatar placeholders", () => {
const cfg: MoltbotConfig = {
const cfg: OpenClawConfig = {
ui: {
assistant: {
avatar: "workspace-relative path, http(s) URL, or data URI",
@@ -19,7 +19,7 @@ describe("resolveAssistantIdentity avatar normalization", () => {
});
it("keeps short text avatars", () => {
const cfg: MoltbotConfig = {
const cfg: OpenClawConfig = {
ui: {
assistant: {
avatar: "PS",
@@ -31,14 +31,14 @@ describe("resolveAssistantIdentity avatar normalization", () => {
});
it("keeps path avatars", () => {
const cfg: MoltbotConfig = {
const cfg: OpenClawConfig = {
ui: {
assistant: {
avatar: "avatars/clawd.png",
avatar: "avatars/openclaw.png",
},
},
};
expect(resolveAssistantIdentity({ cfg, workspaceDir: "" }).avatar).toBe("avatars/clawd.png");
expect(resolveAssistantIdentity({ cfg, workspaceDir: "" }).avatar).toBe("avatars/openclaw.png");
});
});
+2 -2
View File
@@ -1,7 +1,7 @@
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { resolveAgentIdentity } from "../agents/identity.js";
import { loadAgentIdentity } from "../commands/agents.config.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeAgentId } from "../routing/session-key.js";
const MAX_ASSISTANT_NAME = 50;
@@ -47,7 +47,7 @@ function normalizeAvatarValue(value: string | undefined): string | undefined {
}
export function resolveAssistantIdentity(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
agentId?: string | null;
workspaceDir?: string | null;
}): AssistantIdentity {
+8 -3
View File
@@ -171,8 +171,13 @@ export function resolveGatewayAuth(params: {
}): ResolvedGatewayAuth {
const authConfig = params.authConfig ?? {};
const env = params.env ?? process.env;
const token = authConfig.token ?? env.CLAWDBOT_GATEWAY_TOKEN ?? undefined;
const password = authConfig.password ?? env.CLAWDBOT_GATEWAY_PASSWORD ?? undefined;
const token =
authConfig.token ?? env.OPENCLAW_GATEWAY_TOKEN ?? env.CLAWDBOT_GATEWAY_TOKEN ?? undefined;
const password =
authConfig.password ??
env.OPENCLAW_GATEWAY_PASSWORD ??
env.CLAWDBOT_GATEWAY_PASSWORD ??
undefined;
const mode: ResolvedGatewayAuth["mode"] = authConfig.mode ?? (password ? "password" : "token");
const allowTailscale =
authConfig.allowTailscale ?? (params.tailscaleMode === "serve" && mode !== "password");
@@ -188,7 +193,7 @@ export function assertGatewayAuthConfigured(auth: ResolvedGatewayAuth): void {
if (auth.mode === "token" && !auth.token) {
if (auth.allowTailscale) return;
throw new Error(
"gateway auth mode is token, but no token was configured (set gateway.auth.token or CLAWDBOT_GATEWAY_TOKEN)",
"gateway auth mode is token, but no token was configured (set gateway.auth.token or OPENCLAW_GATEWAY_TOKEN)",
);
}
if (auth.mode === "password" && !auth.password) {
+3 -3
View File
@@ -26,7 +26,7 @@ describe("runBootOnce", () => {
});
it("skips when BOOT.md is missing", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-boot-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-boot-"));
await expect(runBootOnce({ cfg: {}, deps: makeDeps(), workspaceDir })).resolves.toEqual({
status: "skipped",
reason: "missing",
@@ -36,7 +36,7 @@ describe("runBootOnce", () => {
});
it("skips when BOOT.md is empty", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-boot-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-boot-"));
await fs.writeFile(path.join(workspaceDir, "BOOT.md"), " \n", "utf-8");
await expect(runBootOnce({ cfg: {}, deps: makeDeps(), workspaceDir })).resolves.toEqual({
status: "skipped",
@@ -47,7 +47,7 @@ describe("runBootOnce", () => {
});
it("runs agent command when BOOT.md exists", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-boot-"));
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-boot-"));
const content = "Say hello when you wake up.";
await fs.writeFile(path.join(workspaceDir, "BOOT.md"), content, "utf-8");
+2 -2
View File
@@ -3,7 +3,7 @@ import path from "node:path";
import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import type { CliDeps } from "../cli/deps.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveMainSessionKey } from "../config/sessions/main-session.js";
import { agentCommand } from "../commands/agent.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
@@ -48,7 +48,7 @@ async function loadBootFile(
}
export async function runBootOnce(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
deps: CliDeps;
workspaceDir: string;
}): Promise<BootRunResult> {
+11 -11
View File
@@ -254,7 +254,7 @@ describe("callGateway error details", () => {
});
describe("callGateway password resolution", () => {
const originalEnvPassword = process.env.CLAWDBOT_GATEWAY_PASSWORD;
const originalEnvPassword = process.env.OPENCLAW_GATEWAY_PASSWORD;
beforeEach(() => {
loadConfig.mockReset();
@@ -264,16 +264,16 @@ describe("callGateway password resolution", () => {
startMode = "hello";
closeCode = 1006;
closeReason = "";
delete process.env.CLAWDBOT_GATEWAY_PASSWORD;
delete process.env.OPENCLAW_GATEWAY_PASSWORD;
resolveGatewayPort.mockReturnValue(18789);
pickPrimaryTailnetIPv4.mockReturnValue(undefined);
});
afterEach(() => {
if (originalEnvPassword == null) {
delete process.env.CLAWDBOT_GATEWAY_PASSWORD;
delete process.env.OPENCLAW_GATEWAY_PASSWORD;
} else {
process.env.CLAWDBOT_GATEWAY_PASSWORD = originalEnvPassword;
process.env.OPENCLAW_GATEWAY_PASSWORD = originalEnvPassword;
}
});
@@ -292,7 +292,7 @@ describe("callGateway password resolution", () => {
});
it("prefers env password over local config password", async () => {
process.env.CLAWDBOT_GATEWAY_PASSWORD = "from-env";
process.env.OPENCLAW_GATEWAY_PASSWORD = "from-env";
loadConfig.mockReturnValue({
gateway: {
mode: "local",
@@ -321,7 +321,7 @@ describe("callGateway password resolution", () => {
});
it("prefers env password over remote password in remote mode", async () => {
process.env.CLAWDBOT_GATEWAY_PASSWORD = "from-env";
process.env.OPENCLAW_GATEWAY_PASSWORD = "from-env";
loadConfig.mockReturnValue({
gateway: {
mode: "remote",
@@ -337,7 +337,7 @@ describe("callGateway password resolution", () => {
});
describe("callGateway token resolution", () => {
const originalEnvToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
const originalEnvToken = process.env.OPENCLAW_GATEWAY_TOKEN;
beforeEach(() => {
loadConfig.mockReset();
@@ -347,21 +347,21 @@ describe("callGateway token resolution", () => {
startMode = "hello";
closeCode = 1006;
closeReason = "";
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
resolveGatewayPort.mockReturnValue(18789);
pickPrimaryTailnetIPv4.mockReturnValue(undefined);
});
afterEach(() => {
if (originalEnvToken == null) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = originalEnvToken;
process.env.OPENCLAW_GATEWAY_TOKEN = originalEnvToken;
}
});
it("uses remote token when remote mode uses url override", async () => {
process.env.CLAWDBOT_GATEWAY_TOKEN = "env-token";
process.env.OPENCLAW_GATEWAY_TOKEN = "env-token";
loadConfig.mockReturnValue({
gateway: {
mode: "remote",
+6 -4
View File
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import {
loadConfig,
resolveConfigPath,
@@ -23,7 +23,7 @@ export type CallGatewayOptions = {
token?: string;
password?: string;
tlsFingerprint?: string;
config?: MoltbotConfig;
config?: OpenClawConfig;
method: string;
params?: unknown;
expectFinal?: boolean;
@@ -52,7 +52,7 @@ export type GatewayConnectionDetails = {
};
export function buildGatewayConnectionDetails(
options: { config?: MoltbotConfig; url?: string; configPath?: string } = {},
options: { config?: OpenClawConfig; url?: string; configPath?: string } = {},
): GatewayConnectionDetails {
const config = options.config ?? loadConfig();
const configPath =
@@ -158,7 +158,8 @@ export async function callGateway<T = unknown>(opts: CallGatewayOptions): Promis
? typeof remote?.token === "string" && remote.token.trim().length > 0
? remote.token.trim()
: undefined
: process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() ||
: process.env.OPENCLAW_GATEWAY_TOKEN?.trim() ||
process.env.CLAWDBOT_GATEWAY_TOKEN?.trim() ||
(typeof authToken === "string" && authToken.trim().length > 0
? authToken.trim()
: undefined));
@@ -166,6 +167,7 @@ export async function callGateway<T = unknown>(opts: CallGatewayOptions): Promis
(typeof opts.password === "string" && opts.password.trim().length > 0
? opts.password.trim()
: undefined) ||
process.env.OPENCLAW_GATEWAY_PASSWORD?.trim() ||
process.env.CLAWDBOT_GATEWAY_PASSWORD?.trim() ||
(isRemoteMode
? typeof remote?.password === "string" && remote.password.trim().length > 0
+5 -5
View File
@@ -1,7 +1,7 @@
import chokidar from "chokidar";
import { type ChannelId, listChannelPlugins } from "../channels/plugins/index.js";
import { getActivePluginRegistry } from "../plugins/runtime.js";
import type { MoltbotConfig, ConfigFileSnapshot, GatewayReloadMode } from "../config/config.js";
import type { OpenClawConfig, ConfigFileSnapshot, GatewayReloadMode } from "../config/config.js";
export type GatewayReloadSettings = {
mode: GatewayReloadMode;
@@ -156,7 +156,7 @@ export function diffConfigPaths(prev: unknown, next: unknown, prefix = ""): stri
return [prefix || "<root>"];
}
export function resolveGatewayReloadSettings(cfg: MoltbotConfig): GatewayReloadSettings {
export function resolveGatewayReloadSettings(cfg: OpenClawConfig): GatewayReloadSettings {
const rawMode = cfg.gateway?.reload?.mode;
const mode =
rawMode === "off" || rawMode === "restart" || rawMode === "hot" || rawMode === "hybrid"
@@ -246,10 +246,10 @@ export type GatewayConfigReloader = {
};
export function startGatewayConfigReloader(opts: {
initialConfig: MoltbotConfig;
initialConfig: OpenClawConfig;
readSnapshot: () => Promise<ConfigFileSnapshot>;
onHotReload: (plan: GatewayReloadPlan, nextConfig: MoltbotConfig) => Promise<void>;
onRestart: (plan: GatewayReloadPlan, nextConfig: MoltbotConfig) => void;
onHotReload: (plan: GatewayReloadPlan, nextConfig: OpenClawConfig) => Promise<void>;
onRestart: (plan: GatewayReloadPlan, nextConfig: OpenClawConfig) => void;
log: {
info: (msg: string) => void;
warn: (msg: string) => void;
+7 -7
View File
@@ -3,7 +3,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { DEFAULT_ASSISTANT_IDENTITY, resolveAssistantIdentity } from "./assistant-identity.js";
import {
buildControlUiAvatarUrl,
@@ -16,7 +16,7 @@ const ROOT_PREFIX = "/";
export type ControlUiRequestOptions = {
basePath?: string;
config?: MoltbotConfig;
config?: OpenClawConfig;
agentId?: string;
};
@@ -176,16 +176,16 @@ function injectControlUiConfig(html: string, opts: ControlUiInjectionOpts): stri
const { basePath, assistantName, assistantAvatar } = opts;
const script =
`<script>` +
`window.__CLAWDBOT_CONTROL_UI_BASE_PATH__=${JSON.stringify(basePath)};` +
`window.__CLAWDBOT_ASSISTANT_NAME__=${JSON.stringify(
`window.__OPENCLAW_CONTROL_UI_BASE_PATH__=${JSON.stringify(basePath)};` +
`window.__OPENCLAW_ASSISTANT_NAME__=${JSON.stringify(
assistantName ?? DEFAULT_ASSISTANT_IDENTITY.name,
)};` +
`window.__CLAWDBOT_ASSISTANT_AVATAR__=${JSON.stringify(
`window.__OPENCLAW_ASSISTANT_AVATAR__=${JSON.stringify(
assistantAvatar ?? DEFAULT_ASSISTANT_IDENTITY.avatar,
)};` +
`</script>`;
// Check if already injected
if (html.includes("__CLAWDBOT_ASSISTANT_NAME__")) return html;
if (html.includes("__OPENCLAW_ASSISTANT_NAME__")) return html;
const headClose = html.indexOf("</head>");
if (headClose !== -1) {
return `${html.slice(0, headClose)}${script}${html.slice(headClose)}`;
@@ -195,7 +195,7 @@ function injectControlUiConfig(html: string, opts: ControlUiInjectionOpts): stri
interface ServeIndexHtmlOpts {
basePath: string;
config?: MoltbotConfig;
config?: OpenClawConfig;
agentId?: string;
}
+44 -44
View File
@@ -12,10 +12,10 @@ import { GatewayClient } from "./client.js";
import { renderCatNoncePngBase64 } from "./live-image-probe.js";
import { startGatewayServer } from "./server.js";
const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.CLAWDBOT_LIVE_TEST);
const CLI_LIVE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND);
const CLI_IMAGE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_PROBE);
const CLI_RESUME = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_CLI_BACKEND_RESUME_PROBE);
const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST);
const CLI_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND);
const CLI_IMAGE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE);
const CLI_RESUME = isTruthyEnvValue(process.env.OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE);
const describeLive = LIVE && CLI_LIVE ? describe : describe.skip;
const DEFAULT_MODEL = "claude-cli/claude-sonnet-4-5";
@@ -94,7 +94,7 @@ function parseImageMode(raw?: string): "list" | "repeat" | undefined {
const trimmed = raw?.trim();
if (!trimmed) return undefined;
if (trimmed === "list" || trimmed === "repeat") return trimmed;
throw new Error("CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE must be 'list' or 'repeat'.");
throw new Error("OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE must be 'list' or 'repeat'.");
}
function withMcpConfigOverrides(args: string[], mcpConfigPath: string): string[] {
@@ -181,31 +181,31 @@ async function connectClient(params: { url: string; token: string }) {
describeLive("gateway live (cli backend)", () => {
it("runs the agent pipeline against the local CLI backend", async () => {
const previous = {
configPath: process.env.CLAWDBOT_CONFIG_PATH,
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
configPath: process.env.OPENCLAW_CONFIG_PATH,
token: process.env.OPENCLAW_GATEWAY_TOKEN,
skipChannels: process.env.OPENCLAW_SKIP_CHANNELS,
skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER,
skipCron: process.env.OPENCLAW_SKIP_CRON,
skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
anthropicApiKeyOld: process.env.ANTHROPIC_API_KEY_OLD,
};
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
delete process.env.ANTHROPIC_API_KEY;
delete process.env.ANTHROPIC_API_KEY_OLD;
const token = `test-${randomUUID()}`;
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
process.env.OPENCLAW_GATEWAY_TOKEN = token;
const rawModel = process.env.CLAWDBOT_LIVE_CLI_BACKEND_MODEL ?? DEFAULT_MODEL;
const rawModel = process.env.OPENCLAW_LIVE_CLI_BACKEND_MODEL ?? DEFAULT_MODEL;
const parsed = parseModelRef(rawModel, "claude-cli");
if (!parsed) {
throw new Error(
`CLAWDBOT_LIVE_CLI_BACKEND_MODEL must resolve to a CLI backend model. Got: ${rawModel}`,
`OPENCLAW_LIVE_CLI_BACKEND_MODEL must resolve to a CLI backend model. Got: ${rawModel}`,
);
}
const providerId = parsed.provider;
@@ -218,36 +218,36 @@ describeLive("gateway live (cli backend)", () => {
? { command: "codex", args: DEFAULT_CODEX_ARGS }
: null;
const cliCommand = process.env.CLAWDBOT_LIVE_CLI_BACKEND_COMMAND ?? providerDefaults?.command;
const cliCommand = process.env.OPENCLAW_LIVE_CLI_BACKEND_COMMAND ?? providerDefaults?.command;
if (!cliCommand) {
throw new Error(
`CLAWDBOT_LIVE_CLI_BACKEND_COMMAND is required for provider "${providerId}".`,
`OPENCLAW_LIVE_CLI_BACKEND_COMMAND is required for provider "${providerId}".`,
);
}
const baseCliArgs =
parseJsonStringArray(
"CLAWDBOT_LIVE_CLI_BACKEND_ARGS",
process.env.CLAWDBOT_LIVE_CLI_BACKEND_ARGS,
"OPENCLAW_LIVE_CLI_BACKEND_ARGS",
process.env.OPENCLAW_LIVE_CLI_BACKEND_ARGS,
) ?? providerDefaults?.args;
if (!baseCliArgs || baseCliArgs.length === 0) {
throw new Error(`CLAWDBOT_LIVE_CLI_BACKEND_ARGS is required for provider "${providerId}".`);
throw new Error(`OPENCLAW_LIVE_CLI_BACKEND_ARGS is required for provider "${providerId}".`);
}
const cliClearEnv =
parseJsonStringArray(
"CLAWDBOT_LIVE_CLI_BACKEND_CLEAR_ENV",
process.env.CLAWDBOT_LIVE_CLI_BACKEND_CLEAR_ENV,
"OPENCLAW_LIVE_CLI_BACKEND_CLEAR_ENV",
process.env.OPENCLAW_LIVE_CLI_BACKEND_CLEAR_ENV,
) ?? (providerId === "claude-cli" ? DEFAULT_CLEAR_ENV : []);
const cliImageArg = process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_ARG?.trim() || undefined;
const cliImageMode = parseImageMode(process.env.CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE);
const cliImageArg = process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG?.trim() || undefined;
const cliImageMode = parseImageMode(process.env.OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE);
if (cliImageMode && !cliImageArg) {
throw new Error(
"CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_MODE requires CLAWDBOT_LIVE_CLI_BACKEND_IMAGE_ARG.",
"OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE requires OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG.",
);
}
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-cli-"));
const disableMcpConfig = process.env.CLAWDBOT_LIVE_CLI_BACKEND_DISABLE_MCP_CONFIG !== "0";
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-cli-"));
const disableMcpConfig = process.env.OPENCLAW_LIVE_CLI_BACKEND_DISABLE_MCP_CONFIG !== "0";
let cliArgs = baseCliArgs;
if (providerId === "claude-cli" && disableMcpConfig) {
const mcpConfigPath = path.join(tempDir, "claude-mcp.json");
@@ -281,9 +281,9 @@ describeLive("gateway live (cli backend)", () => {
},
},
};
const tempConfigPath = path.join(tempDir, "moltbot.json");
const tempConfigPath = path.join(tempDir, "openclaw.json");
await fs.writeFile(tempConfigPath, `${JSON.stringify(nextCfg, null, 2)}\n`);
process.env.CLAWDBOT_CONFIG_PATH = tempConfigPath;
process.env.OPENCLAW_CONFIG_PATH = tempConfigPath;
const port = await getFreeGatewayPort();
const server = await startGatewayServer(port, {
@@ -399,18 +399,18 @@ describeLive("gateway live (cli backend)", () => {
client.stop();
await server.close();
await fs.rm(tempDir, { recursive: true, force: true });
if (previous.configPath === undefined) delete process.env.CLAWDBOT_CONFIG_PATH;
else process.env.CLAWDBOT_CONFIG_PATH = previous.configPath;
if (previous.token === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN;
else process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token;
if (previous.skipChannels === undefined) delete process.env.CLAWDBOT_SKIP_CHANNELS;
else process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels;
if (previous.skipGmail === undefined) delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail;
if (previous.skipCron === undefined) delete process.env.CLAWDBOT_SKIP_CRON;
else process.env.CLAWDBOT_SKIP_CRON = previous.skipCron;
if (previous.skipCanvas === undefined) delete process.env.CLAWDBOT_SKIP_CANVAS_HOST;
else process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas;
if (previous.configPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH;
else process.env.OPENCLAW_CONFIG_PATH = previous.configPath;
if (previous.token === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN;
else process.env.OPENCLAW_GATEWAY_TOKEN = previous.token;
if (previous.skipChannels === undefined) delete process.env.OPENCLAW_SKIP_CHANNELS;
else process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels;
if (previous.skipGmail === undefined) delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
else process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail;
if (previous.skipCron === undefined) delete process.env.OPENCLAW_SKIP_CRON;
else process.env.OPENCLAW_SKIP_CRON = previous.skipCron;
if (previous.skipCanvas === undefined) delete process.env.OPENCLAW_SKIP_CANVAS_HOST;
else process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas;
if (previous.anthropicApiKey === undefined) delete process.env.ANTHROPIC_API_KEY;
else process.env.ANTHROPIC_API_KEY = previous.anthropicApiKey;
if (previous.anthropicApiKeyOld === undefined) delete process.env.ANTHROPIC_API_KEY_OLD;
@@ -7,7 +7,7 @@ import path from "node:path";
import type { Api, Model } from "@mariozechner/pi-ai";
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
import { describe, it } from "vitest";
import { resolveMoltbotAgentDir } from "../agents/agent-paths.js";
import { resolveOpenClawAgentDir } from "../agents/agent-paths.js";
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
import {
type AuthProfileStore,
@@ -21,9 +21,9 @@ import {
} from "../agents/live-auth-keys.js";
import { isModernModelRef } from "../agents/live-model-filter.js";
import { getApiKeyForModel } from "../agents/model-auth.js";
import { ensureMoltbotModelsJson } from "../agents/models-config.js";
import { ensureOpenClawModelsJson } from "../agents/models-config.js";
import { loadConfig } from "../config/config.js";
import type { MoltbotConfig, ModelProviderConfig } from "../config/types.js";
import type { OpenClawConfig, ModelProviderConfig } from "../config/types.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
@@ -31,10 +31,10 @@ import { GatewayClient } from "./client.js";
import { renderCatNoncePngBase64 } from "./live-image-probe.js";
import { startGatewayServer } from "./server.js";
const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.CLAWDBOT_LIVE_TEST);
const GATEWAY_LIVE = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_GATEWAY);
const ZAI_FALLBACK = isTruthyEnvValue(process.env.CLAWDBOT_LIVE_GATEWAY_ZAI_FALLBACK);
const PROVIDERS = parseFilter(process.env.CLAWDBOT_LIVE_GATEWAY_PROVIDERS);
const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST);
const GATEWAY_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY);
const ZAI_FALLBACK = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY_ZAI_FALLBACK);
const PROVIDERS = parseFilter(process.env.OPENCLAW_LIVE_GATEWAY_PROVIDERS);
const THINKING_LEVEL = "high";
const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking)\s*>/i;
const FINAL_TAG_RE = /<\s*\/?\s*final\s*>/i;
@@ -331,7 +331,7 @@ async function connectClient(params: { url: string; token: string }) {
type GatewayModelSuiteParams = {
label: string;
cfg: MoltbotConfig;
cfg: OpenClawConfig;
candidates: Array<Model<Api>>;
extraToolProbes: boolean;
extraImageProbes: boolean;
@@ -340,10 +340,10 @@ type GatewayModelSuiteParams = {
};
function buildLiveGatewayConfig(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
candidates: Array<Model<Api>>;
providerOverrides?: Record<string, ModelProviderConfig>;
}): MoltbotConfig {
}): OpenClawConfig {
const providerOverrides = params.providerOverrides ?? {};
const lmstudioProvider = params.cfg.models?.providers?.lmstudio;
const baseProviders = params.cfg.models?.providers ?? {};
@@ -382,16 +382,16 @@ function buildLiveGatewayConfig(params: {
}
function sanitizeAuthConfig(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
agentDir: string;
}): MoltbotConfig["auth"] | undefined {
}): OpenClawConfig["auth"] | undefined {
const auth = params.cfg.auth;
if (!auth) return auth;
const store = ensureAuthProfileStore(params.agentDir, {
allowKeychainPrompt: false,
});
let profiles: NonNullable<MoltbotConfig["auth"]>["profiles"] | undefined;
let profiles: NonNullable<OpenClawConfig["auth"]>["profiles"] | undefined;
if (auth.profiles) {
profiles = {};
for (const [profileId, profile] of Object.entries(auth.profiles)) {
@@ -421,7 +421,7 @@ function sanitizeAuthConfig(params: {
}
function buildMinimaxProviderOverride(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
api: "openai-completions" | "anthropic-messages";
baseUrl: string;
}): ModelProviderConfig | null {
@@ -436,29 +436,29 @@ function buildMinimaxProviderOverride(params: {
async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
const previous = {
configPath: process.env.CLAWDBOT_CONFIG_PATH,
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
agentDir: process.env.CLAWDBOT_AGENT_DIR,
configPath: process.env.OPENCLAW_CONFIG_PATH,
token: process.env.OPENCLAW_GATEWAY_TOKEN,
skipChannels: process.env.OPENCLAW_SKIP_CHANNELS,
skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER,
skipCron: process.env.OPENCLAW_SKIP_CRON,
skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST,
agentDir: process.env.OPENCLAW_AGENT_DIR,
piAgentDir: process.env.PI_CODING_AGENT_DIR,
stateDir: process.env.CLAWDBOT_STATE_DIR,
stateDir: process.env.OPENCLAW_STATE_DIR,
};
let tempAgentDir: string | undefined;
let tempStateDir: string | undefined;
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
const token = `test-${randomUUID()}`;
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
process.env.OPENCLAW_GATEWAY_TOKEN = token;
const agentId = "dev";
const hostAgentDir = resolveMoltbotAgentDir();
const hostAgentDir = resolveOpenClawAgentDir();
const hostStore = ensureAuthProfileStore(hostAgentDir, {
allowKeychainPrompt: false,
});
@@ -471,26 +471,26 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
lastGood: hostStore.lastGood ? { ...hostStore.lastGood } : undefined,
usageStats: hostStore.usageStats ? { ...hostStore.usageStats } : undefined,
};
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-state-"));
process.env.CLAWDBOT_STATE_DIR = tempStateDir;
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-state-"));
process.env.OPENCLAW_STATE_DIR = tempStateDir;
tempAgentDir = path.join(tempStateDir, "agents", DEFAULT_AGENT_ID, "agent");
saveAuthProfileStore(sanitizedStore, tempAgentDir);
const tempSessionAgentDir = path.join(tempStateDir, "agents", agentId, "agent");
if (tempSessionAgentDir !== tempAgentDir) {
saveAuthProfileStore(sanitizedStore, tempSessionAgentDir);
}
process.env.CLAWDBOT_AGENT_DIR = tempAgentDir;
process.env.OPENCLAW_AGENT_DIR = tempAgentDir;
process.env.PI_CODING_AGENT_DIR = tempAgentDir;
const workspaceDir = resolveAgentWorkspaceDir(params.cfg, agentId);
await fs.mkdir(workspaceDir, { recursive: true });
const nonceA = randomUUID();
const nonceB = randomUUID();
const toolProbePath = path.join(workspaceDir, `.clawdbot-live-tool-probe.${nonceA}.txt`);
const toolProbePath = path.join(workspaceDir, `.openclaw-live-tool-probe.${nonceA}.txt`);
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
const agentDir = resolveMoltbotAgentDir();
const sanitizedCfg: MoltbotConfig = {
const agentDir = resolveOpenClawAgentDir();
const sanitizedCfg: OpenClawConfig = {
...params.cfg,
auth: sanitizeAuthConfig({ cfg: params.cfg, agentDir }),
};
@@ -499,12 +499,12 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
candidates: params.candidates,
providerOverrides: params.providerOverrides,
});
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-live-"));
const tempConfigPath = path.join(tempDir, "moltbot.json");
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-live-"));
const tempConfigPath = path.join(tempDir, "openclaw.json");
await fs.writeFile(tempConfigPath, `${JSON.stringify(nextCfg, null, 2)}\n`);
process.env.CLAWDBOT_CONFIG_PATH = tempConfigPath;
process.env.OPENCLAW_CONFIG_PATH = tempConfigPath;
await ensureMoltbotModelsJson(nextCfg);
await ensureOpenClawModelsJson(nextCfg);
const port = await getFreeGatewayPort();
const server = await startGatewayServer(port, {
@@ -636,7 +636,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
sessionKey,
idempotencyKey: `idem-${runIdTool}-tool`,
message:
"Moltbot live tool probe (local, safe): " +
"OpenClaw live tool probe (local, safe): " +
`use the tool named \`read\` (or \`Read\`) with JSON arguments {"path":"${toolProbePath}"}. ` +
"Then reply with the two nonce values you read (include both).",
thinking: params.thinkingLevel,
@@ -676,7 +676,7 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
sessionKey,
idempotencyKey: `idem-${runIdTool}-exec-read`,
message:
"Moltbot live tool probe (local, safe): " +
"OpenClaw live tool probe (local, safe): " +
"use the tool named `exec` (or `Exec`) to run this command: " +
`mkdir -p "${tempDir}" && printf '%s' '${nonceC}' > "${toolWritePath}". ` +
`Then use the tool named \`read\` (or \`Read\`) with JSON arguments {"path":"${toolWritePath}"}. ` +
@@ -940,15 +940,15 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) {
await fs.rm(tempStateDir, { recursive: true, force: true });
}
process.env.CLAWDBOT_CONFIG_PATH = previous.configPath;
process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token;
process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels;
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail;
process.env.CLAWDBOT_SKIP_CRON = previous.skipCron;
process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas;
process.env.CLAWDBOT_AGENT_DIR = previous.agentDir;
process.env.OPENCLAW_CONFIG_PATH = previous.configPath;
process.env.OPENCLAW_GATEWAY_TOKEN = previous.token;
process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels;
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail;
process.env.OPENCLAW_SKIP_CRON = previous.skipCron;
process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas;
process.env.OPENCLAW_AGENT_DIR = previous.agentDir;
process.env.PI_CODING_AGENT_DIR = previous.piAgentDir;
process.env.CLAWDBOT_STATE_DIR = previous.stateDir;
process.env.OPENCLAW_STATE_DIR = previous.stateDir;
}
}
@@ -957,9 +957,9 @@ describeLive("gateway live (dev agent, profile keys)", () => {
"runs meaningful prompts across models with available keys",
async () => {
const cfg = loadConfig();
await ensureMoltbotModelsJson(cfg);
await ensureOpenClawModelsJson(cfg);
const agentDir = resolveMoltbotAgentDir();
const agentDir = resolveOpenClawAgentDir();
const authStore = ensureAuthProfileStore(agentDir, {
allowKeychainPrompt: false,
});
@@ -967,7 +967,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
const modelRegistry = discoverModels(authStorage, agentDir);
const all = modelRegistry.getAll() as Array<Model<Api>>;
const rawModels = process.env.CLAWDBOT_LIVE_GATEWAY_MODELS?.trim();
const rawModels = process.env.OPENCLAW_LIVE_GATEWAY_MODELS?.trim();
const useModern = !rawModels || rawModels === "modern" || rawModels === "all";
const useExplicit = Boolean(rawModels) && !useModern;
const filter = useExplicit ? parseFilter(rawModels) : null;
@@ -1044,26 +1044,26 @@ describeLive("gateway live (dev agent, profile keys)", () => {
it("z.ai fallback handles anthropic tool history", async () => {
if (!ZAI_FALLBACK) return;
const previous = {
configPath: process.env.CLAWDBOT_CONFIG_PATH,
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
configPath: process.env.OPENCLAW_CONFIG_PATH,
token: process.env.OPENCLAW_GATEWAY_TOKEN,
skipChannels: process.env.OPENCLAW_SKIP_CHANNELS,
skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER,
skipCron: process.env.OPENCLAW_SKIP_CRON,
skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST,
};
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
const token = `test-${randomUUID()}`;
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
process.env.OPENCLAW_GATEWAY_TOKEN = token;
const cfg = loadConfig();
await ensureMoltbotModelsJson(cfg);
await ensureOpenClawModelsJson(cfg);
const agentDir = resolveMoltbotAgentDir();
const agentDir = resolveOpenClawAgentDir();
const authStorage = discoverAuthStorage(agentDir);
const modelRegistry = discoverModels(authStorage, agentDir);
const anthropic = modelRegistry.find("anthropic", "claude-opus-4-5") as Model<Api> | null;
@@ -1082,7 +1082,7 @@ describeLive("gateway live (dev agent, profile keys)", () => {
await fs.mkdir(workspaceDir, { recursive: true });
const nonceA = randomUUID();
const nonceB = randomUUID();
const toolProbePath = path.join(workspaceDir, `.clawdbot-live-zai-fallback.${nonceA}.txt`);
const toolProbePath = path.join(workspaceDir, `.openclaw-live-zai-fallback.${nonceA}.txt`);
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
const port = await getFreeGatewayPort();
@@ -1173,12 +1173,12 @@ describeLive("gateway live (dev agent, profile keys)", () => {
await server.close({ reason: "live test complete" });
await fs.rm(toolProbePath, { force: true });
process.env.CLAWDBOT_CONFIG_PATH = previous.configPath;
process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token;
process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels;
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail;
process.env.CLAWDBOT_SKIP_CRON = previous.skipCron;
process.env.CLAWDBOT_SKIP_CANVAS_HOST = previous.skipCanvas;
process.env.OPENCLAW_CONFIG_PATH = previous.configPath;
process.env.OPENCLAW_GATEWAY_TOKEN = previous.token;
process.env.OPENCLAW_SKIP_CHANNELS = previous.skipChannels;
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previous.skipGmail;
process.env.OPENCLAW_SKIP_CRON = previous.skipCron;
process.env.OPENCLAW_SKIP_CANVAS_HOST = previous.skipCanvas;
}
}, 180_000);
});
+51 -51
View File
@@ -29,39 +29,39 @@ describe("gateway e2e", () => {
async () => {
const prev = {
home: process.env.HOME,
configPath: process.env.CLAWDBOT_CONFIG_PATH,
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
skipBrowser: process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER,
configPath: process.env.OPENCLAW_CONFIG_PATH,
token: process.env.OPENCLAW_GATEWAY_TOKEN,
skipChannels: process.env.OPENCLAW_SKIP_CHANNELS,
skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER,
skipCron: process.env.OPENCLAW_SKIP_CRON,
skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST,
skipBrowser: process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER,
};
const { baseUrl: openaiBaseUrl, restore } = installOpenAiResponsesMock();
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-mock-home-"));
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-mock-home-"));
process.env.HOME = tempHome;
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1";
const token = `test-${randomUUID()}`;
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
process.env.OPENCLAW_GATEWAY_TOKEN = token;
const workspaceDir = path.join(tempHome, "clawd");
const workspaceDir = path.join(tempHome, "openclaw");
await fs.mkdir(workspaceDir, { recursive: true });
const nonceA = randomUUID();
const nonceB = randomUUID();
const toolProbePath = path.join(workspaceDir, `.clawdbot-tool-probe.${nonceA}.txt`);
const toolProbePath = path.join(workspaceDir, `.openclaw-tool-probe.${nonceA}.txt`);
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
const configDir = path.join(tempHome, ".clawdbot");
const configDir = path.join(tempHome, ".openclaw");
await fs.mkdir(configDir, { recursive: true });
const configPath = path.join(configDir, "moltbot.json");
const configPath = path.join(configDir, "openclaw.json");
const cfg = {
agents: { defaults: { workspace: workspaceDir } },
@@ -91,7 +91,7 @@ describe("gateway e2e", () => {
};
await fs.writeFile(configPath, `${JSON.stringify(cfg, null, 2)}\n`);
process.env.CLAWDBOT_CONFIG_PATH = configPath;
process.env.OPENCLAW_CONFIG_PATH = configPath;
const port = await getFreeGatewayPort();
const server = await startGatewayServer(port, {
@@ -141,13 +141,13 @@ describe("gateway e2e", () => {
await fs.rm(tempHome, { recursive: true, force: true });
restore();
process.env.HOME = prev.home;
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser;
process.env.OPENCLAW_CONFIG_PATH = prev.configPath;
process.env.OPENCLAW_GATEWAY_TOKEN = prev.token;
process.env.OPENCLAW_SKIP_CHANNELS = prev.skipChannels;
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prev.skipGmail;
process.env.OPENCLAW_SKIP_CRON = prev.skipCron;
process.env.OPENCLAW_SKIP_CANVAS_HOST = prev.skipCanvas;
process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser;
}
},
);
@@ -155,27 +155,27 @@ describe("gateway e2e", () => {
it("runs wizard over ws and writes auth token config", { timeout: 90_000 }, async () => {
const prev = {
home: process.env.HOME,
stateDir: process.env.CLAWDBOT_STATE_DIR,
configPath: process.env.CLAWDBOT_CONFIG_PATH,
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
skipCron: process.env.CLAWDBOT_SKIP_CRON,
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
skipBrowser: process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER,
stateDir: process.env.OPENCLAW_STATE_DIR,
configPath: process.env.OPENCLAW_CONFIG_PATH,
token: process.env.OPENCLAW_GATEWAY_TOKEN,
skipChannels: process.env.OPENCLAW_SKIP_CHANNELS,
skipGmail: process.env.OPENCLAW_SKIP_GMAIL_WATCHER,
skipCron: process.env.OPENCLAW_SKIP_CRON,
skipCanvas: process.env.OPENCLAW_SKIP_CANVAS_HOST,
skipBrowser: process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER,
};
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1";
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1";
delete process.env.OPENCLAW_GATEWAY_TOKEN;
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-wizard-home-"));
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-wizard-home-"));
process.env.HOME = tempHome;
delete process.env.CLAWDBOT_STATE_DIR;
delete process.env.CLAWDBOT_CONFIG_PATH;
delete process.env.OPENCLAW_STATE_DIR;
delete process.env.OPENCLAW_CONFIG_PATH;
const wizardToken = `wiz-${randomUUID()}`;
const port = await getFreeGatewayPort();
@@ -263,14 +263,14 @@ describe("gateway e2e", () => {
await server2.close({ reason: "wizard auth verify" });
await fs.rm(tempHome, { recursive: true, force: true });
process.env.HOME = prev.home;
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser;
process.env.OPENCLAW_STATE_DIR = prev.stateDir;
process.env.OPENCLAW_CONFIG_PATH = prev.configPath;
process.env.OPENCLAW_GATEWAY_TOKEN = prev.token;
process.env.OPENCLAW_SKIP_CHANNELS = prev.skipChannels;
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prev.skipGmail;
process.env.OPENCLAW_SKIP_CRON = prev.skipCron;
process.env.OPENCLAW_SKIP_CANVAS_HOST = prev.skipCanvas;
process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = prev.skipBrowser;
}
});
});
+2 -2
View File
@@ -63,7 +63,7 @@ describe("hooks mapping", () => {
});
it("runs transform module", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-hooks-"));
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-hooks-"));
const modPath = path.join(dir, "transform.mjs");
const placeholder = "${" + "payload.name}";
fs.writeFileSync(
@@ -99,7 +99,7 @@ describe("hooks mapping", () => {
});
it("treats null transform as a handled skip", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-hooks-skip-"));
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-hooks-skip-"));
const modPath = path.join(dir, "transform.mjs");
fs.writeFileSync(modPath, "export default () => null;");
+5 -5
View File
@@ -1,6 +1,6 @@
import type { IncomingMessage } from "node:http";
import { afterEach, beforeEach, describe, expect, test } from "vitest";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { ChannelPlugin } from "../channels/plugins/types.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { createIMessageTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js";
@@ -26,7 +26,7 @@ describe("gateway hooks helpers", () => {
token: "secret",
path: "hooks///",
},
} as MoltbotConfig;
} as OpenClawConfig;
const resolved = resolveHooksConfig(base);
expect(resolved?.basePath).toBe("/hooks");
expect(resolved?.token).toBe("secret");
@@ -35,7 +35,7 @@ describe("gateway hooks helpers", () => {
test("resolveHooksConfig rejects root path", () => {
const cfg = {
hooks: { enabled: true, token: "x", path: "/" },
} as MoltbotConfig;
} as OpenClawConfig;
expect(() => resolveHooksConfig(cfg)).toThrow("hooks.path may not be '/'");
});
@@ -43,7 +43,7 @@ describe("gateway hooks helpers", () => {
const req = {
headers: {
authorization: "Bearer top",
"x-moltbot-token": "header",
"x-openclaw-token": "header",
},
} as unknown as IncomingMessage;
const url = new URL("http://localhost/hooks/wake?token=query");
@@ -52,7 +52,7 @@ describe("gateway hooks helpers", () => {
expect(result1.fromQuery).toBe(false);
const req2 = {
headers: { "x-moltbot-token": "header" },
headers: { "x-openclaw-token": "header" },
} as unknown as IncomingMessage;
const result2 = extractHookToken(req2, url);
expect(result2.token).toBe("header");
+5 -3
View File
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
import type { IncomingMessage } from "node:http";
import { listChannelPlugins } from "../channels/plugins/index.js";
import type { ChannelId } from "../channels/plugins/types.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeMessageChannel } from "../utils/message-channel.js";
import { type HookMappingResolved, resolveHookMappings } from "./hooks-mapping.js";
@@ -16,7 +16,7 @@ export type HooksConfigResolved = {
mappings: HookMappingResolved[];
};
export function resolveHooksConfig(cfg: MoltbotConfig): HooksConfigResolved | null {
export function resolveHooksConfig(cfg: OpenClawConfig): HooksConfigResolved | null {
if (cfg.hooks?.enabled !== true) return null;
const token = cfg.hooks?.token?.trim();
if (!token) {
@@ -54,7 +54,9 @@ export function extractHookToken(req: IncomingMessage, url: URL): HookTokenResul
if (token) return { token, fromQuery: false };
}
const headerToken =
typeof req.headers["x-moltbot-token"] === "string" ? req.headers["x-moltbot-token"].trim() : "";
typeof req.headers["x-openclaw-token"] === "string"
? req.headers["x-openclaw-token"].trim()
: "";
if (headerToken) return { token: headerToken, fromQuery: false };
const queryToken = url.searchParams.get("token");
if (queryToken) return { token: queryToken.trim(), fromQuery: true };
+5 -3
View File
@@ -19,7 +19,9 @@ export function getBearerToken(req: IncomingMessage): string | undefined {
export function resolveAgentIdFromHeader(req: IncomingMessage): string | undefined {
const raw =
getHeader(req, "x-moltbot-agent-id")?.trim() || getHeader(req, "x-moltbot-agent")?.trim() || "";
getHeader(req, "x-openclaw-agent-id")?.trim() ||
getHeader(req, "x-openclaw-agent")?.trim() ||
"";
if (!raw) return undefined;
return normalizeAgentId(raw);
}
@@ -29,7 +31,7 @@ export function resolveAgentIdFromModel(model: string | undefined): string | und
if (!raw) return undefined;
const m =
raw.match(/^moltbot[:/](?<agentId>[a-z0-9][a-z0-9_-]{0,63})$/i) ??
raw.match(/^openclaw[:/](?<agentId>[a-z0-9][a-z0-9_-]{0,63})$/i) ??
raw.match(/^agent:(?<agentId>[a-z0-9][a-z0-9_-]{0,63})$/i);
const agentId = m?.groups?.agentId;
if (!agentId) return undefined;
@@ -53,7 +55,7 @@ export function resolveSessionKey(params: {
user?: string | undefined;
prefix: string;
}): string {
const explicit = getHeader(params.req, "x-moltbot-session-key")?.trim();
const explicit = getHeader(params.req, "x-openclaw-session-key")?.trim();
if (explicit) return explicit;
const user = params.user?.trim();
+2 -2
View File
@@ -1,4 +1,4 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { NodeSession } from "./node-registry.js";
const CANVAS_COMMANDS = [
@@ -75,7 +75,7 @@ function normalizePlatformId(platform?: string, deviceFamily?: string): string {
}
export function resolveNodeCommandAllowlist(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
node?: Pick<NodeSession, "platform" | "deviceFamily">,
): Set<string> {
const platformId = normalizePlatformId(node?.platform, node?.deviceFamily);
+21 -21
View File
@@ -67,7 +67,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
const server = await startServerWithDefaultConfig(port);
try {
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(404);
@@ -83,7 +83,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
});
try {
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(404);
@@ -124,8 +124,8 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(
port,
{ model: "moltbot", messages: [{ role: "user", content: "hi" }] },
{ "x-moltbot-agent-id": "beta" },
{ model: "openclaw", messages: [{ role: "user", content: "hi" }] },
{ "x-openclaw-agent-id": "beta" },
);
expect(res.status).toBe(200);
@@ -140,7 +140,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
model: "moltbot:beta",
model: "openclaw:beta",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(200);
@@ -158,10 +158,10 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
const res = await postChatCompletions(
port,
{
model: "moltbot:beta",
model: "openclaw:beta",
messages: [{ role: "user", content: "hi" }],
},
{ "x-moltbot-agent-id": "alpha" },
{ "x-openclaw-agent-id": "alpha" },
);
expect(res.status).toBe(200);
@@ -177,10 +177,10 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(
port,
{ model: "moltbot", messages: [{ role: "user", content: "hi" }] },
{ model: "openclaw", messages: [{ role: "user", content: "hi" }] },
{
"x-moltbot-agent-id": "beta",
"x-moltbot-session-key": "agent:beta:openai:custom",
"x-openclaw-agent-id": "beta",
"x-openclaw-session-key": "agent:beta:openai:custom",
},
);
expect(res.status).toBe(200);
@@ -196,7 +196,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
user: "alice",
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(200);
@@ -211,7 +211,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [
{
role: "user",
@@ -232,7 +232,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "I am Claude" }]);
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Hello, who are you?" },
@@ -255,7 +255,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "Hello" },
@@ -274,7 +274,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [
{ role: "developer", content: "You are a helpful assistant." },
{ role: "user", content: "Hello" },
@@ -292,7 +292,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
mockAgentOnce([{ text: "ok" }]);
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "What's the weather?" },
@@ -316,7 +316,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const res = await postChatCompletions(port, {
stream: false,
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(200);
@@ -331,7 +331,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
{
const res = await postChatCompletions(port, {
model: "moltbot",
model: "openclaw",
messages: [{ role: "system", content: "yo" }],
});
expect(res.status).toBe(400);
@@ -359,7 +359,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
const res = await postChatCompletions(port, {
stream: true,
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(res.status).toBe(200);
@@ -392,7 +392,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
const repeatedRes = await postChatCompletions(port, {
stream: true,
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(repeatedRes.status).toBe(200);
@@ -417,7 +417,7 @@ describe("OpenAI-compatible HTTP API (e2e)", () => {
const fallbackRes = await postChatCompletions(port, {
stream: true,
model: "moltbot",
model: "openclaw",
messages: [{ role: "user", content: "hi" }],
});
expect(fallbackRes.status).toBe(200);
+3 -3
View File
@@ -181,7 +181,7 @@ export async function handleOpenAiHttpRequest(
const payload = coerceRequest(body);
const stream = Boolean(payload.stream);
const model = typeof payload.model === "string" ? payload.model : "moltbot";
const model = typeof payload.model === "string" ? payload.model : "openclaw";
const user = typeof payload.user === "string" ? payload.user : undefined;
const agentId = resolveAgentIdForRequest({ req, model });
@@ -223,7 +223,7 @@ export async function handleOpenAiHttpRequest(
.map((p) => (typeof p.text === "string" ? p.text : ""))
.filter(Boolean)
.join("\n\n")
: "No response from Moltbot.";
: "No response from OpenClaw.";
sendJson(res, 200, {
id: runId,
@@ -344,7 +344,7 @@ export async function handleOpenAiHttpRequest(
.map((p) => (typeof p.text === "string" ? p.text : ""))
.filter(Boolean)
.join("\n\n")
: "No response from Moltbot.";
: "No response from OpenClaw.";
sawAssistantDelta = true;
writeSse(res, {
+24 -24
View File
@@ -87,7 +87,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
const _server = await startServerWithDefaultConfig(port);
try {
const res = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(res.status).toBe(404);
@@ -102,7 +102,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
});
try {
const res = await postResponses(disabledPort, {
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(res.status).toBe(404);
@@ -130,7 +130,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
const resMissingAuth = await fetch(`http://127.0.0.1:${port}/v1/responses`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ model: "moltbot", input: "hi" }),
body: JSON.stringify({ model: "openclaw", input: "hi" }),
});
expect(resMissingAuth.status).toBe(401);
await ensureResponseConsumed(resMissingAuth);
@@ -146,8 +146,8 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resHeader = await postResponses(
port,
{ model: "moltbot", input: "hi" },
{ "x-moltbot-agent-id": "beta" },
{ model: "openclaw", input: "hi" },
{ "x-openclaw-agent-id": "beta" },
);
expect(resHeader.status).toBe(200);
const [optsHeader] = agentCommand.mock.calls[0] ?? [];
@@ -157,7 +157,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
await ensureResponseConsumed(resHeader);
mockAgentOnce([{ text: "hello" }]);
const resModel = await postResponses(port, { model: "moltbot:beta", input: "hi" });
const resModel = await postResponses(port, { model: "openclaw:beta", input: "hi" });
expect(resModel.status).toBe(200);
const [optsModel] = agentCommand.mock.calls[0] ?? [];
expect((optsModel as { sessionKey?: string } | undefined)?.sessionKey ?? "").toMatch(
@@ -168,7 +168,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resUser = await postResponses(port, {
user: "alice",
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resUser.status).toBe(200);
@@ -180,7 +180,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resString = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hello world",
});
expect(resString.status).toBe(200);
@@ -190,7 +190,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resArray = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [{ type: "message", role: "user", content: "hello there" }],
});
expect(resArray.status).toBe(200);
@@ -200,7 +200,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resSystemDeveloper = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [
{ type: "message", role: "system", content: "You are a helpful assistant." },
{ type: "message", role: "developer", content: "Be concise." },
@@ -218,7 +218,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resInstructions = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
instructions: "Always respond in French.",
});
@@ -231,7 +231,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "I am Claude" }]);
const resHistory = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [
{ type: "message", role: "system", content: "You are a helpful assistant." },
{ type: "message", role: "user", content: "Hello, who are you?" },
@@ -251,7 +251,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "ok" }]);
const resFunctionOutput = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [
{ type: "message", role: "user", content: "What's the weather?" },
{ type: "function_call_output", call_id: "call_1", output: "Sunny, 70F." },
@@ -266,7 +266,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "ok" }]);
const resInputFile = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [
{
type: "message",
@@ -297,7 +297,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "ok" }]);
const resToolNone = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
tools: [
{
@@ -316,7 +316,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "ok" }]);
const resToolChoice = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
tools: [
{
@@ -340,7 +340,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
await ensureResponseConsumed(resToolChoice);
const resUnknownTool = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
tools: [
{
@@ -355,7 +355,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "ok" }]);
const resMaxTokens = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: "hi",
max_output_tokens: 123,
});
@@ -374,7 +374,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
});
const resUsage = await postResponses(port, {
stream: false,
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resUsage.status).toBe(200);
@@ -385,7 +385,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
mockAgentOnce([{ text: "hello" }]);
const resShape = await postResponses(port, {
stream: false,
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resShape.status).toBe(200);
@@ -407,7 +407,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
await ensureResponseConsumed(resShape);
const resNoUser = await postResponses(port, {
model: "moltbot",
model: "openclaw",
input: [{ type: "message", role: "system", content: "yo" }],
});
expect(resNoUser.status).toBe(400);
@@ -434,7 +434,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
const resDelta = await postResponses(port, {
stream: true,
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resDelta.status).toBe(200);
@@ -470,7 +470,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
const resFallback = await postResponses(port, {
stream: true,
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resFallback.status).toBe(200);
@@ -485,7 +485,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
const resTypeMatch = await postResponses(port, {
stream: true,
model: "moltbot",
model: "openclaw",
input: "hi",
});
expect(resTypeMatch.status).toBe(200);
+4 -4
View File
@@ -1,7 +1,7 @@
/**
* OpenResponses HTTP Handler
*
* Implements the OpenResponses `/v1/responses` endpoint for Moltbot Gateway.
* Implements the OpenResponses `/v1/responses` endpoint for OpenClaw Gateway.
*
* @see https://www.open-responses.com/
*/
@@ -552,7 +552,7 @@ export async function handleOpenResponsesHttpRequest(
.map((p) => (typeof p.text === "string" ? p.text : ""))
.filter(Boolean)
.join("\n\n")
: "No response from Moltbot.";
: "No response from OpenClaw.";
const response = createResponseResource({
id: responseId,
@@ -706,7 +706,7 @@ export async function handleOpenResponsesHttpRequest(
if (evt.stream === "lifecycle") {
const phase = evt.data?.phase;
if (phase === "end" || phase === "error") {
const finalText = accumulatedText || "No response from Moltbot.";
const finalText = accumulatedText || "No response from OpenClaw.";
const finalStatus = phase === "error" ? "failed" : "completed";
requestFinalize(finalStatus, finalText);
}
@@ -831,7 +831,7 @@ export async function handleOpenResponsesHttpRequest(
.map((p) => (typeof p.text === "string" ? p.text : ""))
.filter(Boolean)
.join("\n\n")
: "No response from Moltbot.";
: "No response from OpenClaw.";
accumulatedText = content;
sawAssistantDelta = true;
+5 -5
View File
@@ -1,16 +1,16 @@
export const GATEWAY_CLIENT_IDS = {
WEBCHAT_UI: "webchat-ui",
CONTROL_UI: "moltbot-control-ui",
CONTROL_UI: "openclaw-control-ui",
WEBCHAT: "webchat",
CLI: "cli",
GATEWAY_CLIENT: "gateway-client",
MACOS_APP: "moltbot-macos",
IOS_APP: "moltbot-ios",
ANDROID_APP: "moltbot-android",
MACOS_APP: "openclaw-macos",
IOS_APP: "openclaw-ios",
ANDROID_APP: "openclaw-android",
NODE_HOST: "node-host",
TEST: "test",
FINGERPRINT: "fingerprint",
PROBE: "moltbot-probe",
PROBE: "openclaw-probe",
} as const;
export type GatewayClientId = (typeof GATEWAY_CLIENT_IDS)[keyof typeof GATEWAY_CLIENT_IDS];
+2 -2
View File
@@ -5,10 +5,10 @@ export type BrowserControlServer = {
};
export async function startBrowserControlServerIfEnabled(): Promise<BrowserControlServer | null> {
if (isTruthyEnvValue(process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER)) return null;
if (isTruthyEnvValue(process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER)) return null;
// Lazy import: keeps startup fast, but still bundles for the embedded
// gateway (bun --compile) via the static specifier path.
const override = process.env.CLAWDBOT_BROWSER_CONTROL_MODULE?.trim();
const override = process.env.OPENCLAW_BROWSER_CONTROL_MODULE?.trim();
const mod = override ? await import(override) : await import("../browser/control-service.js");
const start =
typeof (mod as { startBrowserControlServiceFromConfig?: unknown })
+2 -2
View File
@@ -1,7 +1,7 @@
import { resolveChannelDefaultAccountId } from "../channels/plugins/helpers.js";
import { type ChannelId, getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js";
import type { ChannelAccountSnapshot } from "../channels/plugins/types.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { formatErrorMessage } from "../infra/errors.js";
import { resetDirectoryCache } from "../infra/outbound/target-resolver.js";
import type { createSubsystemLogger } from "../logging/subsystem.js";
@@ -45,7 +45,7 @@ function cloneDefaultRuntime(channelId: ChannelId, accountId: string): ChannelAc
}
type ChannelManagerOptions = {
loadConfig: () => MoltbotConfig;
loadConfig: () => OpenClawConfig;
channelLogs: Record<ChannelId, SubsystemLogger>;
channelRuntimeEnvs: Record<ChannelId, RuntimeEnv>;
};
+2 -2
View File
@@ -18,8 +18,8 @@ export const __setMaxChatHistoryMessagesBytesForTest = (value?: number) => {
};
export const DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;
export const getHandshakeTimeoutMs = () => {
if (process.env.VITEST && process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS) {
const parsed = Number(process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS);
if (process.env.VITEST && process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS) {
const parsed = Number(process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS);
if (Number.isFinite(parsed) && parsed > 0) return parsed;
}
return DEFAULT_HANDSHAKE_TIMEOUT_MS;
+1 -1
View File
@@ -26,7 +26,7 @@ export function buildGatewayCronService(params: {
}): GatewayCronState {
const cronLogger = getChildLogger({ module: "cron" });
const storePath = resolveCronStorePath(params.cfg.cron?.store);
const cronEnabled = process.env.CLAWDBOT_SKIP_CRON !== "1" && params.cfg.cron?.enabled !== false;
const cronEnabled = process.env.OPENCLAW_SKIP_CRON !== "1" && params.cfg.cron?.enabled !== false;
const resolveCronAgent = (requested?: string | null) => {
const runtimeConfig = loadConfig();
+15 -4
View File
@@ -1,6 +1,6 @@
import { startGatewayBonjourAdvertiser } from "../infra/bonjour.js";
import { pickPrimaryTailnetIPv4, pickPrimaryTailnetIPv6 } from "../infra/tailnet.js";
import { WIDE_AREA_DISCOVERY_DOMAIN, writeWideAreaGatewayZone } from "../infra/widearea-dns.js";
import { resolveWideAreaDiscoveryDomain, writeWideAreaGatewayZone } from "../infra/widearea-dns.js";
import {
formatBonjourInstanceName,
resolveBonjourCliPath,
@@ -13,6 +13,7 @@ export async function startGatewayDiscovery(params: {
gatewayTls?: { enabled: boolean; fingerprintSha256?: string };
canvasPort?: number;
wideAreaDiscoveryEnabled: boolean;
wideAreaDiscoveryDomain?: string | null;
tailscaleMode: "off" | "serve" | "funnel";
/** mDNS/Bonjour discovery mode (default: minimal). */
mdnsMode?: "off" | "minimal" | "full";
@@ -23,7 +24,7 @@ export async function startGatewayDiscovery(params: {
// mDNS can be disabled via config (mdnsMode: off) or env var.
const bonjourEnabled =
mdnsMode !== "off" &&
process.env.CLAWDBOT_DISABLE_BONJOUR !== "1" &&
process.env.OPENCLAW_DISABLE_BONJOUR !== "1" &&
process.env.NODE_ENV !== "test" &&
!process.env.VITEST;
const mdnsMinimal = mdnsMode !== "full";
@@ -32,7 +33,7 @@ export async function startGatewayDiscovery(params: {
const tailnetDns = needsTailnetDns
? await resolveTailnetDnsHint({ enabled: tailscaleEnabled })
: undefined;
const sshPortEnv = mdnsMinimal ? undefined : process.env.CLAWDBOT_SSH_PORT?.trim();
const sshPortEnv = mdnsMinimal ? undefined : process.env.OPENCLAW_SSH_PORT?.trim();
const sshPortParsed = sshPortEnv ? Number.parseInt(sshPortEnv, 10) : NaN;
const sshPort = Number.isFinite(sshPortParsed) && sshPortParsed > 0 ? sshPortParsed : undefined;
const cliPath = mdnsMinimal ? undefined : resolveBonjourCliPath();
@@ -57,6 +58,15 @@ export async function startGatewayDiscovery(params: {
}
if (params.wideAreaDiscoveryEnabled) {
const wideAreaDomain = resolveWideAreaDiscoveryDomain({
configDomain: params.wideAreaDiscoveryDomain ?? undefined,
});
if (!wideAreaDomain) {
params.logDiscovery.warn(
"discovery.wideArea.enabled is true, but no domain was configured; set discovery.wideArea.domain to enable unicast DNS-SD",
);
return { bonjourStop };
}
const tailnetIPv4 = pickPrimaryTailnetIPv4();
if (!tailnetIPv4) {
params.logDiscovery.warn(
@@ -66,6 +76,7 @@ export async function startGatewayDiscovery(params: {
try {
const tailnetIPv6 = pickPrimaryTailnetIPv6();
const result = await writeWideAreaGatewayZone({
domain: wideAreaDomain,
gatewayPort: params.port,
displayName: formatBonjourInstanceName(params.machineDisplayName),
tailnetIPv4,
@@ -77,7 +88,7 @@ export async function startGatewayDiscovery(params: {
cliPath: resolveBonjourCliPath(),
});
params.logDiscovery.info(
`wide-area DNS-SD ${result.changed ? "updated" : "unchanged"} (${WIDE_AREA_DISCOVERY_DOMAIN}${result.zonePath})`,
`wide-area DNS-SD ${result.changed ? "updated" : "unchanged"} (${wideAreaDomain}${result.zonePath})`,
);
} catch (err) {
params.logDiscovery.warn(`wide-area discovery update failed: ${String(err)}`);
+5 -5
View File
@@ -10,21 +10,21 @@ describe("resolveTailnetDnsHint", () => {
const prevTailnetDns = { value: undefined as string | undefined };
beforeEach(() => {
prevTailnetDns.value = process.env.CLAWDBOT_TAILNET_DNS;
delete process.env.CLAWDBOT_TAILNET_DNS;
prevTailnetDns.value = process.env.OPENCLAW_TAILNET_DNS;
delete process.env.OPENCLAW_TAILNET_DNS;
getTailnetHostname.mockReset();
});
afterEach(() => {
if (prevTailnetDns.value === undefined) {
delete process.env.CLAWDBOT_TAILNET_DNS;
delete process.env.OPENCLAW_TAILNET_DNS;
} else {
process.env.CLAWDBOT_TAILNET_DNS = prevTailnetDns.value;
process.env.OPENCLAW_TAILNET_DNS = prevTailnetDns.value;
}
});
test("returns env hint when disabled", async () => {
process.env.CLAWDBOT_TAILNET_DNS = "studio.tailnet.ts.net.";
process.env.OPENCLAW_TAILNET_DNS = "studio.tailnet.ts.net.";
const value = await resolveTailnetDnsHint({ enabled: false });
expect(value).toBe("studio.tailnet.ts.net");
expect(getTailnetHostname).not.toHaveBeenCalled();
+7 -7
View File
@@ -13,14 +13,14 @@ export type ResolveBonjourCliPathOptions = {
export function formatBonjourInstanceName(displayName: string) {
const trimmed = displayName.trim();
if (!trimmed) return "Moltbot";
if (/moltbot/i.test(trimmed)) return trimmed;
return `${trimmed} (Moltbot)`;
if (!trimmed) return "OpenClaw";
if (/openclaw/i.test(trimmed)) return trimmed;
return `${trimmed} (OpenClaw)`;
}
export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}): string | undefined {
const env = opts.env ?? process.env;
const envPath = env.CLAWDBOT_CLI_PATH?.trim();
const envPath = env.OPENCLAW_CLI_PATH?.trim();
if (envPath) return envPath;
const statSync = opts.statSync ?? fs.statSync;
@@ -34,7 +34,7 @@ export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}):
const execPath = opts.execPath ?? process.execPath;
const execDir = path.dirname(execPath);
const siblingCli = path.join(execDir, "moltbot");
const siblingCli = path.join(execDir, "openclaw");
if (isFile(siblingCli)) return siblingCli;
const argv = opts.argv ?? process.argv;
@@ -46,7 +46,7 @@ export function resolveBonjourCliPath(opts: ResolveBonjourCliPathOptions = {}):
const cwd = opts.cwd ?? process.cwd();
const distCli = path.join(cwd, "dist", "index.js");
if (isFile(distCli)) return distCli;
const binCli = path.join(cwd, "bin", "moltbot.js");
const binCli = path.join(cwd, "bin", "openclaw");
if (isFile(binCli)) return binCli;
return undefined;
@@ -58,7 +58,7 @@ export async function resolveTailnetDnsHint(opts?: {
enabled?: boolean;
}): Promise<string | undefined> {
const env = opts?.env ?? process.env;
const envRaw = env.CLAWDBOT_TAILNET_DNS?.trim();
const envRaw = env.OPENCLAW_TAILNET_DNS?.trim();
const envValue = envRaw && envRaw.length > 0 ? envRaw.replace(/\.$/, "") : "";
if (envValue) return envValue;
if (opts?.enabled === false) return undefined;
+1 -1
View File
@@ -87,7 +87,7 @@ export function createHooksRequestHandler(
logHooks.warn(
"Hook token provided via query parameter is deprecated for security reasons. " +
"Tokens in URLs appear in logs, browser history, and referrer headers. " +
"Use Authorization: Bearer <token> or X-Moltbot-Token header instead.",
"Use Authorization: Bearer <token> or X-OpenClaw-Token header instead.",
);
}
+2 -2
View File
@@ -8,7 +8,7 @@ import {
import { buildChannelUiCatalog } from "../../channels/plugins/catalog.js";
import { buildChannelAccountSnapshot } from "../../channels/plugins/status.js";
import type { ChannelAccountSnapshot, ChannelPlugin } from "../../channels/plugins/types.js";
import type { MoltbotConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/config.js";
import { loadConfig, readConfigFileSnapshot } from "../../config/config.js";
import { getChannelActivity } from "../../infra/channel-activity.js";
import { DEFAULT_ACCOUNT_ID } from "../../routing/session-key.js";
@@ -33,7 +33,7 @@ type ChannelLogoutPayload = {
export async function logoutChannelAccount(params: {
channelId: ChannelId;
accountId?: string | null;
cfg: MoltbotConfig;
cfg: OpenClawConfig;
context: GatewayRequestContext;
plugin: ChannelPlugin;
}): Promise<ChannelLogoutPayload> {
+2 -2
View File
@@ -18,7 +18,7 @@ import {
writeRestartSentinel,
} from "../../infra/restart-sentinel.js";
import { listChannelPlugins } from "../../channels/plugins/index.js";
import { loadMoltbotPlugins } from "../../plugins/loader.js";
import { loadOpenClawPlugins } from "../../plugins/loader.js";
import {
ErrorCodes,
errorShape,
@@ -112,7 +112,7 @@ export const configHandlers: GatewayRequestHandlers = {
}
const cfg = loadConfig();
const workspaceDir = resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
const pluginRegistry = loadMoltbotPlugins({
const pluginRegistry = loadOpenClawPlugins({
config: cfg,
workspaceDir,
logger: {
+4 -4
View File
@@ -16,16 +16,16 @@ describe("logs.tail", () => {
});
it("falls back to latest rolling log file when today is missing", async () => {
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-logs-"));
const older = path.join(tempDir, "moltbot-2026-01-20.log");
const newer = path.join(tempDir, "moltbot-2026-01-21.log");
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-logs-"));
const older = path.join(tempDir, "openclaw-2026-01-20.log");
const newer = path.join(tempDir, "openclaw-2026-01-21.log");
await fs.writeFile(older, '{"msg":"old"}\n');
await fs.writeFile(newer, '{"msg":"new"}\n');
await fs.utimes(older, new Date(0), new Date(0));
await fs.utimes(newer, new Date(), new Date());
setLoggerOverride({ file: path.join(tempDir, "moltbot-2026-01-22.log") });
setLoggerOverride({ file: path.join(tempDir, "openclaw-2026-01-22.log") });
const respond = vi.fn();
await logsHandlers["logs.tail"]({
+1 -1
View File
@@ -13,7 +13,7 @@ const DEFAULT_LIMIT = 500;
const DEFAULT_MAX_BYTES = 250_000;
const MAX_LIMIT = 5000;
const MAX_BYTES = 1_000_000;
const ROLLING_LOG_RE = /^moltbot-\d{4}-\d{2}-\d{2}\.log$/;
const ROLLING_LOG_RE = /^openclaw-\d{4}-\d{2}-\d{2}\.log$/;
function clamp(value: number, min: number, max: number) {
return Math.max(min, Math.min(max, value));
+3 -3
View File
@@ -2,7 +2,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/ag
import { installSkill } from "../../agents/skills-install.js";
import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js";
import { loadWorkspaceSkillEntries, type SkillEntry } from "../../agents/skills.js";
import type { MoltbotConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/config.js";
import { loadConfig, writeConfigFile } from "../../config/config.js";
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
import {
@@ -16,7 +16,7 @@ import {
} from "../protocol/index.js";
import type { GatewayRequestHandlers } from "./types.js";
function listWorkspaceDirs(cfg: MoltbotConfig): string[] {
function listWorkspaceDirs(cfg: OpenClawConfig): string[] {
const dirs = new Set<string>();
const list = cfg.agents?.list;
if (Array.isArray(list)) {
@@ -172,7 +172,7 @@ export const skillsHandlers: GatewayRequestHandlers = {
}
entries[p.skillKey] = current;
skills.entries = entries;
const nextConfig: MoltbotConfig = {
const nextConfig: OpenClawConfig = {
...cfg,
skills,
};
+2 -2
View File
@@ -1,4 +1,4 @@
import { resolveMoltbotPackageRoot } from "../../infra/moltbot-root.js";
import { resolveOpenClawPackageRoot } from "../../infra/openclaw-root.js";
import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
import {
formatDoctorNonInteractiveHint,
@@ -49,7 +49,7 @@ export const updateHandlers: GatewayRequestHandlers = {
let result: Awaited<ReturnType<typeof runGatewayUpdate>>;
try {
const root =
(await resolveMoltbotPackageRoot({
(await resolveOpenClawPackageRoot({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
+3 -3
View File
@@ -3,10 +3,10 @@ import type { PluginRegistry } from "../plugins/registry.js";
import type { PluginDiagnostic } from "../plugins/types.js";
import { loadGatewayPlugins } from "./server-plugins.js";
const loadMoltbotPlugins = vi.hoisted(() => vi.fn());
const loadOpenClawPlugins = vi.hoisted(() => vi.fn());
vi.mock("../plugins/loader.js", () => ({
loadMoltbotPlugins,
loadOpenClawPlugins,
}));
const createRegistry = (diagnostics: PluginDiagnostic[]): PluginRegistry => ({
@@ -34,7 +34,7 @@ describe("loadGatewayPlugins", () => {
message: "failed to load plugin: boom",
},
];
loadMoltbotPlugins.mockReturnValue(createRegistry(diagnostics));
loadOpenClawPlugins.mockReturnValue(createRegistry(diagnostics));
const log = {
info: vi.fn(),
+2 -2
View File
@@ -1,5 +1,5 @@
import type { loadConfig } from "../config/config.js";
import { loadMoltbotPlugins } from "../plugins/loader.js";
import { loadOpenClawPlugins } from "../plugins/loader.js";
import type { GatewayRequestHandler } from "./server-methods/types.js";
export function loadGatewayPlugins(params: {
@@ -14,7 +14,7 @@ export function loadGatewayPlugins(params: {
coreGatewayHandlers: Record<string, GatewayRequestHandler>;
baseMethods: string[];
}) {
const pluginRegistry = loadMoltbotPlugins({
const pluginRegistry = loadOpenClawPlugins({
config: params.cfg,
workspaceDir: params.workspaceDir,
logger: {
+5 -5
View File
@@ -87,7 +87,7 @@ export function createGatewayReloadHandlers(params: {
if (plan.restartGmailWatcher) {
await stopGmailWatcher().catch(() => {});
if (!isTruthyEnvValue(process.env.CLAWDBOT_SKIP_GMAIL_WATCHER)) {
if (!isTruthyEnvValue(process.env.OPENCLAW_SKIP_GMAIL_WATCHER)) {
try {
const gmailResult = await startGmailWatcher(nextConfig);
if (gmailResult.started) {
@@ -103,17 +103,17 @@ export function createGatewayReloadHandlers(params: {
params.logHooks.error(`gmail watcher failed to start: ${String(err)}`);
}
} else {
params.logHooks.info("skipping gmail watcher restart (CLAWDBOT_SKIP_GMAIL_WATCHER=1)");
params.logHooks.info("skipping gmail watcher restart (OPENCLAW_SKIP_GMAIL_WATCHER=1)");
}
}
if (plan.restartChannels.size > 0) {
if (
isTruthyEnvValue(process.env.CLAWDBOT_SKIP_CHANNELS) ||
isTruthyEnvValue(process.env.CLAWDBOT_SKIP_PROVIDERS)
isTruthyEnvValue(process.env.OPENCLAW_SKIP_CHANNELS) ||
isTruthyEnvValue(process.env.OPENCLAW_SKIP_PROVIDERS)
) {
params.logChannels.info(
"skipping channel reload (CLAWDBOT_SKIP_CHANNELS=1 or CLAWDBOT_SKIP_PROVIDERS=1)",
"skipping channel reload (OPENCLAW_SKIP_CHANNELS=1 or OPENCLAW_SKIP_PROVIDERS=1)",
);
} else {
const restartChannel = async (name: ChannelKind) => {
+3 -3
View File
@@ -77,12 +77,12 @@ export async function resolveGatewayRuntimeConfig(params: {
(authMode === "token" && hasToken) || (authMode === "password" && hasPassword);
const hooksConfig = resolveHooksConfig(params.cfg);
const canvasHostEnabled =
process.env.CLAWDBOT_SKIP_CANVAS_HOST !== "1" && params.cfg.canvasHost?.enabled !== false;
process.env.OPENCLAW_SKIP_CANVAS_HOST !== "1" && params.cfg.canvasHost?.enabled !== false;
assertGatewayAuthConfigured(resolvedAuth);
if (tailscaleMode === "funnel" && authMode !== "password") {
throw new Error(
"tailscale funnel requires gateway auth mode=password (set gateway.auth.password or CLAWDBOT_GATEWAY_PASSWORD)",
"tailscale funnel requires gateway auth mode=password (set gateway.auth.password or OPENCLAW_GATEWAY_PASSWORD)",
);
}
if (tailscaleMode !== "off" && !isLoopbackHost(bindHost)) {
@@ -90,7 +90,7 @@ export async function resolveGatewayRuntimeConfig(params: {
}
if (!isLoopbackHost(bindHost) && !hasSharedSecret) {
throw new Error(
`refusing to bind gateway to ${bindHost}:${params.port} without auth (set gateway.auth.token/password, or set CLAWDBOT_GATEWAY_TOKEN/CLAWDBOT_GATEWAY_PASSWORD)`,
`refusing to bind gateway to ${bindHost}:${params.port} without auth (set gateway.auth.token/password, or set OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD)`,
);
}
+1 -1
View File
@@ -22,7 +22,7 @@ import type { PluginRegistry } from "../plugins/registry.js";
import type { GatewayTlsRuntime } from "./server/tls.js";
export async function createGatewayRuntimeState(params: {
cfg: import("../config/config.js").MoltbotConfig;
cfg: import("../config/config.js").OpenClawConfig;
bindHost: string;
port: number;
controlUiEnabled: boolean;
+8 -8
View File
@@ -15,7 +15,7 @@ import {
triggerInternalHook,
} from "../hooks/internal-hooks.js";
import { loadInternalHooks } from "../hooks/loader.js";
import type { loadMoltbotPlugins } from "../plugins/loader.js";
import type { loadOpenClawPlugins } from "../plugins/loader.js";
import { type PluginServicesHandle, startPluginServices } from "../plugins/services.js";
import { startBrowserControlServerIfEnabled } from "./server-browser.js";
import {
@@ -25,7 +25,7 @@ import {
export async function startGatewaySidecars(params: {
cfg: ReturnType<typeof loadConfig>;
pluginRegistry: ReturnType<typeof loadMoltbotPlugins>;
pluginRegistry: ReturnType<typeof loadOpenClawPlugins>;
defaultWorkspaceDir: string;
deps: CliDeps;
startChannels: () => Promise<void>;
@@ -38,7 +38,7 @@ export async function startGatewaySidecars(params: {
logChannels: { info: (msg: string) => void; error: (msg: string) => void };
logBrowser: { error: (msg: string) => void };
}) {
// Start clawd browser control server (unless disabled via config).
// Start OpenClaw browser control server (unless disabled via config).
let browserControl: Awaited<ReturnType<typeof startBrowserControlServerIfEnabled>> = null;
try {
browserControl = await startBrowserControlServerIfEnabled();
@@ -47,7 +47,7 @@ export async function startGatewaySidecars(params: {
}
// Start Gmail watcher if configured (hooks.gmail.account).
if (!isTruthyEnvValue(process.env.CLAWDBOT_SKIP_GMAIL_WATCHER)) {
if (!isTruthyEnvValue(process.env.OPENCLAW_SKIP_GMAIL_WATCHER)) {
try {
const gmailResult = await startGmailWatcher(params.cfg);
if (gmailResult.started) {
@@ -112,10 +112,10 @@ export async function startGatewaySidecars(params: {
}
// Launch configured channels so gateway replies via the surface the message came from.
// Tests can opt out via CLAWDBOT_SKIP_CHANNELS (or legacy CLAWDBOT_SKIP_PROVIDERS).
// Tests can opt out via OPENCLAW_SKIP_CHANNELS (or legacy OPENCLAW_SKIP_PROVIDERS).
const skipChannels =
isTruthyEnvValue(process.env.CLAWDBOT_SKIP_CHANNELS) ||
isTruthyEnvValue(process.env.CLAWDBOT_SKIP_PROVIDERS);
isTruthyEnvValue(process.env.OPENCLAW_SKIP_CHANNELS) ||
isTruthyEnvValue(process.env.OPENCLAW_SKIP_PROVIDERS);
if (!skipChannels) {
try {
await params.startChannels();
@@ -124,7 +124,7 @@ export async function startGatewaySidecars(params: {
}
} else {
params.logChannels.info(
"skipping channel start (CLAWDBOT_SKIP_CHANNELS=1 or CLAWDBOT_SKIP_PROVIDERS=1)",
"skipping channel start (OPENCLAW_SKIP_CHANNELS=1 or OPENCLAW_SKIP_PROVIDERS=1)",
);
}
@@ -167,7 +167,7 @@ describe("gateway server agent", () => {
test("agent marks implicit delivery when lastTo is stale", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+436769770569"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -199,7 +199,7 @@ describe("gateway server agent", () => {
test("agent forwards sessionKey to agentCommand", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -227,7 +227,7 @@ describe("gateway server agent", () => {
test("agent derives sessionKey from agentId", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
testState.agentsConfig = { list: [{ id: "ops" }] };
await writeSessionStore({
@@ -285,7 +285,7 @@ describe("gateway server agent", () => {
test("agent forwards accountId to agentCommand", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -320,7 +320,7 @@ describe("gateway server agent", () => {
test("agent avoids lastAccountId when explicit to is provided", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -353,7 +353,7 @@ describe("gateway server agent", () => {
test("agent keeps explicit accountId when explicit to is provided", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -387,7 +387,7 @@ describe("gateway server agent", () => {
test("agent falls back to lastAccountId for implicit delivery", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -418,7 +418,7 @@ describe("gateway server agent", () => {
test("agent forwards image attachments as images[]", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -459,7 +459,7 @@ describe("gateway server agent", () => {
test("agent falls back to whatsapp when delivery requested and no last channel exists", async () => {
setRegistry(defaultRegistry);
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -488,7 +488,7 @@ describe("gateway server agent", () => {
test("agent routes main last-channel whatsapp", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -521,7 +521,7 @@ describe("gateway server agent", () => {
test("agent routes main last-channel telegram", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -553,7 +553,7 @@ describe("gateway server agent", () => {
test("agent routes main last-channel discord", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -585,7 +585,7 @@ describe("gateway server agent", () => {
test("agent routes main last-channel slack", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -617,7 +617,7 @@ describe("gateway server agent", () => {
test("agent routes main last-channel signal", async () => {
setRegistry(defaultRegistry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -137,7 +137,7 @@ describe("gateway server agent", () => {
]);
registryState.registry = registry;
setActivePluginRegistry(registry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -177,7 +177,7 @@ describe("gateway server agent", () => {
]);
registryState.registry = registry;
setActivePluginRegistry(registry);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -231,7 +231,7 @@ describe("gateway server agent", () => {
test("agent ignores webchat last-channel for routing", async () => {
testState.allowFrom = ["+1555"];
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -262,7 +262,7 @@ describe("gateway server agent", () => {
});
test("agent uses webchat for internal runs when last provider is webchat", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
@@ -395,7 +395,7 @@ describe("gateway server agent", () => {
});
test("agent events stream to webchat clients when run context is registered", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
+25 -25
View File
@@ -49,8 +49,8 @@ describe("gateway server auth/connect", () => {
test("closes silent handshakes after timeout", { timeout: 60_000 }, async () => {
vi.useRealTimers();
const prevHandshakeTimeout = process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS;
process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS = "50";
const prevHandshakeTimeout = process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS;
process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS = "50";
try {
const ws = await openWs(port);
const handshakeTimeoutMs = getHandshakeTimeoutMs();
@@ -58,9 +58,9 @@ describe("gateway server auth/connect", () => {
expect(closed).toBe(true);
} finally {
if (prevHandshakeTimeout === undefined) {
delete process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS;
delete process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS;
} else {
process.env.CLAWDBOT_TEST_HANDSHAKE_TIMEOUT_MS = prevHandshakeTimeout;
process.env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS = prevHandshakeTimeout;
}
}
});
@@ -220,8 +220,8 @@ describe("gateway server auth/connect", () => {
let prevToken: string | undefined;
beforeAll(async () => {
prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
process.env.CLAWDBOT_GATEWAY_TOKEN = "secret";
prevToken = process.env.OPENCLAW_GATEWAY_TOKEN;
process.env.OPENCLAW_GATEWAY_TOKEN = "secret";
port = await getFreePort();
server = await startGatewayServer(port);
});
@@ -229,9 +229,9 @@ describe("gateway server auth/connect", () => {
afterAll(async () => {
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -294,9 +294,9 @@ describe("gateway server auth/connect", () => {
ws.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -309,8 +309,8 @@ describe("gateway server auth/connect", () => {
trustedProxies: ["127.0.0.1"],
},
} as any);
const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
process.env.CLAWDBOT_GATEWAY_TOKEN = "secret";
const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN;
process.env.OPENCLAW_GATEWAY_TOKEN = "secret";
const port = await getFreePort();
const server = await startGatewayServer(port);
const ws = new WebSocket(`ws://127.0.0.1:${port}`, {
@@ -359,17 +359,17 @@ describe("gateway server auth/connect", () => {
ws.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
test("allows control ui with stale device identity when device auth is disabled", async () => {
testState.gatewayControlUi = { dangerouslyDisableDeviceAuth: true };
testState.gatewayAuth = { mode: "token", token: "secret" };
const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
process.env.CLAWDBOT_GATEWAY_TOKEN = "secret";
const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN;
process.env.OPENCLAW_GATEWAY_TOKEN = "secret";
const port = await getFreePort();
const server = await startGatewayServer(port);
const ws = await openWs(port);
@@ -407,9 +407,9 @@ describe("gateway server auth/connect", () => {
ws.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -443,9 +443,9 @@ describe("gateway server auth/connect", () => {
ws2.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -461,7 +461,7 @@ describe("gateway server auth/connect", () => {
const { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } =
await import("../utils/message-channel.js");
const { server, ws, port, prevToken } = await startServerWithClient("secret");
const identityDir = await mkdtemp(join(tmpdir(), "moltbot-device-scope-"));
const identityDir = await mkdtemp(join(tmpdir(), "openclaw-device-scope-"));
const identity = loadOrCreateDeviceIdentity(join(identityDir, "device.json"));
const client = {
id: GATEWAY_CLIENT_NAMES.TEST,
@@ -522,9 +522,9 @@ describe("gateway server auth/connect", () => {
ws2.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -560,9 +560,9 @@ describe("gateway server auth/connect", () => {
ws2.close();
await server.close();
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
});
@@ -56,7 +56,7 @@ describe("gateway server chat", () => {
const historyMaxBytes = 192 * 1024;
__setMaxChatHistoryMessagesBytesForTest(historyMaxBytes);
await connectOk(ws);
const sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
tempDirs.push(sessionDir);
testState.sessionStorePath = path.join(sessionDir, "sessions.json");
const writeStore = async (
@@ -100,7 +100,7 @@ describe("gateway server chat", () => {
const sessionCall = spy.mock.calls.at(-1)?.[0] as { SessionKey?: string } | undefined;
expect(sessionCall?.SessionKey).toBe("agent:main:subagent:abc");
const sendPolicyDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const sendPolicyDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
tempDirs.push(sendPolicyDir);
testState.sessionStorePath = path.join(sendPolicyDir, "sessions.json");
testState.sessionConfig = {
@@ -139,7 +139,7 @@ describe("gateway server chat", () => {
testState.sessionStorePath = undefined;
testState.sessionConfig = undefined;
const agentBlockedDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const agentBlockedDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
tempDirs.push(agentBlockedDir);
testState.sessionStorePath = path.join(agentBlockedDir, "sessions.json");
testState.sessionConfig = {
@@ -241,7 +241,7 @@ describe("gateway server chat", () => {
| undefined;
expect(imgOnlyOpts?.images).toEqual([{ type: "image", data: pngB64, mimeType: "image/png" }]);
const historyDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const historyDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
tempDirs.push(historyDir);
testState.sessionStorePath = path.join(historyDir, "sessions.json");
await writeSessionStore({
@@ -293,7 +293,7 @@ describe("gateway server chat", () => {
});
test("routes chat.send slash commands without agent runs", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
try {
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
@@ -332,7 +332,7 @@ describe("gateway server chat", () => {
});
test("agent events include sessionKey and agent.wait covers lifecycle flows", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
entries: {
+6 -6
View File
@@ -19,16 +19,16 @@ let port = 0;
let previousToken: string | undefined;
beforeAll(async () => {
previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
previousToken = process.env.OPENCLAW_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
port = await getFreePort();
server = await startGatewayServer(port);
});
afterAll(async () => {
await server.close();
if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN;
else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken;
if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN;
else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken;
});
const openClient = async () => {
@@ -49,7 +49,7 @@ describe("gateway config.apply", () => {
id,
method: "config.apply",
params: {
raw: '{ "agents": { "list": [{ "id": "main", "workspace": "~/clawd" }] } }',
raw: '{ "agents": { "list": [{ "id": "main", "workspace": "~/openclaw" }] } }',
sessionKey: "agent:main:whatsapp:dm:+15555550123",
restartDelayMs: 0,
},
@@ -62,7 +62,7 @@ describe("gateway config.apply", () => {
expect(res.ok).toBe(true);
// Verify sentinel file was created (restart was scheduled)
const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json");
const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json");
// Wait for file to be written
await new Promise((resolve) => setTimeout(resolve, 100));
+3 -3
View File
@@ -190,7 +190,7 @@ describe("gateway config.patch", () => {
);
expect(patchRes.ok).toBe(true);
const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json");
const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json");
await new Promise((resolve) => setTimeout(resolve, 100));
try {
@@ -288,7 +288,7 @@ describe("gateway config.patch", () => {
describe("gateway server sessions", () => {
it("filters sessions by agentId", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-agents-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-agents-"));
testState.sessionConfig = {
store: path.join(dir, "{agentId}", "sessions.json"),
};
@@ -349,7 +349,7 @@ describe("gateway server sessions", () => {
});
it("resolves and patches main alias to default agent main key", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-"));
const storePath = path.join(dir, "sessions.json");
testState.sessionStorePath = storePath;
testState.agentsConfig = { list: [{ id: "ops", default: true }] };
+10 -10
View File
@@ -50,9 +50,9 @@ async function waitForNonEmptyFile(pathname: string, timeoutMs = 2000) {
describe("gateway server cron", () => {
test("handles cron CRUD, normalization, and patch semantics", { timeout: 120_000 }, async () => {
const prevSkipCron = process.env.CLAWDBOT_SKIP_CRON;
process.env.CLAWDBOT_SKIP_CRON = "0";
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-cron-"));
const prevSkipCron = process.env.OPENCLAW_SKIP_CRON;
process.env.OPENCLAW_SKIP_CRON = "0";
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-cron-"));
testState.cronStorePath = path.join(dir, "cron", "jobs.json");
testState.sessionConfig = { mainKey: "primary" };
testState.cronEnabled = false;
@@ -256,17 +256,17 @@ describe("gateway server cron", () => {
testState.sessionConfig = undefined;
testState.cronEnabled = undefined;
if (prevSkipCron === undefined) {
delete process.env.CLAWDBOT_SKIP_CRON;
delete process.env.OPENCLAW_SKIP_CRON;
} else {
process.env.CLAWDBOT_SKIP_CRON = prevSkipCron;
process.env.OPENCLAW_SKIP_CRON = prevSkipCron;
}
}
});
test("writes cron run history and auto-runs due jobs", async () => {
const prevSkipCron = process.env.CLAWDBOT_SKIP_CRON;
process.env.CLAWDBOT_SKIP_CRON = "0";
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gw-cron-log-"));
const prevSkipCron = process.env.OPENCLAW_SKIP_CRON;
process.env.OPENCLAW_SKIP_CRON = "0";
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-cron-log-"));
testState.cronStorePath = path.join(dir, "cron", "jobs.json");
testState.cronEnabled = undefined;
await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true });
@@ -353,9 +353,9 @@ describe("gateway server cron", () => {
testState.cronStorePath = undefined;
testState.cronEnabled = undefined;
if (prevSkipCron === undefined) {
delete process.env.CLAWDBOT_SKIP_CRON;
delete process.env.OPENCLAW_SKIP_CRON;
} else {
process.env.CLAWDBOT_SKIP_CRON = prevSkipCron;
process.env.OPENCLAW_SKIP_CRON = prevSkipCron;
}
}
}, 45_000);
+5 -5
View File
@@ -28,16 +28,16 @@ let port = 0;
let previousToken: string | undefined;
beforeAll(async () => {
previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
previousToken = process.env.OPENCLAW_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
port = await getFreePort();
server = await startGatewayServer(port);
});
afterAll(async () => {
await server.close();
if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN;
else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken;
if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN;
else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken;
});
const openClient = async (opts?: Parameters<typeof connectOk>[1]) => {
@@ -214,7 +214,7 @@ describe("gateway server health/presence", () => {
});
test("presence includes client fingerprint", async () => {
const identityPath = path.join(os.tmpdir(), `moltbot-device-${randomUUID()}.json`);
const identityPath = path.join(os.tmpdir(), `openclaw-device-${randomUUID()}.json`);
const identity = loadOrCreateDeviceIdentity(identityPath);
const role = "operator";
const scopes: string[] = [];
+1 -1
View File
@@ -108,7 +108,7 @@ describe("gateway server hooks", () => {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-moltbot-token": "hook-secret",
"x-openclaw-token": "hook-secret",
},
body: JSON.stringify({ text: "Header auth" }),
});
+8 -7
View File
@@ -20,7 +20,7 @@ import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js";
import { onHeartbeatEvent } from "../infra/heartbeat-events.js";
import { startHeartbeatRunner } from "../infra/heartbeat-runner.js";
import { getMachineDisplayName } from "../infra/machine-name.js";
import { ensureMoltbotCliOnPath } from "../infra/path-env.js";
import { ensureOpenClawCliOnPath } from "../infra/path-env.js";
import {
primeRemoteSkillsCache,
refreshRemoteBinsForConnectedNodes,
@@ -73,7 +73,7 @@ import { attachGatewayWsHandlers } from "./server-ws-runtime.js";
export { __resetModelCatalogCacheForTest } from "./server-model-catalog.js";
ensureMoltbotCliOnPath();
ensureOpenClawCliOnPath();
const log = createSubsystemLogger("gateway");
const logCanvas = log.child("canvas");
@@ -149,13 +149,13 @@ export async function startGatewayServer(
opts: GatewayServerOptions = {},
): Promise<GatewayServer> {
// Ensure all default port derivations (browser/canvas) see the actual runtime port.
process.env.CLAWDBOT_GATEWAY_PORT = String(port);
process.env.OPENCLAW_GATEWAY_PORT = String(port);
logAcceptedEnvOption({
key: "CLAWDBOT_RAW_STREAM",
key: "OPENCLAW_RAW_STREAM",
description: "raw stream logging enabled",
});
logAcceptedEnvOption({
key: "CLAWDBOT_RAW_STREAM_PATH",
key: "OPENCLAW_RAW_STREAM_PATH",
description: "raw stream log path override",
});
@@ -169,7 +169,7 @@ export async function startGatewayServer(
const { config: migrated, changes } = migrateLegacyConfig(configSnapshot.parsed);
if (!migrated) {
throw new Error(
`Legacy config entries detected but auto-migration failed. Run "${formatCliCommand("moltbot doctor")}" to migrate.`,
`Legacy config entries detected but auto-migration failed. Run "${formatCliCommand("openclaw doctor")}" to migrate.`,
);
}
await writeConfigFile(migrated);
@@ -191,7 +191,7 @@ export async function startGatewayServer(
.join("\n")
: "Unknown validation issue.";
throw new Error(
`Invalid config at ${configSnapshot.path}.\n${issues}\nRun "${formatCliCommand("moltbot doctor")}" to repair, then retry.`,
`Invalid config at ${configSnapshot.path}.\n${issues}\nRun "${formatCliCommand("openclaw doctor")}" to repair, then retry.`,
);
}
@@ -351,6 +351,7 @@ export async function startGatewayServer(
? { enabled: true, fingerprintSha256: gatewayTls.fingerprintSha256 }
: undefined,
wideAreaDiscoveryEnabled: cfgAtStart.discovery?.wideArea?.enabled === true,
wideAreaDiscoveryDomain: cfgAtStart.discovery?.wideArea?.domain,
tailscaleMode,
mdnsMode: cfgAtStart.discovery?.mdns?.mode,
logDiscovery,
+4 -4
View File
@@ -54,11 +54,11 @@ function connectReq(
);
}
test("accepts moltbot-ios as a valid gateway client id", async () => {
test("accepts openclaw-ios as a valid gateway client id", async () => {
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
await new Promise<void>((resolve) => ws.once("open", resolve));
const res = await connectReq(ws, { clientId: "moltbot-ios", platform: "ios" });
const res = await connectReq(ws, { clientId: "openclaw-ios", platform: "ios" });
// We don't care if auth fails here; we only care that schema validation accepts the client id.
// A schema rejection would close the socket before sending a response.
if (!res.ok) {
@@ -73,11 +73,11 @@ test("accepts moltbot-ios as a valid gateway client id", async () => {
ws.close();
});
test("accepts moltbot-android as a valid gateway client id", async () => {
test("accepts openclaw-android as a valid gateway client id", async () => {
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
await new Promise<void>((resolve) => ws.once("open", resolve));
const res = await connectReq(ws, { clientId: "moltbot-android", platform: "android" });
const res = await connectReq(ws, { clientId: "openclaw-android", platform: "android" });
// We don't care if auth fails here; we only care that schema validation accepts the client id.
// A schema rejection would close the socket before sending a response.
if (!res.ok) {
@@ -93,12 +93,12 @@ const emptyRegistry = createRegistry([]);
describe("gateway server models + voicewake", () => {
const setTempHome = (homeDir: string) => {
const prevHome = process.env.HOME;
const prevStateDir = process.env.CLAWDBOT_STATE_DIR;
const prevStateDir = process.env.OPENCLAW_STATE_DIR;
const prevUserProfile = process.env.USERPROFILE;
const prevHomeDrive = process.env.HOMEDRIVE;
const prevHomePath = process.env.HOMEPATH;
process.env.HOME = homeDir;
process.env.CLAWDBOT_STATE_DIR = path.join(homeDir, ".clawdbot");
process.env.OPENCLAW_STATE_DIR = path.join(homeDir, ".openclaw");
process.env.USERPROFILE = homeDir;
if (process.platform === "win32") {
const parsed = path.parse(homeDir);
@@ -112,9 +112,9 @@ describe("gateway server models + voicewake", () => {
process.env.HOME = prevHome;
}
if (prevStateDir === undefined) {
delete process.env.CLAWDBOT_STATE_DIR;
delete process.env.OPENCLAW_STATE_DIR;
} else {
process.env.CLAWDBOT_STATE_DIR = prevStateDir;
process.env.OPENCLAW_STATE_DIR = prevStateDir;
}
if (prevUserProfile === undefined) {
delete process.env.USERPROFILE;
@@ -140,12 +140,12 @@ describe("gateway server models + voicewake", () => {
"voicewake.get returns defaults and voicewake.set broadcasts",
{ timeout: 60_000 },
async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-home-"));
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-"));
const restoreHome = setTempHome(homeDir);
const initial = await rpcReq<{ triggers: string[] }>(ws, "voicewake.get");
expect(initial.ok).toBe(true);
expect(initial.payload?.triggers).toEqual(["clawd", "claude", "computer"]);
expect(initial.payload?.triggers).toEqual(["openclaw", "claude", "computer"]);
const changedP = onceMessage<{
type: "event";
@@ -171,7 +171,7 @@ describe("gateway server models + voicewake", () => {
expect(after.payload?.triggers).toEqual(["hi", "there"]);
const onDisk = JSON.parse(
await fs.readFile(path.join(homeDir, ".clawdbot", "settings", "voicewake.json"), "utf8"),
await fs.readFile(path.join(homeDir, ".openclaw", "settings", "voicewake.json"), "utf8"),
) as { triggers?: unknown; updatedAtMs?: unknown };
expect(onDisk.triggers).toEqual(["hi", "there"]);
expect(typeof onDisk.updatedAtMs).toBe("number");
@@ -181,7 +181,7 @@ describe("gateway server models + voicewake", () => {
);
test("pushes voicewake.changed to nodes on connect and on updates", async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-home-"));
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-home-"));
const restoreHome = setTempHome(homeDir);
const nodeWs = new WebSocket(`ws://127.0.0.1:${port}`);
@@ -203,7 +203,7 @@ describe("gateway server models + voicewake", () => {
const first = await firstEventP;
expect(first.event).toBe("voicewake.changed");
expect((first.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"clawd",
"openclaw",
"claude",
"computer",
]);
@@ -213,14 +213,14 @@ describe("gateway server models + voicewake", () => {
(o) => o.type === "event" && o.event === "voicewake.changed",
);
const setRes = await rpcReq<{ triggers: string[] }>(ws, "voicewake.set", {
triggers: ["clawd", "computer"],
triggers: ["openclaw", "computer"],
});
expect(setRes.ok).toBe(true);
const broadcast = await broadcastP;
expect(broadcast.event).toBe("voicewake.changed");
expect((broadcast.payload as { triggers?: unknown } | undefined)?.triggers).toEqual([
"clawd",
"openclaw",
"computer",
]);
@@ -315,14 +315,14 @@ describe("gateway server models + voicewake", () => {
describe("gateway server misc", () => {
test("hello-ok advertises the gateway port for canvas host", async () => {
const prevToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
const prevCanvasPort = process.env.CLAWDBOT_CANVAS_HOST_PORT;
process.env.CLAWDBOT_GATEWAY_TOKEN = "secret";
const prevToken = process.env.OPENCLAW_GATEWAY_TOKEN;
const prevCanvasPort = process.env.OPENCLAW_CANVAS_HOST_PORT;
process.env.OPENCLAW_GATEWAY_TOKEN = "secret";
testTailnetIPv4.value = "100.64.0.1";
testState.gatewayBind = "lan";
const canvasPort = await getFreePort();
testState.canvasHostPort = canvasPort;
process.env.CLAWDBOT_CANVAS_HOST_PORT = String(canvasPort);
process.env.OPENCLAW_CANVAS_HOST_PORT = String(canvasPort);
const testPort = await getFreePort();
const canvasHostUrl = resolveCanvasHostUrl({
@@ -332,14 +332,14 @@ describe("gateway server misc", () => {
});
expect(canvasHostUrl).toBe(`http://100.64.0.1:${canvasPort}`);
if (prevToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevToken;
}
if (prevCanvasPort === undefined) {
delete process.env.CLAWDBOT_CANVAS_HOST_PORT;
delete process.env.OPENCLAW_CANVAS_HOST_PORT;
} else {
process.env.CLAWDBOT_CANVAS_HOST_PORT = prevCanvasPort;
process.env.OPENCLAW_CANVAS_HOST_PORT = prevCanvasPort;
}
});
@@ -375,8 +375,8 @@ describe("gateway server misc", () => {
});
test("auto-enables configured channel plugins on startup", async () => {
const configPath = process.env.CLAWDBOT_CONFIG_PATH;
if (!configPath) throw new Error("Missing CLAWDBOT_CONFIG_PATH");
const configPath = process.env.OPENCLAW_CONFIG_PATH;
if (!configPath) throw new Error("Missing OPENCLAW_CONFIG_PATH");
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(
configPath,
+8 -8
View File
@@ -172,22 +172,22 @@ describe("gateway hot reload", () => {
let prevSkipGmail: string | undefined;
beforeEach(() => {
prevSkipChannels = process.env.CLAWDBOT_SKIP_CHANNELS;
prevSkipGmail = process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
process.env.CLAWDBOT_SKIP_CHANNELS = "0";
delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
prevSkipChannels = process.env.OPENCLAW_SKIP_CHANNELS;
prevSkipGmail = process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
process.env.OPENCLAW_SKIP_CHANNELS = "0";
delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
});
afterEach(() => {
if (prevSkipChannels === undefined) {
delete process.env.CLAWDBOT_SKIP_CHANNELS;
delete process.env.OPENCLAW_SKIP_CHANNELS;
} else {
process.env.CLAWDBOT_SKIP_CHANNELS = prevSkipChannels;
process.env.OPENCLAW_SKIP_CHANNELS = prevSkipChannels;
}
if (prevSkipGmail === undefined) {
delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
} else {
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prevSkipGmail;
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = prevSkipGmail;
}
});
@@ -176,7 +176,7 @@ describe("gateway update.run", () => {
await waitForSignal(() => sigusr1.mock.calls.length > 0);
expect(sigusr1).toHaveBeenCalled();
const sentinelPath = path.join(os.homedir(), ".clawdbot", "restart-sentinel.json");
const sentinelPath = path.join(os.homedir(), ".openclaw", "restart-sentinel.json");
const raw = await fs.readFile(sentinelPath, "utf-8");
const parsed = JSON.parse(raw) as {
payload?: { kind?: string; stats?: { mode?: string } };
+13 -13
View File
@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { createMoltbotTools } from "../agents/moltbot-tools.js";
import { createOpenClawTools } from "../agents/openclaw-tools.js";
import { resolveSessionTranscriptPath } from "../config/sessions.js";
import { emitAgentEvent } from "../infra/agent-events.js";
import {
@@ -19,25 +19,25 @@ let prevGatewayPort: string | undefined;
let prevGatewayToken: string | undefined;
beforeAll(async () => {
prevGatewayPort = process.env.CLAWDBOT_GATEWAY_PORT;
prevGatewayToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
prevGatewayPort = process.env.OPENCLAW_GATEWAY_PORT;
prevGatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN;
gatewayPort = await getFreePort();
process.env.CLAWDBOT_GATEWAY_PORT = String(gatewayPort);
process.env.CLAWDBOT_GATEWAY_TOKEN = "test-token";
process.env.OPENCLAW_GATEWAY_PORT = String(gatewayPort);
process.env.OPENCLAW_GATEWAY_TOKEN = "test-token";
server = await startGatewayServer(gatewayPort);
});
afterAll(async () => {
await server.close();
if (prevGatewayPort === undefined) {
delete process.env.CLAWDBOT_GATEWAY_PORT;
delete process.env.OPENCLAW_GATEWAY_PORT;
} else {
process.env.CLAWDBOT_GATEWAY_PORT = prevGatewayPort;
process.env.OPENCLAW_GATEWAY_PORT = prevGatewayPort;
}
if (prevGatewayToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = prevGatewayToken;
process.env.OPENCLAW_GATEWAY_TOKEN = prevGatewayToken;
}
});
@@ -86,7 +86,7 @@ describe("sessions_send gateway loopback", () => {
});
});
const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send");
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) throw new Error("missing sessions_send tool");
const result = await tool.execute("call-loopback", {
@@ -151,7 +151,7 @@ describe("sessions_send label lookup", () => {
timeoutMs: 5000,
});
const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send");
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) throw new Error("missing sessions_send tool");
// Send using label instead of sessionKey
@@ -171,7 +171,7 @@ describe("sessions_send label lookup", () => {
});
it("returns error when label not found", { timeout: 60_000 }, async () => {
const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send");
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) throw new Error("missing sessions_send tool");
const result = await tool.execute("call-missing-label", {
@@ -185,7 +185,7 @@ describe("sessions_send label lookup", () => {
});
it("returns error when neither sessionKey nor label provided", { timeout: 60_000 }, async () => {
const tool = createMoltbotTools().find((candidate) => candidate.name === "sessions_send");
const tool = createOpenClawTools().find((candidate) => candidate.name === "sessions_send");
if (!tool) throw new Error("missing sessions_send tool");
const result = await tool.execute("call-no-key", {
@@ -48,16 +48,16 @@ let port = 0;
let previousToken: string | undefined;
beforeAll(async () => {
previousToken = process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
previousToken = process.env.OPENCLAW_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
port = await getFreePort();
server = await startGatewayServer(port);
});
afterAll(async () => {
await server.close();
if (previousToken === undefined) delete process.env.CLAWDBOT_GATEWAY_TOKEN;
else process.env.CLAWDBOT_GATEWAY_TOKEN = previousToken;
if (previousToken === undefined) delete process.env.OPENCLAW_GATEWAY_TOKEN;
else process.env.OPENCLAW_GATEWAY_TOKEN = previousToken;
});
const openClient = async (opts?: Parameters<typeof connectOk>[1]) => {
@@ -74,7 +74,7 @@ describe("gateway server sessions", () => {
});
test("lists and patches session store via sessions.* RPC", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-"));
const storePath = path.join(dir, "sessions.json");
const now = Date.now();
const recent = now - 30_000;
@@ -370,7 +370,7 @@ describe("gateway server sessions", () => {
});
test("sessions.preview returns transcript previews", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-preview-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-preview-"));
const storePath = path.join(dir, "sessions.json");
testState.sessionStorePath = storePath;
const sessionId = "sess-preview";
@@ -415,7 +415,7 @@ describe("gateway server sessions", () => {
});
test("sessions.delete rejects main and aborts active runs", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-sessions-"));
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-sessions-"));
const storePath = path.join(dir, "sessions.json");
testState.sessionStorePath = storePath;
@@ -789,7 +789,7 @@ export function attachGatewayWsMessageHandler(params: {
type: "hello-ok",
protocol: PROTOCOL_VERSION,
server: {
version: process.env.CLAWDBOT_VERSION ?? process.env.npm_package_version ?? "dev",
version: process.env.OPENCLAW_VERSION ?? process.env.npm_package_version ?? "dev",
commit: process.env.GIT_COMMIT,
host: os.hostname(),
connId,
+3 -3
View File
@@ -13,7 +13,7 @@ describe("readFirstUserMessageFromTranscript", () => {
let storePath: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-fs-test-"));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-fs-test-"));
storePath = path.join(tmpDir, "sessions.json");
});
@@ -159,7 +159,7 @@ describe("readLastMessagePreviewFromTranscript", () => {
let storePath: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-fs-test-"));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-fs-test-"));
storePath = path.join(tmpDir, "sessions.json");
});
@@ -348,7 +348,7 @@ describe("readSessionPreviewItemsFromTranscript", () => {
let storePath: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "moltbot-session-preview-test-"));
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-preview-test-"));
storePath = path.join(tmpDir, "sessions.json");
});
+2 -1
View File
@@ -47,7 +47,8 @@ export function resolveSessionTranscriptCandidates(
if (agentId) {
candidates.push(resolveSessionTranscriptPath(sessionId, agentId));
}
candidates.push(path.join(os.homedir(), ".clawdbot", "sessions", `${sessionId}.jsonl`));
const home = os.homedir();
candidates.push(path.join(home, ".openclaw", "sessions", `${sessionId}.jsonl`));
return candidates;
}
+7 -7
View File
@@ -1,7 +1,7 @@
import os from "node:os";
import path from "node:path";
import { describe, expect, test } from "vitest";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { SessionEntry } from "../config/sessions.js";
import {
capArrayByJsonBytes,
@@ -46,7 +46,7 @@ describe("gateway session utils", () => {
const cfg = {
session: { mainKey: "work" },
agents: { list: [{ id: "ops", default: true }] },
} as MoltbotConfig;
} as OpenClawConfig;
expect(resolveSessionStoreKey({ cfg, sessionKey: "main" })).toBe("agent:ops:work");
expect(resolveSessionStoreKey({ cfg, sessionKey: "work" })).toBe("agent:ops:work");
expect(resolveSessionStoreKey({ cfg, sessionKey: "agent:ops:main" })).toBe("agent:ops:work");
@@ -56,7 +56,7 @@ describe("gateway session utils", () => {
const cfg = {
session: { mainKey: "main" },
agents: { list: [{ id: "ops", default: true }] },
} as MoltbotConfig;
} as OpenClawConfig;
expect(resolveSessionStoreKey({ cfg, sessionKey: "discord:group:123" })).toBe(
"agent:ops:discord:group:123",
);
@@ -69,7 +69,7 @@ describe("gateway session utils", () => {
const cfg = {
session: { scope: "global", mainKey: "work" },
agents: { list: [{ id: "ops", default: true }] },
} as MoltbotConfig;
} as OpenClawConfig;
expect(resolveSessionStoreKey({ cfg, sessionKey: "main" })).toBe("global");
const target = resolveGatewaySessionStoreTarget({ cfg, key: "main" });
expect(target.canonicalKey).toBe("global");
@@ -79,14 +79,14 @@ describe("gateway session utils", () => {
test("resolveGatewaySessionStoreTarget uses canonical key for main alias", () => {
const storeTemplate = path.join(
os.tmpdir(),
"moltbot-session-utils",
"openclaw-session-utils",
"{agentId}",
"sessions.json",
);
const cfg = {
session: { mainKey: "main", store: storeTemplate },
agents: { list: [{ id: "ops", default: true }] },
} as MoltbotConfig;
} as OpenClawConfig;
const target = resolveGatewaySessionStoreTarget({ cfg, key: "main" });
expect(target.canonicalKey).toBe("agent:ops:main");
expect(target.storeKeys).toEqual(expect.arrayContaining(["agent:ops:main", "main"]));
@@ -193,7 +193,7 @@ describe("listSessionsFromStore search", () => {
const baseCfg = {
session: { mainKey: "main" },
agents: { list: [{ id: "main", default: true }] },
} as MoltbotConfig;
} as OpenClawConfig;
const makeStore = (): Record<string, SessionEntry> => ({
"agent:main:work-project": {
+15 -12
View File
@@ -5,7 +5,7 @@ import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent
import { lookupContextTokens } from "../agents/context.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
import { type MoltbotConfig, loadConfig } from "../config/config.js";
import { type OpenClawConfig, loadConfig } from "../config/config.js";
import { resolveStateDir } from "../config/paths.js";
import {
buildGroupDisplayName,
@@ -85,7 +85,7 @@ function isWorkspaceRelativePath(value: string): boolean {
}
function resolveIdentityAvatarUrl(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
agentId: string,
avatar: string | undefined,
): string | undefined {
@@ -211,7 +211,7 @@ function listExistingAgentIdsFromDisk(): string[] {
}
}
function listConfiguredAgentIds(cfg: MoltbotConfig): string[] {
function listConfiguredAgentIds(cfg: OpenClawConfig): string[] {
const agents = cfg.agents?.list ?? [];
if (agents.length > 0) {
const ids = new Set<string>();
@@ -239,7 +239,7 @@ function listConfiguredAgentIds(cfg: MoltbotConfig): string[] {
return sorted;
}
export function listAgentsForGateway(cfg: MoltbotConfig): {
export function listAgentsForGateway(cfg: OpenClawConfig): {
defaultId: string;
mainKey: string;
scope: SessionScope;
@@ -301,11 +301,14 @@ function canonicalizeSessionKeyForAgent(agentId: string, key: string): string {
return `agent:${normalizeAgentId(agentId)}:${key}`;
}
function resolveDefaultStoreAgentId(cfg: MoltbotConfig): string {
function resolveDefaultStoreAgentId(cfg: OpenClawConfig): string {
return normalizeAgentId(resolveDefaultAgentId(cfg));
}
export function resolveSessionStoreKey(params: { cfg: MoltbotConfig; sessionKey: string }): string {
export function resolveSessionStoreKey(params: {
cfg: OpenClawConfig;
sessionKey: string;
}): string {
const raw = params.sessionKey.trim();
if (!raw) return raw;
if (raw === "global" || raw === "unknown") return raw;
@@ -330,7 +333,7 @@ export function resolveSessionStoreKey(params: { cfg: MoltbotConfig; sessionKey:
return canonicalizeSessionKeyForAgent(agentId, raw);
}
function resolveSessionStoreAgentId(cfg: MoltbotConfig, canonicalKey: string): string {
function resolveSessionStoreAgentId(cfg: OpenClawConfig, canonicalKey: string): string {
if (canonicalKey === "global" || canonicalKey === "unknown") {
return resolveDefaultStoreAgentId(cfg);
}
@@ -347,7 +350,7 @@ function canonicalizeSpawnedByForAgent(agentId: string, spawnedBy?: string): str
return `agent:${normalizeAgentId(agentId)}:${raw}`;
}
export function resolveGatewaySessionStoreTarget(params: { cfg: MoltbotConfig; key: string }): {
export function resolveGatewaySessionStoreTarget(params: { cfg: OpenClawConfig; key: string }): {
agentId: string;
storePath: string;
canonicalKey: string;
@@ -403,7 +406,7 @@ function mergeSessionEntryIntoCombined(params: {
}
}
export function loadCombinedSessionStoreForGateway(cfg: MoltbotConfig): {
export function loadCombinedSessionStoreForGateway(cfg: OpenClawConfig): {
storePath: string;
store: Record<string, SessionEntry>;
} {
@@ -446,7 +449,7 @@ export function loadCombinedSessionStoreForGateway(cfg: MoltbotConfig): {
return { storePath, store: combined };
}
export function getSessionDefaults(cfg: MoltbotConfig): GatewaySessionsDefaults {
export function getSessionDefaults(cfg: OpenClawConfig): GatewaySessionsDefaults {
const resolved = resolveConfiguredModelRef({
cfg,
defaultProvider: DEFAULT_PROVIDER,
@@ -464,7 +467,7 @@ export function getSessionDefaults(cfg: MoltbotConfig): GatewaySessionsDefaults
}
export function resolveSessionModelRef(
cfg: MoltbotConfig,
cfg: OpenClawConfig,
entry?: SessionEntry,
): { provider: string; model: string } {
const resolved = resolveConfiguredModelRef({
@@ -483,7 +486,7 @@ export function resolveSessionModelRef(
}
export function listSessionsFromStore(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
storePath: string;
store: Record<string, SessionEntry>;
opts: import("./protocol/index.js").SessionsListParams;
+6 -6
View File
@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { SessionEntry } from "../config/sessions.js";
import { applySessionsPatchToStore } from "./sessions-patch.js";
@@ -7,7 +7,7 @@ describe("gateway sessions patch", () => {
test("persists elevatedLevel=off (does not clear)", async () => {
const store: Record<string, SessionEntry> = {};
const res = await applySessionsPatchToStore({
cfg: {} as MoltbotConfig,
cfg: {} as OpenClawConfig,
store,
storeKey: "agent:main:main",
patch: { elevatedLevel: "off" },
@@ -20,7 +20,7 @@ describe("gateway sessions patch", () => {
test("persists elevatedLevel=on", async () => {
const store: Record<string, SessionEntry> = {};
const res = await applySessionsPatchToStore({
cfg: {} as MoltbotConfig,
cfg: {} as OpenClawConfig,
store,
storeKey: "agent:main:main",
patch: { elevatedLevel: "on" },
@@ -35,7 +35,7 @@ describe("gateway sessions patch", () => {
"agent:main:main": { elevatedLevel: "off" } as SessionEntry,
};
const res = await applySessionsPatchToStore({
cfg: {} as MoltbotConfig,
cfg: {} as OpenClawConfig,
store,
storeKey: "agent:main:main",
patch: { elevatedLevel: null },
@@ -48,7 +48,7 @@ describe("gateway sessions patch", () => {
test("rejects invalid elevatedLevel values", async () => {
const store: Record<string, SessionEntry> = {};
const res = await applySessionsPatchToStore({
cfg: {} as MoltbotConfig,
cfg: {} as OpenClawConfig,
store,
storeKey: "agent:main:main",
patch: { elevatedLevel: "maybe" },
@@ -71,7 +71,7 @@ describe("gateway sessions patch", () => {
} as SessionEntry,
};
const res = await applySessionsPatchToStore({
cfg: {} as MoltbotConfig,
cfg: {} as OpenClawConfig,
store,
storeKey: "agent:main:main",
patch: { model: "openai/gpt-5.2" },
+2 -2
View File
@@ -13,7 +13,7 @@ import {
normalizeUsageDisplay,
supportsXHighThinking,
} from "../auto-reply/thinking.js";
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import type { SessionEntry } from "../config/sessions.js";
import { isSubagentSessionKey } from "../routing/session-key.js";
import { applyVerboseOverride, parseVerboseOverride } from "../sessions/level-overrides.js";
@@ -56,7 +56,7 @@ function normalizeExecAsk(raw: string): "off" | "on-miss" | "always" | undefined
}
export async function applySessionsPatchToStore(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
store: Record<string, SessionEntry>;
storeKey: string;
patch: SessionsPatchParams;
+2 -2
View File
@@ -1,4 +1,4 @@
import type { MoltbotConfig } from "../config/config.js";
import type { OpenClawConfig } from "../config/config.js";
import { loadSessionStore } from "../config/sessions.js";
import { parseSessionLabel } from "../sessions/session-label.js";
import {
@@ -16,7 +16,7 @@ import {
export type SessionsResolveResult = { ok: true; key: string } | { ok: false; error: ErrorShape };
export function resolveSessionKeyFromResolveParams(params: {
cfg: MoltbotConfig;
cfg: OpenClawConfig;
p: SessionsResolveParams;
}): SessionsResolveResult {
const { cfg, p } = params;
+8 -6
View File
@@ -188,12 +188,12 @@ export const resetTestPluginRegistry = () => {
};
const testConfigRoot = {
value: path.join(os.tmpdir(), `moltbot-gateway-test-${process.pid}-${crypto.randomUUID()}`),
value: path.join(os.tmpdir(), `openclaw-gateway-test-${process.pid}-${crypto.randomUUID()}`),
};
export const setTestConfigRoot = (root: string) => {
testConfigRoot.value = root;
process.env.CLAWDBOT_CONFIG_PATH = path.join(root, "moltbot.json");
process.env.OPENCLAW_CONFIG_PATH = path.join(root, "openclaw.json");
};
export const testTailnetIPv4 = hoisted.testTailnetIPv4;
@@ -271,7 +271,7 @@ vi.mock("../config/sessions.js", async () => {
vi.mock("../config/config.js", async () => {
const actual = await vi.importActual<typeof import("../config/config.js")>("../config/config.js");
const resolveConfigPath = () => path.join(testConfigRoot.value, "moltbot.json");
const resolveConfigPath = () => path.join(testConfigRoot.value, "openclaw.json");
const hashConfigRaw = (raw: string | null) =>
crypto
.createHash("sha256")
@@ -389,7 +389,7 @@ vi.mock("../config/config.js", async () => {
: {};
const defaults = {
model: { primary: "anthropic/claude-opus-4-5" },
workspace: path.join(os.tmpdir(), "clawd-gateway-test"),
workspace: path.join(os.tmpdir(), "openclaw-gateway-test"),
...fileDefaults,
...testState.agentConfig,
};
@@ -560,5 +560,7 @@ vi.mock("../cli/deps.js", async () => {
};
});
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
process.env.CLAWDBOT_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
process.env.OPENCLAW_SKIP_CHANNELS = "1";
process.env.OPENCLAW_SKIP_CRON = "1";
+28 -28
View File
@@ -78,22 +78,22 @@ export async function writeSessionStore(params: {
async function setupGatewayTestHome() {
previousHome = process.env.HOME;
previousUserProfile = process.env.USERPROFILE;
previousStateDir = process.env.CLAWDBOT_STATE_DIR;
previousConfigPath = process.env.CLAWDBOT_CONFIG_PATH;
previousSkipBrowserControl = process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER;
previousSkipGmailWatcher = process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
previousSkipCanvasHost = process.env.CLAWDBOT_SKIP_CANVAS_HOST;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-gateway-home-"));
previousStateDir = process.env.OPENCLAW_STATE_DIR;
previousConfigPath = process.env.OPENCLAW_CONFIG_PATH;
previousSkipBrowserControl = process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER;
previousSkipGmailWatcher = process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
previousSkipCanvasHost = process.env.OPENCLAW_SKIP_CANVAS_HOST;
tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-home-"));
process.env.HOME = tempHome;
process.env.USERPROFILE = tempHome;
process.env.CLAWDBOT_STATE_DIR = path.join(tempHome, ".clawdbot");
delete process.env.CLAWDBOT_CONFIG_PATH;
process.env.OPENCLAW_STATE_DIR = path.join(tempHome, ".openclaw");
delete process.env.OPENCLAW_CONFIG_PATH;
}
function applyGatewaySkipEnv() {
process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = "1";
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = "1";
process.env.OPENCLAW_SKIP_GMAIL_WATCHER = "1";
process.env.OPENCLAW_SKIP_CANVAS_HOST = "1";
}
async function resetGatewayTestState(options: { uniqueConfigRoot: boolean }) {
@@ -105,8 +105,8 @@ async function resetGatewayTestState(options: { uniqueConfigRoot: boolean }) {
}
applyGatewaySkipEnv();
tempConfigRoot = options.uniqueConfigRoot
? await fs.mkdtemp(path.join(tempHome, "moltbot-test-"))
: path.join(tempHome, ".clawdbot-test");
? await fs.mkdtemp(path.join(tempHome, "openclaw-test-"))
: path.join(tempHome, ".openclaw-test");
setTestConfigRoot(tempConfigRoot);
sessionStoreSaveDelayMs.value = 0;
testTailnetIPv4.value = undefined;
@@ -152,17 +152,17 @@ async function cleanupGatewayTestHome(options: { restoreEnv: boolean }) {
else process.env.HOME = previousHome;
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
else process.env.USERPROFILE = previousUserProfile;
if (previousStateDir === undefined) delete process.env.CLAWDBOT_STATE_DIR;
else process.env.CLAWDBOT_STATE_DIR = previousStateDir;
if (previousConfigPath === undefined) delete process.env.CLAWDBOT_CONFIG_PATH;
else process.env.CLAWDBOT_CONFIG_PATH = previousConfigPath;
if (previousStateDir === undefined) delete process.env.OPENCLAW_STATE_DIR;
else process.env.OPENCLAW_STATE_DIR = previousStateDir;
if (previousConfigPath === undefined) delete process.env.OPENCLAW_CONFIG_PATH;
else process.env.OPENCLAW_CONFIG_PATH = previousConfigPath;
if (previousSkipBrowserControl === undefined)
delete process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER;
else process.env.CLAWDBOT_SKIP_BROWSER_CONTROL_SERVER = previousSkipBrowserControl;
if (previousSkipGmailWatcher === undefined) delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previousSkipGmailWatcher;
if (previousSkipCanvasHost === undefined) delete process.env.CLAWDBOT_SKIP_CANVAS_HOST;
else process.env.CLAWDBOT_SKIP_CANVAS_HOST = previousSkipCanvasHost;
delete process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER;
else process.env.OPENCLAW_SKIP_BROWSER_CONTROL_SERVER = previousSkipBrowserControl;
if (previousSkipGmailWatcher === undefined) delete process.env.OPENCLAW_SKIP_GMAIL_WATCHER;
else process.env.OPENCLAW_SKIP_GMAIL_WATCHER = previousSkipGmailWatcher;
if (previousSkipCanvasHost === undefined) delete process.env.OPENCLAW_SKIP_CANVAS_HOST;
else process.env.OPENCLAW_SKIP_CANVAS_HOST = previousSkipCanvasHost;
}
if (options.restoreEnv && tempHome) {
await fs.rm(tempHome, {
@@ -259,7 +259,7 @@ export async function startGatewayServer(port: number, opts?: GatewayServerOptio
export async function startServerWithClient(token?: string, opts?: GatewayServerOptions) {
let port = await getFreePort();
const prev = process.env.CLAWDBOT_GATEWAY_TOKEN;
const prev = process.env.OPENCLAW_GATEWAY_TOKEN;
if (typeof token === "string") {
testState.gatewayAuth = { mode: "token", token };
}
@@ -269,9 +269,9 @@ export async function startServerWithClient(token?: string, opts?: GatewayServer
? (testState.gatewayAuth as { token?: string }).token
: undefined);
if (fallbackToken === undefined) {
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
} else {
process.env.CLAWDBOT_GATEWAY_TOKEN = fallbackToken;
process.env.OPENCLAW_GATEWAY_TOKEN = fallbackToken;
}
let server: Awaited<ReturnType<typeof startGatewayServer>> | null = null;
@@ -348,13 +348,13 @@ export async function connectReq(
? undefined
: typeof (testState.gatewayAuth as { token?: unknown } | undefined)?.token === "string"
? ((testState.gatewayAuth as { token?: string }).token ?? undefined)
: process.env.CLAWDBOT_GATEWAY_TOKEN;
: process.env.OPENCLAW_GATEWAY_TOKEN;
const defaultPassword =
opts?.skipDefaultAuth === true
? undefined
: typeof (testState.gatewayAuth as { password?: unknown } | undefined)?.password === "string"
? ((testState.gatewayAuth as { password?: string }).password ?? undefined)
: process.env.CLAWDBOT_GATEWAY_PASSWORD;
: process.env.OPENCLAW_GATEWAY_PASSWORD;
const token = opts?.token ?? defaultToken;
const password = opts?.password ?? defaultPassword;
const requestedScopes = Array.isArray(opts?.scopes) ? opts?.scopes : [];
+2 -2
View File
@@ -13,8 +13,8 @@ installGatewayTestHooks({ scope: "suite" });
beforeEach(() => {
// Ensure these tests are not affected by host env vars.
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
delete process.env.CLAWDBOT_GATEWAY_PASSWORD;
delete process.env.OPENCLAW_GATEWAY_TOKEN;
delete process.env.OPENCLAW_GATEWAY_PASSWORD;
});
const resolveGatewayToken = (): string => {
+6 -4
View File
@@ -1,6 +1,6 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import { createMoltbotTools } from "../agents/moltbot-tools.js";
import { createOpenClawTools } from "../agents/openclaw-tools.js";
import {
filterToolsByPolicy,
resolveEffectiveToolPolicy,
@@ -156,8 +156,10 @@ export async function handleToolsInvokeHttpRequest(
!rawSessionKey || rawSessionKey === "main" ? resolveMainSessionKey(cfg) : rawSessionKey;
// Resolve message channel/account hints (optional headers) for policy inheritance.
const messageChannel = normalizeMessageChannel(getHeader(req, "x-moltbot-message-channel") ?? "");
const accountId = getHeader(req, "x-moltbot-account-id")?.trim() || undefined;
const messageChannel = normalizeMessageChannel(
getHeader(req, "x-openclaw-message-channel") ?? "",
);
const accountId = getHeader(req, "x-openclaw-account-id")?.trim() || undefined;
const {
agentId,
@@ -194,7 +196,7 @@ export async function handleToolsInvokeHttpRequest(
: undefined;
// Build tool list (core + plugin tools).
const allTools = createMoltbotTools({
const allTools = createOpenClawTools({
agentSessionKey: sessionKey,
agentChannel: messageChannel ?? undefined,
agentAccountId: accountId,