History

wire embedded web UI back into CLI for compiled binaries

Rhys Sullivan committed 7 months ago

Commit ce52c6d1 parent 756a9042 files · +35 −3Browse files

Unified · Split

2 files
  1. apps/cli/src/main.ts +6 −1
  2. apps/local/src/serve.ts +29 −2
apps/cli/src/main.ts+6−1
@@ -30,6 +30,9 @@ import * as Cause from "effect/Cause"; · 29 unmodified lines
30import { ExecutorApi } from "@executor/api";30import { ExecutorApi } from "@executor/api";
31import { startServer, runMcpStdioServer, getExecutor } from "@executor/local";31import { startServer, runMcpStdioServer, getExecutor } from "@executor/local";
32 32
33// Embedded web UI — baked into compiled binaries via `with { type: "file" }`
34import embeddedWebUI from "./embedded-web-ui.gen";
35
33// ---------------------------------------------------------------------------36// ---------------------------------------------------------------------------
34// Constants37// Constants
35// ---------------------------------------------------------------------------38// ---------------------------------------------------------------------------
@@ -115,7 +118,9 @@ const makeApiClient = (baseUrl: string) => · 79 unmodified lines
115 118
116const runForegroundSession = (input: { port: number }) =>119const runForegroundSession = (input: { port: number }) =>
117 Effect.gen(function* () {120 Effect.gen(function* () {
118 const server = yield* Effect.promise(() => startServer({ port: input.port }));121 const server = yield* Effect.promise(() =>
122 startServer({ port: input.port, embeddedWebUI }),
123 );
119 124
120 const baseUrl = `http://localhost:${server.port}`;125 const baseUrl = `http://localhost:${server.port}`;
121 console.log(`Executor is ready.`);126 console.log(`Executor is ready.`);
apps/local/src/serve.ts+29−2
@@ -44,13 +44,30 @@ function collectStaticRoutes(dir: string, prefix = ""): Record<string, ReturnTyp · 43 unmodified lines
44 return routes;44 return routes;
45}45}
46 46
47/**
48 * Convert an embedded web UI map (path → bunfs path) into Bun.serve routes.
49 * The embedded map is generated by the CLI build step using `with { type: "file" }`.
50 */
51function embeddedToStaticRoutes(
52 embedded: Record<string, string>,
53): Record<string, ReturnType<typeof Bun.file>> {
54 const routes: Record<string, ReturnType<typeof Bun.file>> = {};
55 for (const [key, bunfsPath] of Object.entries(embedded)) {
56 routes[`/${key}`] = Bun.file(bunfsPath);
57 }
58 return routes;
59}
60
47// ---------------------------------------------------------------------------61// ---------------------------------------------------------------------------
48// Server62// Server
49// ---------------------------------------------------------------------------63// ---------------------------------------------------------------------------
50 64
51export interface StartServerOptions {65export interface StartServerOptions {
52 port?: number;66 port?: number;
67 /** Directory containing built client assets (for dev/disk serving). */
53 clientDir?: string;68 clientDir?: string;
69 /** Embedded web UI map from compiled binary (path → bunfs path). Overrides clientDir. */
70 embeddedWebUI?: Record<string, string> | null;
54}71}
55 72
56export interface ServerInstance {73export interface ServerInstance {
@@ -63,8 +80,18 @@ export async function startServer(opts: StartServerOptions = {}): Promise<Server · 6 unmodified lines
63 const clientDir = opts.clientDir ?? resolve(import.meta.dirname, "../dist");80 const clientDir = opts.clientDir ?? resolve(import.meta.dirname, "../dist");
64 81
65 const handlers = await getServerHandlers();82 const handlers = await getServerHandlers();
66 const staticRoutes = collectStaticRoutes(clientDir);83
67 const indexHtml = Bun.file(join(clientDir, "index.html"));84 // Build static routes from either embedded assets or disk
85 let staticRoutes: Record<string, ReturnType<typeof Bun.file>>;
86 let indexHtml: ReturnType<typeof Bun.file>;
87
88 if (opts.embeddedWebUI) {
89 staticRoutes = embeddedToStaticRoutes(opts.embeddedWebUI);
90 indexHtml = staticRoutes["/index.html"] ?? Bun.file(join(clientDir, "index.html"));
91 } else {
92 staticRoutes = collectStaticRoutes(clientDir);
93 indexHtml = Bun.file(join(clientDir, "index.html"));
94 }
68 95
69 const server = Bun.serve({96 const server = Bun.serve({
70 port,97 port,