import type { ChildProcess } from 'node:child_process'; /** A caller-supplied process spawner so spawned children join the caller's * lifecycle (teardown, respawn policy, stdio). Mirrors the `spawnChild` * closures inside `agent-dev` and the gateway. */ export type SpawnChild = (label: string, bin: string, args: string[], env?: NodeJS.ProcessEnv, optional?: boolean, respawn?: { delayMs: number; max: number; }) => ChildProcess; export interface LensFrontendOptions { /** Absolute path to the frontend project root (holds vite.config.*). */ projectRoot: string; /** Workspace root — used to resolve bundles + the default event file. */ workspaceRoot: string; /** Label for logs (the nx project name). */ project?: string; /** Shared JSONL event bus the vite plugin + capture runner append to. */ eventFile: string; /** Pin the Vite dev port (so the gateway upstream + capture URL are * deterministic). Default 5173 when chrome capture is on, else Vite's own. */ port?: number; /** Launch the headless browser-capture sidecar against the dev URL. */ chrome?: boolean; /** Headless Chrome (default true). */ headless?: boolean; /** Override the URL Chrome navigates to (default http://localhost:/). */ openUrl?: string; /** Override the vite binary path (else resolved from node_modules/.bin). */ viteBin?: string; /** Extra env merged into the Vite child (e.g. cluster identity). */ viteEnv?: NodeJS.ProcessEnv; /** Prefix for the spawned children's labels (default '' ⇒ `vite`/`browser-capture`). The shared daemon * passes `::` so a REGISTERED workspace's children carry unique labels — its auto-heal * and per-workspace reap can target them without touching another workspace's identically-named vite. */ labelPrefix?: string; /** Logger (default console.log). */ log?: (line: string) => void; } export interface LensFrontendResult { /** The pinned Vite dev port (undefined when unpinned). */ devPort?: number; /** The dev URL the gateway should upstream to / Chrome captures. */ devUrl?: string; /** The spawned Vite child. */ vite: ChildProcess; } /** * Spawn ONE frontend project under the lens: its Vite dev server (lens plugin * already wired by `setup-vite`) + an optional browser-capture sidecar, both * publishing to the shared event bus. Does NOT spawn the dashboard or MCP * server — those are singletons the CALLER owns. * * Returns the resolved dev port/URL so the gateway can route its TCP upstream * at it. Throws only if Vite can't be located; capture is best-effort. */ export declare function spawnLensFrontend(options: LensFrontendOptions, spawnChild: SpawnChild): LensFrontendResult; export declare function locateBin(name: string, roots: string[]): string | undefined; export declare function resolveFirstExisting(names: string[], root: string): string | undefined; export declare function globalNodeModules(): string | undefined; /** * Resolve the LensMCP MCP server bundle — the self-contained `lensmcp` CLI * bundle (`bundled/main.js`), else the in-repo dev build. See the doc on * `findCaptureRunner` for why we never reach into an unpublished `@lensmcp/*`. */ export declare function findMcpBundle(workspaceRoot: string): string | undefined; /** * Resolve the lens DASHBOARD bundle — the human web view (`bundled/dashboard.js`, * default :4321). Same shipping story as the MCP bundle. */ export declare function findDashboardBundle(workspaceRoot: string): string | undefined; export declare function findCaptureRunner(workspaceRoot: string): string | undefined; /** * Resolve the standalone browser-event bridge runner — the self-contained * `lensmcp` package's `bundled/bridge.js`, else the in-repo dev build. */ export declare function findBridgeBundle(workspaceRoot: string): string | undefined;