mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 19:01:47 +03:00
refactor: rename to openclaw
This commit is contained in:
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)}`);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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"]({
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,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(),
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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)`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 }] };
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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" }),
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 } };
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 : [];
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user