fix(ui): fix web UI after tsdown migration and typing changes

This commit is contained in:
Gustavo Madeira Santana
2026-02-03 13:56:20 -05:00
parent 1c4db91593
commit 5935c4d23d
24 changed files with 499 additions and 43 deletions

View File

@@ -1,8 +1,8 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { OpenClawConfig } from "../config/config.js";
import { resolveControlUiRootSync } from "../infra/control-ui-assets.js";
import { DEFAULT_ASSISTANT_IDENTITY, resolveAssistantIdentity } from "./assistant-identity.js";
import {
buildControlUiAvatarUrl,
@@ -17,34 +17,13 @@ export type ControlUiRequestOptions = {
basePath?: string;
config?: OpenClawConfig;
agentId?: string;
root?: ControlUiRootState;
};
function resolveControlUiRoot(): string | null {
const here = path.dirname(fileURLToPath(import.meta.url));
const execDir = (() => {
try {
return path.dirname(fs.realpathSync(process.execPath));
} catch {
return null;
}
})();
const candidates = [
// Packaged app: control-ui lives alongside the executable.
execDir ? path.resolve(execDir, "control-ui") : null,
// Running from dist: dist/gateway/control-ui.js -> dist/control-ui
path.resolve(here, "../control-ui"),
// Running from source: src/gateway/control-ui.ts -> dist/control-ui
path.resolve(here, "../../dist/control-ui"),
// Fallback to cwd (dev)
path.resolve(process.cwd(), "dist", "control-ui"),
].filter((dir): dir is string => Boolean(dir));
for (const dir of candidates) {
if (fs.existsSync(path.join(dir, "index.html"))) {
return dir;
}
}
return null;
}
export type ControlUiRootState =
| { kind: "resolved"; path: string }
| { kind: "invalid"; path: string }
| { kind: "missing" };
function contentTypeForExt(ext: string): string {
switch (ext) {
@@ -288,7 +267,32 @@ export function handleControlUiHttpRequest(
}
}
const root = resolveControlUiRoot();
const rootState = opts?.root;
if (rootState?.kind === "invalid") {
res.statusCode = 503;
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end(
`Control UI assets not found at ${rootState.path}. Build them with \`pnpm ui:build\` (auto-installs UI deps), or update gateway.controlUi.root.`,
);
return true;
}
if (rootState?.kind === "missing") {
res.statusCode = 503;
res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end(
"Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.",
);
return true;
}
const root =
rootState?.kind === "resolved"
? rootState.path
: resolveControlUiRootSync({
moduleUrl: import.meta.url,
argv1: process.argv[1],
cwd: process.cwd(),
});
if (!root) {
res.statusCode = 503;
res.setHeader("Content-Type", "text/plain; charset=utf-8");