mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 05:41:24 +00:00
refactor: rename to openclaw
This commit is contained in:
@@ -3,12 +3,13 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { LEGACY_CANVAS_HANDLER_NAME } from "../compat/legacy-names.js";
|
||||
import { detectMime } from "../media/mime.js";
|
||||
|
||||
export const A2UI_PATH = "/__moltbot__/a2ui";
|
||||
export const CANVAS_HOST_PATH = "/__moltbot__/canvas";
|
||||
export const CANVAS_WS_PATH = "/__moltbot/ws";
|
||||
export const A2UI_PATH = "/__openclaw__/a2ui";
|
||||
|
||||
export const CANVAS_HOST_PATH = "/__openclaw__/canvas";
|
||||
|
||||
export const CANVAS_WS_PATH = "/__openclaw__/ws";
|
||||
|
||||
let cachedA2uiRootReal: string | null | undefined;
|
||||
let resolvingA2uiRoot: Promise<string | null> | null = null;
|
||||
@@ -92,15 +93,14 @@ async function resolveA2uiFilePath(rootReal: string, urlPath: string) {
|
||||
}
|
||||
|
||||
export function injectCanvasLiveReload(html: string): string {
|
||||
const legacyHandlerName = LEGACY_CANVAS_HANDLER_NAME;
|
||||
const snippet = `
|
||||
<script>
|
||||
(() => {
|
||||
// Cross-platform action bridge helper.
|
||||
// Works on:
|
||||
// - iOS: window.webkit.messageHandlers.(current|legacy)CanvasA2UIAction.postMessage(...)
|
||||
// - Android: window.(current|legacy)CanvasA2UIAction.postMessage(...)
|
||||
const handlerNames = ["moltbotCanvasA2UIAction", "${legacyHandlerName}"];
|
||||
// - iOS: window.webkit.messageHandlers.openclawCanvasA2UIAction.postMessage(...)
|
||||
// - Android: window.openclawCanvasA2UIAction.postMessage(...)
|
||||
const handlerNames = ["openclawCanvasA2UIAction"];
|
||||
function postToNode(payload) {
|
||||
try {
|
||||
const raw = typeof payload === "string" ? payload : JSON.stringify(payload);
|
||||
@@ -127,13 +127,11 @@ export function injectCanvasLiveReload(html: string): string {
|
||||
const action = { ...userAction, id };
|
||||
return postToNode({ userAction: action });
|
||||
}
|
||||
globalThis.Moltbot = globalThis.Moltbot ?? {};
|
||||
globalThis.Moltbot.postMessage = postToNode;
|
||||
globalThis.Moltbot.sendUserAction = sendUserAction;
|
||||
globalThis.moltbotPostMessage = postToNode;
|
||||
globalThis.moltbotSendUserAction = sendUserAction;
|
||||
globalThis.clawdbotPostMessage = postToNode;
|
||||
globalThis.clawdbotSendUserAction = sendUserAction;
|
||||
globalThis.OpenClaw = globalThis.OpenClaw ?? {};
|
||||
globalThis.OpenClaw.postMessage = postToNode;
|
||||
globalThis.OpenClaw.sendUserAction = sendUserAction;
|
||||
globalThis.openclawPostMessage = postToNode;
|
||||
globalThis.openclawSendUserAction = sendUserAction;
|
||||
|
||||
try {
|
||||
const proto = location.protocol === "https:" ? "wss" : "ws";
|
||||
@@ -161,9 +159,9 @@ export async function handleA2uiHttpRequest(
|
||||
if (!urlRaw) return false;
|
||||
|
||||
const url = new URL(urlRaw, "http://localhost");
|
||||
if (url.pathname !== A2UI_PATH && !url.pathname.startsWith(`${A2UI_PATH}/`)) {
|
||||
return false;
|
||||
}
|
||||
const basePath =
|
||||
url.pathname === A2UI_PATH || url.pathname.startsWith(`${A2UI_PATH}/`) ? A2UI_PATH : undefined;
|
||||
if (!basePath) return false;
|
||||
|
||||
if (req.method !== "GET" && req.method !== "HEAD") {
|
||||
res.statusCode = 405;
|
||||
@@ -180,7 +178,7 @@ export async function handleA2uiHttpRequest(
|
||||
return true;
|
||||
}
|
||||
|
||||
const rel = url.pathname.slice(A2UI_PATH.length);
|
||||
const rel = url.pathname.slice(basePath.length);
|
||||
const filePath = await resolveA2uiFilePath(a2uiRootReal, rel || "/");
|
||||
if (!filePath) {
|
||||
res.statusCode = 404;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Moltbot Canvas</title>
|
||||
<title>OpenClaw Canvas</title>
|
||||
<script>
|
||||
(() => {
|
||||
try {
|
||||
@@ -81,7 +81,7 @@
|
||||
backface-visibility: hidden;
|
||||
opacity: 0.45;
|
||||
pointer-events: none;
|
||||
animation: moltbot-grid-drift 140s ease-in-out infinite alternate;
|
||||
animation: openclaw-grid-drift 140s ease-in-out infinite alternate;
|
||||
}
|
||||
:root[data-platform="android"] body::before {
|
||||
opacity: 0.8;
|
||||
@@ -101,7 +101,7 @@
|
||||
backface-visibility: hidden;
|
||||
transform: translate3d(0, 0, 0);
|
||||
pointer-events: none;
|
||||
animation: moltbot-glow-drift 110s ease-in-out infinite alternate;
|
||||
animation: openclaw-glow-drift 110s ease-in-out infinite alternate;
|
||||
}
|
||||
:root[data-platform="android"] body::after {
|
||||
opacity: 0.85;
|
||||
@@ -116,7 +116,7 @@
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
@keyframes moltbot-grid-drift {
|
||||
@keyframes openclaw-grid-drift {
|
||||
0% {
|
||||
transform: translate3d(-12px, 8px, 0) rotate(-7deg);
|
||||
opacity: 0.4;
|
||||
@@ -130,7 +130,7 @@
|
||||
opacity: 0.42;
|
||||
}
|
||||
}
|
||||
@keyframes moltbot-glow-drift {
|
||||
@keyframes openclaw-glow-drift {
|
||||
0% {
|
||||
transform: translate3d(-18px, 12px, 0) scale(1.02);
|
||||
opacity: 0.4;
|
||||
@@ -153,14 +153,14 @@
|
||||
touch-action: none;
|
||||
z-index: 1;
|
||||
}
|
||||
:root[data-platform="android"] #moltbot-canvas {
|
||||
:root[data-platform="android"] #openclaw-canvas {
|
||||
background:
|
||||
radial-gradient(1100px 800px at 20% 15%, rgba(42, 113, 255, 0.78), rgba(0, 0, 0, 0) 58%),
|
||||
radial-gradient(900px 650px at 82% 28%, rgba(255, 0, 138, 0.66), rgba(0, 0, 0, 0) 62%),
|
||||
radial-gradient(1000px 900px at 60% 88%, rgba(0, 209, 255, 0.58), rgba(0, 0, 0, 0) 62%),
|
||||
#141c33;
|
||||
}
|
||||
#moltbot-status {
|
||||
#openclaw-status {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: none;
|
||||
@@ -172,7 +172,7 @@
|
||||
pointer-events: none;
|
||||
z-index: 3;
|
||||
}
|
||||
#moltbot-status .card {
|
||||
#openclaw-status .card {
|
||||
width: min(560px, 88vw);
|
||||
text-align: left;
|
||||
padding: 14px 16px 12px;
|
||||
@@ -185,7 +185,7 @@
|
||||
-webkit-backdrop-filter: blur(18px) saturate(140%);
|
||||
backdrop-filter: blur(18px) saturate(140%);
|
||||
}
|
||||
#moltbot-status .title {
|
||||
#openclaw-status .title {
|
||||
font:
|
||||
600 12px/1.2 -apple-system,
|
||||
BlinkMacSystemFont,
|
||||
@@ -196,7 +196,7 @@
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
#moltbot-status .subtitle {
|
||||
#openclaw-status .subtitle {
|
||||
margin-top: 8px;
|
||||
font:
|
||||
500 13px/1.45 -apple-system,
|
||||
@@ -208,39 +208,39 @@
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
moltbot-a2ui-host {
|
||||
openclaw-a2ui-host {
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 4;
|
||||
--moltbot-a2ui-inset-top: 28px;
|
||||
--moltbot-a2ui-inset-right: 0px;
|
||||
--moltbot-a2ui-inset-bottom: 0px;
|
||||
--moltbot-a2ui-inset-left: 0px;
|
||||
--moltbot-a2ui-scroll-pad-bottom: 0px;
|
||||
--moltbot-a2ui-status-top: calc(50% - 18px);
|
||||
--moltbot-a2ui-empty-top: 18px;
|
||||
--openclaw-a2ui-inset-top: 28px;
|
||||
--openclaw-a2ui-inset-right: 0px;
|
||||
--openclaw-a2ui-inset-bottom: 0px;
|
||||
--openclaw-a2ui-inset-left: 0px;
|
||||
--openclaw-a2ui-scroll-pad-bottom: 0px;
|
||||
--openclaw-a2ui-status-top: calc(50% - 18px);
|
||||
--openclaw-a2ui-empty-top: 18px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="moltbot-canvas"></canvas>
|
||||
<div id="moltbot-status">
|
||||
<canvas id="openclaw-canvas"></canvas>
|
||||
<div id="openclaw-status">
|
||||
<div class="card">
|
||||
<div class="title" id="moltbot-status-title">Ready</div>
|
||||
<div class="subtitle" id="moltbot-status-subtitle">Waiting for agent</div>
|
||||
<div class="title" id="openclaw-status-title">Ready</div>
|
||||
<div class="subtitle" id="openclaw-status-subtitle">Waiting for agent</div>
|
||||
</div>
|
||||
</div>
|
||||
<moltbot-a2ui-host></moltbot-a2ui-host>
|
||||
<openclaw-a2ui-host></openclaw-a2ui-host>
|
||||
<script src="a2ui.bundle.js"></script>
|
||||
<script>
|
||||
(() => {
|
||||
const canvas = document.getElementById("moltbot-canvas");
|
||||
const canvas = document.getElementById("openclaw-canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
const statusEl = document.getElementById("moltbot-status");
|
||||
const titleEl = document.getElementById("moltbot-status-title");
|
||||
const subtitleEl = document.getElementById("moltbot-status-subtitle");
|
||||
const statusEl = document.getElementById("openclaw-status");
|
||||
const titleEl = document.getElementById("openclaw-status-title");
|
||||
const subtitleEl = document.getElementById("openclaw-status-subtitle");
|
||||
const debugStatusEnabledByQuery = (() => {
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -278,7 +278,7 @@
|
||||
statusEl.style.display = "none";
|
||||
}
|
||||
|
||||
window.__moltbot = {
|
||||
window.__openclaw = {
|
||||
canvas,
|
||||
ctx,
|
||||
setDebugStatusEnabled,
|
||||
|
||||
@@ -15,12 +15,12 @@ describe("canvas host", () => {
|
||||
const out = injectCanvasLiveReload("<html><body>Hello</body></html>");
|
||||
expect(out).toContain(CANVAS_WS_PATH);
|
||||
expect(out).toContain("location.reload");
|
||||
expect(out).toContain("moltbotCanvasA2UIAction");
|
||||
expect(out).toContain("moltbotSendUserAction");
|
||||
expect(out).toContain("openclawCanvasA2UIAction");
|
||||
expect(out).toContain("openclawSendUserAction");
|
||||
});
|
||||
|
||||
it("creates a default index.html when missing", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
|
||||
const server = await startCanvasHost({
|
||||
runtime: defaultRuntime,
|
||||
@@ -35,7 +35,7 @@ describe("canvas host", () => {
|
||||
const html = await res.text();
|
||||
expect(res.status).toBe(200);
|
||||
expect(html).toContain("Interactive test page");
|
||||
expect(html).toContain("moltbotSendUserAction");
|
||||
expect(html).toContain("openclawSendUserAction");
|
||||
expect(html).toContain(CANVAS_WS_PATH);
|
||||
} finally {
|
||||
await server.close();
|
||||
@@ -44,7 +44,7 @@ describe("canvas host", () => {
|
||||
});
|
||||
|
||||
it("skips live reload injection when disabled", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
await fs.writeFile(path.join(dir, "index.html"), "<html><body>no-reload</body></html>", "utf8");
|
||||
|
||||
const server = await startCanvasHost({
|
||||
@@ -72,7 +72,7 @@ describe("canvas host", () => {
|
||||
});
|
||||
|
||||
it("serves canvas content from the mounted base path", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
await fs.writeFile(path.join(dir, "index.html"), "<html><body>v1</body></html>", "utf8");
|
||||
|
||||
const handler = await createCanvasHostHandler({
|
||||
@@ -117,7 +117,7 @@ describe("canvas host", () => {
|
||||
});
|
||||
|
||||
it("reuses a handler without closing it twice", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
await fs.writeFile(path.join(dir, "index.html"), "<html><body>v1</body></html>", "utf8");
|
||||
|
||||
const handler = await createCanvasHostHandler({
|
||||
@@ -150,7 +150,7 @@ describe("canvas host", () => {
|
||||
});
|
||||
|
||||
it("serves HTML with injection and broadcasts reload on file changes", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
const index = path.join(dir, "index.html");
|
||||
await fs.writeFile(index, "<html><body>v1</body></html>", "utf8");
|
||||
|
||||
@@ -201,7 +201,7 @@ describe("canvas host", () => {
|
||||
}, 20_000);
|
||||
|
||||
it("serves the gateway-hosted A2UI scaffold", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-canvas-"));
|
||||
const a2uiRoot = path.resolve(process.cwd(), "src/canvas-host/a2ui");
|
||||
const bundlePath = path.join(a2uiRoot, "a2ui.bundle.js");
|
||||
let createdBundle = false;
|
||||
@@ -209,7 +209,7 @@ describe("canvas host", () => {
|
||||
try {
|
||||
await fs.stat(bundlePath);
|
||||
} catch {
|
||||
await fs.writeFile(bundlePath, "window.moltbotA2UI = {};", "utf8");
|
||||
await fs.writeFile(bundlePath, "window.openclawA2UI = {};", "utf8");
|
||||
createdBundle = true;
|
||||
}
|
||||
|
||||
@@ -222,18 +222,18 @@ describe("canvas host", () => {
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await fetch(`http://127.0.0.1:${server.port}/__moltbot__/a2ui/`);
|
||||
const res = await fetch(`http://127.0.0.1:${server.port}/__openclaw__/a2ui/`);
|
||||
const html = await res.text();
|
||||
expect(res.status).toBe(200);
|
||||
expect(html).toContain("moltbot-a2ui-host");
|
||||
expect(html).toContain("moltbotCanvasA2UIAction");
|
||||
expect(html).toContain("openclaw-a2ui-host");
|
||||
expect(html).toContain("openclawCanvasA2UIAction");
|
||||
|
||||
const bundleRes = await fetch(
|
||||
`http://127.0.0.1:${server.port}/__moltbot__/a2ui/a2ui.bundle.js`,
|
||||
`http://127.0.0.1:${server.port}/__openclaw__/a2ui/a2ui.bundle.js`,
|
||||
);
|
||||
const js = await bundleRes.text();
|
||||
expect(bundleRes.status).toBe(200);
|
||||
expect(js).toContain("moltbotA2UI");
|
||||
expect(js).toContain("openclawA2UI");
|
||||
} finally {
|
||||
await server.close();
|
||||
if (createdBundle) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as fsSync from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import http, { type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
||||
import type { Socket } from "node:net";
|
||||
@@ -59,7 +60,7 @@ function defaultIndexHTML() {
|
||||
return `<!doctype html>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Moltbot Canvas</title>
|
||||
<title>OpenClaw Canvas</title>
|
||||
<style>
|
||||
html, body { height: 100%; margin: 0; background: #000; color: #fff; font: 16px/1.4 -apple-system, BlinkMacSystemFont, system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif; }
|
||||
.wrap { min-height: 100%; display: grid; place-items: center; padding: 24px; }
|
||||
@@ -77,7 +78,7 @@ function defaultIndexHTML() {
|
||||
<div class="wrap">
|
||||
<div class="card">
|
||||
<div class="title">
|
||||
<h1>Moltbot Canvas</h1>
|
||||
<h1>OpenClaw Canvas</h1>
|
||||
<div class="sub">Interactive test page (auto-reload enabled)</div>
|
||||
</div>
|
||||
|
||||
@@ -102,46 +103,35 @@ function defaultIndexHTML() {
|
||||
!!(
|
||||
window.webkit &&
|
||||
window.webkit.messageHandlers &&
|
||||
(window.webkit.messageHandlers.moltbotCanvasA2UIAction ||
|
||||
window.webkit.messageHandlers.clawdbotCanvasA2UIAction)
|
||||
window.webkit.messageHandlers.openclawCanvasA2UIAction
|
||||
);
|
||||
const hasAndroid = () =>
|
||||
!!(
|
||||
(window.moltbotCanvasA2UIAction &&
|
||||
typeof window.moltbotCanvasA2UIAction.postMessage === "function") ||
|
||||
(window.clawdbotCanvasA2UIAction &&
|
||||
typeof window.clawdbotCanvasA2UIAction.postMessage === "function")
|
||||
(window.openclawCanvasA2UIAction &&
|
||||
typeof window.openclawCanvasA2UIAction.postMessage === "function")
|
||||
);
|
||||
const legacySend = typeof window.clawdbotSendUserAction === "function" ? window.clawdbotSendUserAction : undefined;
|
||||
if (!window.moltbotSendUserAction && legacySend) {
|
||||
window.moltbotSendUserAction = legacySend;
|
||||
}
|
||||
if (!window.clawdbotSendUserAction && typeof window.moltbotSendUserAction === "function") {
|
||||
window.clawdbotSendUserAction = window.moltbotSendUserAction;
|
||||
}
|
||||
const hasHelper = () =>
|
||||
typeof window.moltbotSendUserAction === "function" ||
|
||||
typeof window.clawdbotSendUserAction === "function";
|
||||
const hasHelper = () => typeof window.openclawSendUserAction === "function";
|
||||
statusEl.innerHTML =
|
||||
"Bridge: " +
|
||||
(hasHelper() ? "<span class='ok'>ready</span>" : "<span class='bad'>missing</span>") +
|
||||
" · iOS=" + (hasIOS() ? "yes" : "no") +
|
||||
" · Android=" + (hasAndroid() ? "yes" : "no");
|
||||
|
||||
window.addEventListener("moltbot:a2ui-action-status", (ev) => {
|
||||
const onStatus = (ev) => {
|
||||
const d = ev && ev.detail || {};
|
||||
log("Action status: id=" + (d.id || "?") + " ok=" + String(!!d.ok) + (d.error ? (" error=" + d.error) : ""));
|
||||
});
|
||||
};
|
||||
window.addEventListener("openclaw:a2ui-action-status", onStatus);
|
||||
|
||||
function send(name, sourceComponentId) {
|
||||
if (!hasHelper()) {
|
||||
log("No action bridge found. Ensure you're viewing this on an iOS/Android Moltbot node canvas.");
|
||||
log("No action bridge found. Ensure you're viewing this on an iOS/Android OpenClaw node canvas.");
|
||||
return;
|
||||
}
|
||||
const sendUserAction =
|
||||
typeof window.moltbotSendUserAction === "function"
|
||||
? window.moltbotSendUserAction
|
||||
: window.clawdbotSendUserAction;
|
||||
typeof window.openclawSendUserAction === "function"
|
||||
? window.openclawSendUserAction
|
||||
: undefined;
|
||||
const ok = sendUserAction({
|
||||
name,
|
||||
surfaceId: "main",
|
||||
@@ -199,7 +189,8 @@ async function resolveFilePath(rootReal: string, urlPath: string) {
|
||||
}
|
||||
|
||||
function isDisabledByEnv() {
|
||||
if (isTruthyEnvValue(process.env.CLAWDBOT_SKIP_CANVAS_HOST)) return true;
|
||||
if (isTruthyEnvValue(process.env.OPENCLAW_SKIP_CANVAS_HOST)) return true;
|
||||
if (isTruthyEnvValue(process.env.OPENCLAW_SKIP_CANVAS_HOST)) return true;
|
||||
if (process.env.NODE_ENV === "test") return true;
|
||||
if (process.env.VITEST) return true;
|
||||
return false;
|
||||
@@ -228,6 +219,18 @@ async function prepareCanvasRoot(rootDir: string) {
|
||||
return rootReal;
|
||||
}
|
||||
|
||||
function resolveDefaultCanvasRoot(): string {
|
||||
const candidates = [path.join(os.homedir(), ".openclaw", "canvas")];
|
||||
const existing = candidates.find((dir) => {
|
||||
try {
|
||||
return fsSync.statSync(dir).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return existing ?? candidates[0];
|
||||
}
|
||||
|
||||
export async function createCanvasHostHandler(
|
||||
opts: CanvasHostHandlerOpts,
|
||||
): Promise<CanvasHostHandler> {
|
||||
@@ -242,7 +245,7 @@ export async function createCanvasHostHandler(
|
||||
};
|
||||
}
|
||||
|
||||
const rootDir = resolveUserPath(opts.rootDir ?? path.join(os.homedir(), "clawd", "canvas"));
|
||||
const rootDir = resolveUserPath(opts.rootDir ?? resolveDefaultCanvasRoot());
|
||||
const rootReal = await prepareCanvasRoot(rootDir);
|
||||
|
||||
const liveReload = opts.liveReload !== false;
|
||||
@@ -322,13 +325,8 @@ export async function createCanvasHostHandler(
|
||||
|
||||
let urlPath = url.pathname;
|
||||
if (basePath !== "/") {
|
||||
if (urlPath === basePath) {
|
||||
urlPath = "/";
|
||||
} else if (urlPath.startsWith(`${basePath}/`)) {
|
||||
urlPath = urlPath.slice(basePath.length) || "/";
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (urlPath !== basePath && !urlPath.startsWith(`${basePath}/`)) return false;
|
||||
urlPath = urlPath === basePath ? "/" : urlPath.slice(basePath.length) || "/";
|
||||
}
|
||||
|
||||
if (req.method !== "GET" && req.method !== "HEAD") {
|
||||
@@ -344,7 +342,7 @@ export async function createCanvasHostHandler(
|
||||
res.statusCode = 404;
|
||||
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
||||
res.end(
|
||||
`<!doctype html><meta charset="utf-8" /><title>Moltbot Canvas</title><pre>Missing file.\nCreate ${rootDir}/index.html</pre>`,
|
||||
`<!doctype html><meta charset="utf-8" /><title>OpenClaw Canvas</title><pre>Missing file.\nCreate ${rootDir}/index.html</pre>`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user