refactor: rename to openclaw

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

View File

@@ -3,12 +3,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Moltbot Control</title>
<title>OpenClaw Control</title>
<meta name="color-scheme" content="dark light" />
<link rel="icon" href="/favicon.ico" sizes="any" />
</head>
<body>
<moltbot-app></moltbot-app>
<openclaw-app></openclaw-app>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,5 +1,5 @@
{
"name": "moltbot-control-ui",
"name": "openclaw-control-ui",
"private": true,
"type": "module",
"scripts": {

View File

@@ -239,7 +239,7 @@ html.theme-transition::view-transition-new(theme) {
}
}
moltbot-app {
openclaw-app {
display: block;
position: relative;
z-index: 1;

View File

@@ -5,32 +5,32 @@ import {
waitWhatsAppLogin,
} from "./controllers/channels";
import { loadConfig, saveConfig } from "./controllers/config";
import type { MoltbotApp } from "./app";
import type { OpenClawApp } from "./app";
import type { NostrProfile } from "./types";
import { createNostrProfileFormState } from "./views/channels.nostr-profile-form";
export async function handleWhatsAppStart(host: MoltbotApp, force: boolean) {
export async function handleWhatsAppStart(host: OpenClawApp, force: boolean) {
await startWhatsAppLogin(host, force);
await loadChannels(host, true);
}
export async function handleWhatsAppWait(host: MoltbotApp) {
export async function handleWhatsAppWait(host: OpenClawApp) {
await waitWhatsAppLogin(host);
await loadChannels(host, true);
}
export async function handleWhatsAppLogout(host: MoltbotApp) {
export async function handleWhatsAppLogout(host: OpenClawApp) {
await logoutWhatsApp(host);
await loadChannels(host, true);
}
export async function handleChannelConfigSave(host: MoltbotApp) {
export async function handleChannelConfigSave(host: OpenClawApp) {
await saveConfig(host);
await loadConfig(host);
await loadChannels(host, true);
}
export async function handleChannelConfigReload(host: MoltbotApp) {
export async function handleChannelConfigReload(host: OpenClawApp) {
await loadConfig(host);
await loadChannels(host, true);
}
@@ -49,7 +49,7 @@ function parseValidationErrors(details: unknown): Record<string, string> {
return errors;
}
function resolveNostrAccountId(host: MoltbotApp): string {
function resolveNostrAccountId(host: OpenClawApp): string {
const accounts = host.channelsSnapshot?.channelAccounts?.nostr ?? [];
return accounts[0]?.accountId ?? host.nostrProfileAccountId ?? "default";
}
@@ -59,7 +59,7 @@ function buildNostrProfileUrl(accountId: string, suffix = ""): string {
}
export function handleNostrProfileEdit(
host: MoltbotApp,
host: OpenClawApp,
accountId: string,
profile: NostrProfile | null,
) {
@@ -67,13 +67,13 @@ export function handleNostrProfileEdit(
host.nostrProfileFormState = createNostrProfileFormState(profile ?? undefined);
}
export function handleNostrProfileCancel(host: MoltbotApp) {
export function handleNostrProfileCancel(host: OpenClawApp) {
host.nostrProfileFormState = null;
host.nostrProfileAccountId = null;
}
export function handleNostrProfileFieldChange(
host: MoltbotApp,
host: OpenClawApp,
field: keyof NostrProfile,
value: string,
) {
@@ -92,7 +92,7 @@ export function handleNostrProfileFieldChange(
};
}
export function handleNostrProfileToggleAdvanced(host: MoltbotApp) {
export function handleNostrProfileToggleAdvanced(host: OpenClawApp) {
const state = host.nostrProfileFormState;
if (!state) return;
host.nostrProfileFormState = {
@@ -101,7 +101,7 @@ export function handleNostrProfileToggleAdvanced(host: MoltbotApp) {
};
}
export async function handleNostrProfileSave(host: MoltbotApp) {
export async function handleNostrProfileSave(host: OpenClawApp) {
const state = host.nostrProfileFormState;
if (!state || state.saving) return;
const accountId = resolveNostrAccountId(host);
@@ -167,7 +167,7 @@ export async function handleNostrProfileSave(host: MoltbotApp) {
}
}
export async function handleNostrProfileImport(host: MoltbotApp) {
export async function handleNostrProfileImport(host: OpenClawApp) {
const state = host.nostrProfileFormState;
if (!state || state.importing) return;
const accountId = resolveNostrAccountId(host);

View File

@@ -7,7 +7,7 @@ import { setLastActiveSessionKey } from "./app-settings";
import { normalizeBasePath } from "./navigation";
import type { GatewayHelloOk } from "./gateway";
import { parseAgentSessionKey } from "../../../src/sessions/session-key-utils.js";
import type { MoltbotApp } from "./app";
import type { OpenClawApp } from "./app";
import type { ChatAttachment, ChatQueueItem } from "./ui-types";
type ChatHost = {
@@ -53,7 +53,7 @@ function isChatResetCommand(text: string) {
export async function handleAbortChat(host: ChatHost) {
if (!host.connected) return;
host.chatMessage = "";
await abortChatRun(host as unknown as MoltbotApp);
await abortChatRun(host as unknown as OpenClawApp);
}
function enqueueChatMessage(host: ChatHost, text: string, attachments?: ChatAttachment[]) {
@@ -84,7 +84,7 @@ async function sendChatMessageNow(
},
) {
resetToolStream(host as unknown as Parameters<typeof resetToolStream>[0]);
const ok = await sendChatMessage(host as unknown as MoltbotApp, message, opts?.attachments);
const ok = await sendChatMessage(host as unknown as OpenClawApp, message, opts?.attachments);
if (!ok && opts?.previousDraft != null) {
host.chatMessage = opts.previousDraft;
}
@@ -169,8 +169,8 @@ export async function handleSendChat(
export async function refreshChat(host: ChatHost) {
await Promise.all([
loadChatHistory(host as unknown as MoltbotApp),
loadSessions(host as unknown as MoltbotApp, { activeMinutes: 0 }),
loadChatHistory(host as unknown as OpenClawApp),
loadSessions(host as unknown as OpenClawApp, { activeMinutes: 0 }),
refreshChatAvatar(host),
]);
scheduleChatScroll(host as unknown as Parameters<typeof scheduleChatScroll>[0], true);

View File

@@ -23,7 +23,7 @@ import {
parseExecApprovalResolved,
removeExecApproval,
} from "./controllers/exec-approval";
import type { MoltbotApp } from "./app";
import type { OpenClawApp } from "./app";
import type { ExecApprovalRequest } from "./controllers/exec-approval";
import { loadAssistantIdentity } from "./controllers/assistant-identity";
import { loadSessions } from "./controllers/sessions";
@@ -122,7 +122,7 @@ export function connectGateway(host: GatewayHost) {
url: host.settings.gatewayUrl,
token: host.settings.token.trim() ? host.settings.token : undefined,
password: host.password.trim() ? host.password : undefined,
clientName: "moltbot-control-ui",
clientName: "openclaw-control-ui",
mode: "webchat",
onHello: (hello) => {
host.connected = true;
@@ -135,10 +135,10 @@ export function connectGateway(host: GatewayHost) {
(host as unknown as { chatStream: string | null }).chatStream = null;
(host as unknown as { chatStreamStartedAt: number | null }).chatStreamStartedAt = null;
resetToolStream(host as unknown as Parameters<typeof resetToolStream>[0]);
void loadAssistantIdentity(host as unknown as MoltbotApp);
void loadAgents(host as unknown as MoltbotApp);
void loadNodes(host as unknown as MoltbotApp, { quiet: true });
void loadDevices(host as unknown as MoltbotApp, { quiet: true });
void loadAssistantIdentity(host as unknown as OpenClawApp);
void loadAgents(host as unknown as OpenClawApp);
void loadNodes(host as unknown as OpenClawApp, { quiet: true });
void loadDevices(host as unknown as OpenClawApp, { quiet: true });
void refreshActiveTab(host as unknown as Parameters<typeof refreshActiveTab>[0]);
},
onClose: ({ code, reason }) => {
@@ -190,7 +190,7 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) {
payload.sessionKey,
);
}
const state = handleChatEvent(host as unknown as MoltbotApp, payload);
const state = handleChatEvent(host as unknown as OpenClawApp, payload);
if (state === "final" || state === "error" || state === "aborted") {
resetToolStream(host as unknown as Parameters<typeof resetToolStream>[0]);
void flushChatQueueForEvent(
@@ -199,11 +199,11 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) {
if (host.refreshSessionsAfterChat) {
host.refreshSessionsAfterChat = false;
if (state === "final") {
void loadSessions(host as unknown as MoltbotApp, { activeMinutes: 0 });
void loadSessions(host as unknown as OpenClawApp, { activeMinutes: 0 });
}
}
}
if (state === "final") void loadChatHistory(host as unknown as MoltbotApp);
if (state === "final") void loadChatHistory(host as unknown as OpenClawApp);
return;
}
@@ -222,7 +222,7 @@ function handleGatewayEventUnsafe(host: GatewayHost, evt: GatewayEventFrame) {
}
if (evt.event === "device.pair.requested" || evt.event === "device.pair.resolved") {
void loadDevices(host as unknown as MoltbotApp, { quiet: true });
void loadDevices(host as unknown as OpenClawApp, { quiet: true });
}
if (evt.event === "exec.approval.requested") {

View File

@@ -1,7 +1,7 @@
import { loadLogs } from "./controllers/logs";
import { loadNodes } from "./controllers/nodes";
import { loadDebug } from "./controllers/debug";
import type { MoltbotApp } from "./app";
import type { OpenClawApp } from "./app";
type PollingHost = {
nodesPollInterval: number | null;
@@ -13,7 +13,7 @@ type PollingHost = {
export function startNodesPolling(host: PollingHost) {
if (host.nodesPollInterval != null) return;
host.nodesPollInterval = window.setInterval(
() => void loadNodes(host as unknown as MoltbotApp, { quiet: true }),
() => void loadNodes(host as unknown as OpenClawApp, { quiet: true }),
5000,
);
}
@@ -28,7 +28,7 @@ export function startLogsPolling(host: PollingHost) {
if (host.logsPollInterval != null) return;
host.logsPollInterval = window.setInterval(() => {
if (host.tab !== "logs") return;
void loadLogs(host as unknown as MoltbotApp, { quiet: true });
void loadLogs(host as unknown as OpenClawApp, { quiet: true });
}, 2000);
}
@@ -42,7 +42,7 @@ export function startDebugPolling(host: PollingHost) {
if (host.debugPollInterval != null) return;
host.debugPollInterval = window.setInterval(() => {
if (host.tab !== "debug") return;
void loadDebug(host as unknown as MoltbotApp);
void loadDebug(host as unknown as OpenClawApp);
}, 3000);
}

View File

@@ -130,10 +130,10 @@ export function renderApp(state: AppViewState) {
</button>
<div class="brand">
<div class="brand-logo">
<img src="https://mintcdn.com/clawdhub/4rYvG-uuZrMK_URE/assets/pixel-lobster.svg?fit=max&auto=format&n=4rYvG-uuZrMK_URE&q=85&s=da2032e9eac3b5d9bfe7eb96ca6a8a26" alt="Moltbot" />
<img src="https://mintcdn.com/clawdhub/4rYvG-uuZrMK_URE/assets/pixel-lobster.svg?fit=max&auto=format&n=4rYvG-uuZrMK_URE&q=85&s=da2032e9eac3b5d9bfe7eb96ca6a8a26" alt="OpenClaw" />
</div>
<div class="brand-text">
<div class="brand-title">MOLTBOT</div>
<div class="brand-title">OPENCLAW</div>
<div class="brand-sub">Gateway Dashboard</div>
</div>
</div>
@@ -181,7 +181,7 @@ export function renderApp(state: AppViewState) {
<div class="nav-group__items">
<a
class="nav-item nav-item--external"
href="https://docs.molt.bot"
href="https://docs.openclaw.ai"
target="_blank"
rel="noreferrer"
title="Docs (opens in new tab)"

View File

@@ -103,7 +103,7 @@ export function exportLogs(lines: string[], label: string) {
const anchor = document.createElement("a");
const stamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-");
anchor.href = url;
anchor.download = `moltbot-logs-${label}-${stamp}.log`;
anchor.download = `openclaw-logs-${label}-${stamp}.log`;
anchor.click();
URL.revokeObjectURL(url);
}

View File

@@ -16,7 +16,7 @@ import { startThemeTransition, type ThemeTransitionContext } from "./theme-trans
import { scheduleChatScroll, scheduleLogsScroll } from "./app-scroll";
import { startLogsPolling, stopLogsPolling, startDebugPolling, stopDebugPolling } from "./app-polling";
import { refreshChat } from "./app-chat";
import type { MoltbotApp } from "./app";
import type { OpenClawApp } from "./app";
type SettingsHost = {
settings: UiSettings;
@@ -145,15 +145,15 @@ export function setTheme(
export async function refreshActiveTab(host: SettingsHost) {
if (host.tab === "overview") await loadOverview(host);
if (host.tab === "channels") await loadChannelsTab(host);
if (host.tab === "instances") await loadPresence(host as unknown as MoltbotApp);
if (host.tab === "sessions") await loadSessions(host as unknown as MoltbotApp);
if (host.tab === "instances") await loadPresence(host as unknown as OpenClawApp);
if (host.tab === "sessions") await loadSessions(host as unknown as OpenClawApp);
if (host.tab === "cron") await loadCron(host);
if (host.tab === "skills") await loadSkills(host as unknown as MoltbotApp);
if (host.tab === "skills") await loadSkills(host as unknown as OpenClawApp);
if (host.tab === "nodes") {
await loadNodes(host as unknown as MoltbotApp);
await loadDevices(host as unknown as MoltbotApp);
await loadConfig(host as unknown as MoltbotApp);
await loadExecApprovals(host as unknown as MoltbotApp);
await loadNodes(host as unknown as OpenClawApp);
await loadDevices(host as unknown as OpenClawApp);
await loadConfig(host as unknown as OpenClawApp);
await loadExecApprovals(host as unknown as OpenClawApp);
}
if (host.tab === "chat") {
await refreshChat(host as unknown as Parameters<typeof refreshChat>[0]);
@@ -163,16 +163,16 @@ export async function refreshActiveTab(host: SettingsHost) {
);
}
if (host.tab === "config") {
await loadConfigSchema(host as unknown as MoltbotApp);
await loadConfig(host as unknown as MoltbotApp);
await loadConfigSchema(host as unknown as OpenClawApp);
await loadConfig(host as unknown as OpenClawApp);
}
if (host.tab === "debug") {
await loadDebug(host as unknown as MoltbotApp);
await loadDebug(host as unknown as OpenClawApp);
host.eventLog = host.eventLogBuffer;
}
if (host.tab === "logs") {
host.logsAtBottom = true;
await loadLogs(host as unknown as MoltbotApp, { reset: true });
await loadLogs(host as unknown as OpenClawApp, { reset: true });
scheduleLogsScroll(
host as unknown as Parameters<typeof scheduleLogsScroll>[0],
true,
@@ -182,7 +182,7 @@ export async function refreshActiveTab(host: SettingsHost) {
export function inferBasePath() {
if (typeof window === "undefined") return "";
const configured = window.__CLAWDBOT_CONTROL_UI_BASE_PATH__;
const configured = window.__OPENCLAW_CONTROL_UI_BASE_PATH__;
if (typeof configured === "string" && configured.trim()) {
return normalizeBasePath(configured);
}
@@ -308,26 +308,26 @@ export function syncUrlWithSessionKey(
export async function loadOverview(host: SettingsHost) {
await Promise.all([
loadChannels(host as unknown as MoltbotApp, false),
loadPresence(host as unknown as MoltbotApp),
loadSessions(host as unknown as MoltbotApp),
loadCronStatus(host as unknown as MoltbotApp),
loadDebug(host as unknown as MoltbotApp),
loadChannels(host as unknown as OpenClawApp, false),
loadPresence(host as unknown as OpenClawApp),
loadSessions(host as unknown as OpenClawApp),
loadCronStatus(host as unknown as OpenClawApp),
loadDebug(host as unknown as OpenClawApp),
]);
}
export async function loadChannelsTab(host: SettingsHost) {
await Promise.all([
loadChannels(host as unknown as MoltbotApp, true),
loadConfigSchema(host as unknown as MoltbotApp),
loadConfig(host as unknown as MoltbotApp),
loadChannels(host as unknown as OpenClawApp, true),
loadConfigSchema(host as unknown as OpenClawApp),
loadConfig(host as unknown as OpenClawApp),
]);
}
export async function loadCron(host: SettingsHost) {
await Promise.all([
loadChannels(host as unknown as MoltbotApp, false),
loadCronStatus(host as unknown as MoltbotApp),
loadCronJobs(host as unknown as MoltbotApp),
loadChannels(host as unknown as OpenClawApp, false),
loadCronStatus(host as unknown as OpenClawApp),
loadCronJobs(host as unknown as OpenClawApp),
]);
}

View File

@@ -81,7 +81,7 @@ import { loadAssistantIdentity as loadAssistantIdentityInternal } from "./contro
declare global {
interface Window {
__CLAWDBOT_CONTROL_UI_BASE_PATH__?: string;
__OPENCLAW_CONTROL_UI_BASE_PATH__?: string;
}
}
@@ -96,8 +96,8 @@ function resolveOnboardingMode(): boolean {
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
}
@customElement("moltbot-app")
export class MoltbotApp extends LitElement {
@customElement("openclaw-app")
export class OpenClawApp extends LitElement {
@state() settings: UiSettings = loadSettings();
@state() password = "";
@state() tab: Tab = "chat";

View File

@@ -12,8 +12,8 @@ export type AssistantIdentity = {
declare global {
interface Window {
__CLAWDBOT_ASSISTANT_NAME__?: string;
__CLAWDBOT_ASSISTANT_AVATAR__?: string;
__OPENCLAW_ASSISTANT_NAME__?: string;
__OPENCLAW_ASSISTANT_AVATAR__?: string;
}
}
@@ -43,7 +43,7 @@ export function resolveInjectedAssistantIdentity(): AssistantIdentity {
return normalizeAssistantIdentity({});
}
return normalizeAssistantIdentity({
name: window.__CLAWDBOT_ASSISTANT_NAME__,
avatar: window.__CLAWDBOT_ASSISTANT_AVATAR__,
name: window.__OPENCLAW_ASSISTANT_NAME__,
avatar: window.__OPENCLAW_ASSISTANT_AVATAR__,
});
}

View File

@@ -1,28 +1,28 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { MoltbotApp } from "./app";
import { OpenClawApp } from "./app";
const originalConnect = MoltbotApp.prototype.connect;
const originalConnect = OpenClawApp.prototype.connect;
function mountApp(pathname: string) {
window.history.replaceState({}, "", pathname);
const app = document.createElement("moltbot-app") as MoltbotApp;
const app = document.createElement("openclaw-app") as OpenClawApp;
document.body.append(app);
return app;
}
beforeEach(() => {
MoltbotApp.prototype.connect = () => {
OpenClawApp.prototype.connect = () => {
// no-op: avoid real gateway WS connections in browser tests
};
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});
afterEach(() => {
MoltbotApp.prototype.connect = originalConnect;
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
OpenClawApp.prototype.connect = originalConnect;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});

View File

@@ -163,7 +163,7 @@ export function handleChatEvent(
if (payload.sessionKey !== state.sessionKey) return null;
// Final from another run (e.g. sub-agent announce): refresh history to show new message.
// See https://github.com/moltbot/moltbot/issues/1909
// See https://github.com/openclaw/openclaw/issues/1909
if (
payload.runId &&
state.chatRunId &&

View File

@@ -142,7 +142,7 @@ describe("applyConfig", () => {
state.client = { request } as unknown as ConfigState["client"];
state.applySessionKey = "agent:main:whatsapp:dm:+15555550123";
state.configFormMode = "raw";
state.configRaw = "{\n agent: { workspace: \"~/clawd\" }\n}\n";
state.configRaw = "{\n agent: { workspace: \"~/openclaw\" }\n}\n";
state.configSnapshot = {
hash: "hash-123",
};
@@ -150,7 +150,7 @@ describe("applyConfig", () => {
await applyConfig(state);
expect(request).toHaveBeenCalledWith("config.apply", {
raw: "{\n agent: { workspace: \"~/clawd\" }\n}\n",
raw: "{\n agent: { workspace: \"~/openclaw\" }\n}\n",
baseHash: "hash-123",
sessionKey: "agent:main:whatsapp:dm:+15555550123",
});

View File

@@ -11,7 +11,7 @@ type DeviceAuthStore = {
tokens: Record<string, DeviceAuthEntry>;
};
const STORAGE_KEY = "moltbot.device.auth.v1";
const STORAGE_KEY = "openclaw.device.auth.v1";
function normalizeRole(role: string): string {
return role.trim();

View File

@@ -14,7 +14,7 @@ export type DeviceIdentity = {
privateKey: string;
};
const STORAGE_KEY = "moltbot-device-identity-v1";
const STORAGE_KEY = "openclaw-device-identity-v1";
function base64UrlEncode(bytes: Uint8Array): string {
let binary = "";

View File

@@ -1,28 +1,28 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { MoltbotApp } from "./app";
import { OpenClawApp } from "./app";
const originalConnect = MoltbotApp.prototype.connect;
const originalConnect = OpenClawApp.prototype.connect;
function mountApp(pathname: string) {
window.history.replaceState({}, "", pathname);
const app = document.createElement("moltbot-app") as MoltbotApp;
const app = document.createElement("openclaw-app") as OpenClawApp;
document.body.append(app);
return app;
}
beforeEach(() => {
MoltbotApp.prototype.connect = () => {
OpenClawApp.prototype.connect = () => {
// no-op: avoid real gateway WS connections in browser tests
};
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});
afterEach(() => {
MoltbotApp.prototype.connect = originalConnect;
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
OpenClawApp.prototype.connect = originalConnect;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});

View File

@@ -1,13 +1,13 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { MoltbotApp } from "./app";
import { OpenClawApp } from "./app";
import "../styles.css";
const originalConnect = MoltbotApp.prototype.connect;
const originalConnect = OpenClawApp.prototype.connect;
function mountApp(pathname: string) {
window.history.replaceState({}, "", pathname);
const app = document.createElement("moltbot-app") as MoltbotApp;
const app = document.createElement("openclaw-app") as OpenClawApp;
document.body.append(app);
return app;
}
@@ -19,17 +19,17 @@ function nextFrame() {
}
beforeEach(() => {
MoltbotApp.prototype.connect = () => {
OpenClawApp.prototype.connect = () => {
// no-op: avoid real gateway WS connections in browser tests
};
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});
afterEach(() => {
MoltbotApp.prototype.connect = originalConnect;
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = undefined;
OpenClawApp.prototype.connect = originalConnect;
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = undefined;
localStorage.clear();
document.body.innerHTML = "";
});
@@ -53,22 +53,22 @@ describe("control UI routing", () => {
});
it("infers nested base paths", async () => {
const app = mountApp("/apps/moltbot/cron");
const app = mountApp("/apps/openclaw/cron");
await app.updateComplete;
expect(app.basePath).toBe("/apps/moltbot");
expect(app.basePath).toBe("/apps/openclaw");
expect(app.tab).toBe("cron");
expect(window.location.pathname).toBe("/apps/moltbot/cron");
expect(window.location.pathname).toBe("/apps/openclaw/cron");
});
it("honors explicit base path overrides", async () => {
window.__CLAWDBOT_CONTROL_UI_BASE_PATH__ = "/moltbot";
const app = mountApp("/moltbot/sessions");
window.__OPENCLAW_CONTROL_UI_BASE_PATH__ = "/openclaw";
const app = mountApp("/openclaw/sessions");
await app.updateComplete;
expect(app.basePath).toBe("/moltbot");
expect(app.basePath).toBe("/openclaw");
expect(app.tab).toBe("sessions");
expect(window.location.pathname).toBe("/moltbot/sessions");
expect(window.location.pathname).toBe("/openclaw/sessions");
});
it("updates the URL when clicking nav items", async () => {
@@ -169,7 +169,7 @@ describe("control UI routing", () => {
it("hydrates token from URL params even when settings already set", async () => {
localStorage.setItem(
"moltbot.control.settings.v1",
"openclaw.control.settings.v1",
JSON.stringify({ token: "existing-token" }),
);
const app = mountApp("/ui/overview?token=abc123");

View File

@@ -73,7 +73,7 @@ describe("subtitleForTab", () => {
it("returns descriptive subtitles", () => {
expect(subtitleForTab("chat")).toContain("chat session");
expect(subtitleForTab("config")).toContain("moltbot.json");
expect(subtitleForTab("config")).toContain("openclaw.json");
});
});
@@ -95,7 +95,7 @@ describe("normalizeBasePath", () => {
});
it("handles nested paths", () => {
expect(normalizeBasePath("/apps/moltbot")).toBe("/apps/moltbot");
expect(normalizeBasePath("/apps/openclaw")).toBe("/apps/openclaw");
});
});
@@ -122,7 +122,7 @@ describe("pathForTab", () => {
it("prepends base path", () => {
expect(pathForTab("chat", "/ui")).toBe("/ui/chat");
expect(pathForTab("sessions", "/apps/moltbot")).toBe("/apps/moltbot/sessions");
expect(pathForTab("sessions", "/apps/openclaw")).toBe("/apps/openclaw/sessions");
});
});
@@ -139,7 +139,7 @@ describe("tabFromPath", () => {
it("handles base paths", () => {
expect(tabFromPath("/ui/chat", "/ui")).toBe("chat");
expect(tabFromPath("/apps/moltbot/sessions", "/apps/moltbot")).toBe("sessions");
expect(tabFromPath("/apps/openclaw/sessions", "/apps/openclaw")).toBe("sessions");
});
it("returns null for unknown path", () => {
@@ -164,7 +164,7 @@ describe("inferBasePathFromPathname", () => {
it("infers base path from nested paths", () => {
expect(inferBasePathFromPathname("/ui/chat")).toBe("/ui");
expect(inferBasePathFromPathname("/apps/moltbot/sessions")).toBe("/apps/moltbot");
expect(inferBasePathFromPathname("/apps/openclaw/sessions")).toBe("/apps/openclaw");
});
it("handles index.html suffix", () => {

View File

@@ -177,7 +177,7 @@ export function subtitleForTab(tab: Tab) {
case "chat":
return "Direct gateway chat session for quick interventions.";
case "config":
return "Edit ~/.clawdbot/moltbot.json safely.";
return "Edit ~/.openclaw/openclaw.json safely.";
case "debug":
return "Gateway snapshots, events, and manual RPC calls.";
case "logs":

View File

@@ -1,4 +1,4 @@
const KEY = "moltbot.control.settings.v1";
const KEY = "openclaw.control.settings.v1";
import type { ThemeMode } from "./theme";

View File

@@ -37,7 +37,7 @@ function createProps(overrides: Partial<ChatProps> = {}): ChatProps {
error: null,
sessions: createSessions(),
focusMode: false,
assistantName: "Moltbot",
assistantName: "OpenClaw",
assistantAvatar: null,
onRefresh: () => undefined,
onToggleFocusMode: () => undefined,

View File

@@ -55,7 +55,7 @@ export function renderDebug(props: DebugProps) {
${securitySummary
? html`<div class="callout ${securityTone}" style="margin-top: 8px;">
Security audit: ${securityLabel}${info > 0 ? ` · ${info} info` : ""}. Run
<span class="mono">moltbot security audit --deep</span> for details.
<span class="mono">openclaw security audit --deep</span> for details.
</div>`
: nothing}
<pre class="code-block">${JSON.stringify(props.status ?? {}, null, 2)}</pre>

View File

@@ -43,13 +43,13 @@ export function renderOverview(props: OverviewProps) {
<div class="muted" style="margin-top: 8px;">
This gateway requires auth. Add a token or password, then click Connect.
<div style="margin-top: 6px;">
<span class="mono">moltbot dashboard --no-open</span> → tokenized URL<br />
<span class="mono">moltbot doctor --generate-gateway-token</span> → set token
<span class="mono">openclaw dashboard --no-open</span> → tokenized URL<br />
<span class="mono">openclaw doctor --generate-gateway-token</span> → set token
</div>
<div style="margin-top: 6px;">
<a
class="session-link"
href="https://docs.molt.bot/web/dashboard"
href="https://docs.openclaw.ai/web/dashboard"
target="_blank"
rel="noreferrer"
title="Control UI auth docs (opens in new tab)"
@@ -62,12 +62,12 @@ export function renderOverview(props: OverviewProps) {
return html`
<div class="muted" style="margin-top: 8px;">
Auth failed. Re-copy a tokenized URL with
<span class="mono">moltbot dashboard --no-open</span>, or update the token,
<span class="mono">openclaw dashboard --no-open</span>, or update the token,
then click Connect.
<div style="margin-top: 6px;">
<a
class="session-link"
href="https://docs.molt.bot/web/dashboard"
href="https://docs.openclaw.ai/web/dashboard"
target="_blank"
rel="noreferrer"
title="Control UI auth docs (opens in new tab)"
@@ -96,7 +96,7 @@ export function renderOverview(props: OverviewProps) {
<div style="margin-top: 6px;">
<a
class="session-link"
href="https://docs.molt.bot/gateway/tailscale"
href="https://docs.openclaw.ai/gateway/tailscale"
target="_blank"
rel="noreferrer"
title="Tailscale Serve docs (opens in new tab)"
@@ -105,7 +105,7 @@ export function renderOverview(props: OverviewProps) {
<span class="muted"> · </span>
<a
class="session-link"
href="https://docs.molt.bot/web/control-ui#insecure-http"
href="https://docs.openclaw.ai/web/control-ui#insecure-http"
target="_blank"
rel="noreferrer"
title="Insecure HTTP docs (opens in new tab)"
@@ -141,7 +141,7 @@ export function renderOverview(props: OverviewProps) {
const v = (e.target as HTMLInputElement).value;
props.onSettingsChange({ ...props.settings, token: v });
}}
placeholder="CLAWDBOT_GATEWAY_TOKEN"
placeholder="OPENCLAW_GATEWAY_TOKEN"
/>
</label>
<label class="field">

View File

@@ -13,7 +13,7 @@ function normalizeBase(input: string): string {
}
export default defineConfig(({ command }) => {
const envBase = process.env.CLAWDBOT_CONTROL_UI_BASE_PATH?.trim();
const envBase = process.env.OPENCLAW_CONTROL_UI_BASE_PATH?.trim();
const base = envBase ? normalizeBase(envBase) : "./";
return {
base,