Serve the web client from the daemon (#1635)

* Serve the web client from the daemon

Keep the bundled browser UI opt-in and exclude it from desktop packaging so desktop builds do not ship a duplicate renderer.

* Escape daemon web UI bootstrap hint

* Fix bundled web UI dist path
This commit is contained in:
Mohamed Boudra
2026-06-26 12:00:11 +08:00
committed by GitHub
parent 3d6b4adc68
commit 4e2c06ec71
24 changed files with 1302 additions and 6 deletions

View File

@@ -43,6 +43,8 @@ export function createDaemonCommand(): Command {
.option("--no-relay", "Disable relay on restarted daemon")
.option("--no-mcp", "Disable Agent MCP on restarted daemon")
.option("--no-inject-mcp", "Disable auto-injecting the Paseo MCP into created agents")
.option("--web-ui", "Enable the bundled daemon web UI on restarted daemon")
.option("--no-web-ui", "Disable the bundled daemon web UI on restarted daemon")
.option(
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',

View File

@@ -153,6 +153,44 @@ describe("local daemon launch supervision", () => {
expect(launch?.options?.env?.PASEO_RELAY_USE_TLS).toBe("true");
});
test("web UI flag is passed to the supervised daemon", async () => {
const runtime = new FakeDaemonRuntime();
const status = startLocalDaemonForeground(
{
home: "/tmp/paseo-test",
webUi: true,
},
runtime,
);
expect(status).toBe(0);
expect(runtime.recordedLaunches.map((launch) => launch.mode)).toEqual(["foreground"]);
const launch = runtime.recordedLaunches[0];
expect(launch?.mode).toBe("foreground");
expect(launch?.args).toContain("--web-ui");
expect(launch?.options?.env?.PASEO_WEB_UI_ENABLED).toBe("true");
});
test("no-web UI flag is passed to the supervised daemon", async () => {
const runtime = new FakeDaemonRuntime();
const status = startLocalDaemonForeground(
{
home: "/tmp/paseo-test",
webUi: false,
},
runtime,
);
expect(status).toBe(0);
expect(runtime.recordedLaunches.map((launch) => launch.mode)).toEqual(["foreground"]);
const launch = runtime.recordedLaunches[0];
expect(launch?.mode).toBe("foreground");
expect(launch?.args).toContain("--no-web-ui");
expect(launch?.options?.env?.PASEO_WEB_UI_ENABLED).toBe("false");
});
test("local daemon state keeps public relay TLS separate from daemon relay TLS", async () => {
const home = await createPaseoHome({
version: 1,

View File

@@ -15,6 +15,7 @@ export interface DaemonStartOptions {
relayUseTls?: boolean;
mcp?: boolean;
injectMcp?: boolean;
webUi?: boolean;
hostnames?: string;
}
@@ -138,6 +139,12 @@ function buildRunnerArgs(options: DaemonStartOptions): string[] {
if (options.injectMcp === false) {
args.push("--no-inject-mcp");
}
if (options.webUi === true) {
args.push("--web-ui");
}
if (options.webUi === false) {
args.push("--no-web-ui");
}
return args;
}
@@ -158,6 +165,12 @@ function buildChildEnv(options: DaemonStartOptions): NodeJS.ProcessEnv {
if (options.relayUseTls === true) {
childEnv.PASEO_RELAY_USE_TLS = "true";
}
if (options.webUi === true) {
childEnv.PASEO_WEB_UI_ENABLED = "true";
}
if (options.webUi === false) {
childEnv.PASEO_WEB_UI_ENABLED = "false";
}
return childEnv;
}

View File

@@ -61,6 +61,7 @@ function toStartOptions(options: CommandOptions): DaemonStartOptions {
relay: typeof options.relay === "boolean" ? options.relay : undefined,
mcp: typeof options.mcp === "boolean" ? options.mcp : undefined,
injectMcp: typeof options.injectMcp === "boolean" ? options.injectMcp : undefined,
webUi: typeof options.webUi === "boolean" ? options.webUi : undefined,
hostnames: typeof options.hostnames === "string" ? options.hostnames : undefined,
};

View File

@@ -24,6 +24,8 @@ export function startCommand(): Command {
.option("--relay-use-tls", "Use wss:// for the relay connection and pairing offers")
.option("--no-mcp", "Disable the Agent MCP HTTP endpoint")
.option("--no-inject-mcp", "Disable auto-injecting the Paseo MCP into created agents")
.option("--web-ui", "Enable the bundled daemon web UI")
.option("--no-web-ui", "Disable the bundled daemon web UI")
.option(
"--hostnames <hosts>",
'Daemon hostnames (comma-separated, e.g. "myhost,.example.com" or "true" for any)',