@rahmantech/litedesign 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -10
- package/dist/extension/content.js +448 -28
- package/dist/extension/core.iife.js +214 -8
- package/dist/extension/manifest.json +1 -1
- package/dist/extension/sw.js +1 -0
- package/dist/index.js +120 -15
- package/package.json +3 -2
- package/dist/extension/content.js.map +0 -7
- package/dist/extension/popup.js.map +0 -7
- package/dist/extension/sw.js.map +0 -7
- package/dist/index.js.map +0 -7
package/dist/index.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/commands/doctor.ts", "../src/config.ts", "../src/paths.ts", "../src/version.ts", "../src/ws.ts", "../src/hub.ts", "../src/mcp/handoff.ts", "../src/mcp/errors.ts", "../src/hub-client.ts", "../src/commands/setup.ts", "../src/commands/extension.ts", "../src/commands/ws.ts", "../../core/src/geometry.ts", "../../core/src/align.ts", "../../core/src/color.ts", "../../core/src/constants.ts", "../../core/src/gaps.ts", "../../core/src/extract.ts", "../../core/src/rules/rule.ts", "../../core/src/rules/alignment.ts", "../../core/src/rules/contrast.ts", "../../core/src/rules/overflow.ts", "../../core/src/rules/radius.ts", "../../core/src/rules/spacing.ts", "../../core/src/rules/index.ts", "../../core/src/walk.ts", "../../core/src/graph.ts", "../../core/src/render/layers.ts", "../../core/src/render/overlay.ts", "../../core/src/index.ts", "../src/drivers/extension.ts", "../src/drivers/playwright.ts", "../src/drivers/index.ts", "../src/mcp/result.ts", "../src/mcp/session.ts", "../src/mcp/tools/await-page.ts", "../src/mcp/format.ts", "../src/mcp/rules.ts", "../src/mcp/tools/find-issues.ts", "../src/mcp/tools/inspect.ts", "../src/mcp/tools/measure.ts", "../src/mcp/tools/overlay.ts", "../src/mcp/tools/screenshot.ts", "../src/mcp/tools/screenshot-annotated.ts", "../src/mcp/server.ts", "../src/cli.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport { readConfig } from '../config.js'\nimport { CONFIG, EXT_DIR } from '../paths.js'\nimport { VERSION } from '../version.js'\nimport { wsStatus } from '../ws.js'\n\ntype Status = 'ok' | 'warn' | 'fail'\n\nfunction line(status: Status, label: string, detail: string): void {\n const mark = status === 'ok' ? 'ok ' : status === 'warn' ? 'warn' : 'fail'\n console.log(` ${mark} ${label.padEnd(12)} ${detail}`)\n}\n\nexport async function doctor(): Promise<void> {\n console.log(`\\n litedesign doctor \u00B7 v${VERSION}\\n`)\n\n const major = Number(process.versions.node.split('.')[0])\n line(major >= 20 ? 'ok' : 'fail', 'node', `v${process.versions.node} (requires >= 20)`)\n\n const manifestPath = path.join(EXT_DIR, 'manifest.json')\n if (existsSync(manifestPath)) {\n const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as { version?: string }\n line('ok', 'extension', `${EXT_DIR} (v${manifest.version ?? '?'})`)\n } else {\n line('fail', 'extension', `missing at ${EXT_DIR} \u2014 run: litedesign setup`)\n }\n\n const { port, mode } = await readConfig()\n\n if (existsSync(CONFIG)) {\n line('ok', 'config', `port ${port}, mode ${mode}`)\n } else {\n line('warn', 'config', 'missing \u2014 run: litedesign setup')\n }\n\n const status = await wsStatus(port)\n line(\n status.running ? 'ok' : 'warn',\n 'bridge',\n status.running\n ? `running on ${port} \u00B7 ${status.extensions ?? 0} extension(s) \u00B7 ${status.pages?.length ?? 0} page(s)`\n : `stopped \u2014 run: litedesign ws start`,\n )\n\n console.log('')\n}\n", "import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport { CONFIG, DEFAULT_PORT } from './paths.js'\n\nexport type Mode = 'auto' | 'playwright' | 'extension'\n\nexport type Config = {\n port: number\n mode: Mode\n}\n\nconst MODES: readonly Mode[] = ['auto', 'playwright', 'extension']\n\nconst FALLBACK: Config = { port: DEFAULT_PORT, mode: 'auto' }\n\n/**\n * Reads `~/.litedesign/config.json` and falls back to defaults for every value\n * that is missing or malformed. A broken config should never stop the server.\n */\nexport async function readConfig(): Promise<Config> {\n if (!existsSync(CONFIG)) return { ...FALLBACK }\n\n try {\n const raw = JSON.parse(await readFile(CONFIG, 'utf8')) as {\n port?: unknown\n mode?: unknown\n }\n\n return {\n port: isPort(raw.port) ? raw.port : FALLBACK.port,\n mode: typeof raw.mode === 'string' && isMode(raw.mode) ? raw.mode : FALLBACK.mode,\n }\n } catch {\n return { ...FALLBACK }\n }\n}\n\nfunction isPort(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 && value < 65536\n}\n\nfunction isMode(value: string): value is Mode {\n return (MODES as readonly string[]).includes(value)\n}\n", "import os from 'node:os'\nimport path from 'node:path'\n\nexport const HOME = path.join(os.homedir(), '.litedesign')\nexport const EXT_DIR = path.join(HOME, 'extension')\nexport const CONFIG = path.join(HOME, 'config.json')\nexport const DEFAULT_PORT = 8787\n\n/**\n * One state file per port. A single file meant a bridge on a second port (a\n * test run, a second project) overwrote the pid of the first, so `ws stop`\n * reported \"not running\" while it still ran.\n */\nexport function wsState(port: number): string {\n return path.join(HOME, `ws-${port}.json`)\n}\n\n/** Extension folder bundled inside this package. */\nexport const BUNDLED_EXTENSION = new URL('./extension/', import.meta.url)\n", "export const VERSION = '0.1.0'\n", "import { spawn } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { readFile, rm, writeFile } from 'node:fs/promises'\nimport { createConnection } from 'node:net'\nimport { Hub, type HubPage } from './hub.js'\nimport { HubClient } from './hub-client.js'\nimport { ToolError } from './mcp/errors.js'\nimport { wsState } from './paths.js'\n\nexport type WsState = { pid: number; port: number }\n\nexport type WsStatus = {\n running: boolean\n port: number\n pid?: number\n extensions?: number\n pages?: HubPage[]\n}\n\nconst START_TIMEOUT = 5000\n\n/** True when something is listening on the port. */\nexport function portOpen(port: number, timeoutMs = 400): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = createConnection({ host: '127.0.0.1', port })\n const done = (value: boolean): void => {\n socket.destroy()\n resolve(value)\n }\n\n socket.setTimeout(timeoutMs)\n socket.once('connect', () => done(true))\n socket.once('timeout', () => done(false))\n socket.once('error', () => done(false))\n })\n}\n\nexport async function readState(port: number): Promise<WsState | undefined> {\n const file = wsState(port)\n if (!existsSync(file)) return undefined\n\n try {\n const raw = JSON.parse(await readFile(file, 'utf8')) as { pid?: unknown; port?: unknown }\n if (typeof raw.pid !== 'number' || typeof raw.port !== 'number') return undefined\n return { pid: raw.pid, port: raw.port }\n } catch {\n return undefined\n }\n}\n\nasync function writeState(state: WsState): Promise<void> {\n await writeFile(wsState(state.port), `${JSON.stringify(state, null, 2)}\\n`)\n}\n\nasync function clearState(port: number): Promise<void> {\n await rm(wsState(port), { force: true })\n}\n\nexport function isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Runs the bridge in the foreground. `ws start` launches this detached; the\n * pid file is how `ws stop` and `ws status` find it again.\n */\nexport async function runDaemon(port: number): Promise<void> {\n let hub: Hub\n\n try {\n hub = await Hub.start(port)\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n throw new ToolError(`could not listen on port ${port}: ${detail}`)\n }\n\n await writeState({ pid: process.pid, port: hub.port })\n\n console.log(` bridge ws://127.0.0.1:${hub.port} \u00B7 pid ${process.pid} \u00B7 Ctrl+C to stop`)\n\n const stop = (): void => {\n void (async () => {\n await clearState(port)\n await hub.close()\n process.exit(0)\n })()\n }\n\n process.once('SIGINT', stop)\n process.once('SIGTERM', stop)\n}\n\n/**\n * Starts the bridge in the background unless something already listens on the\n * port. The child writes the pid file itself, so the pid is never guessed.\n */\nexport async function startDaemon(port: number): Promise<WsState> {\n if (await portOpen(port)) {\n const state = await readState(port)\n return state ?? { pid: 0, port }\n }\n\n const script = process.argv[1]\n if (script === undefined) {\n throw new ToolError('could not find the litedesign entry point to start the bridge')\n }\n\n const child = spawn(process.execPath, [script, 'ws', 'run', '--port', String(port)], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n child.unref()\n\n const started = await waitFor(async () => portOpen(port), START_TIMEOUT)\n\n if (!started) {\n throw new ToolError(\n `the bridge did not start on port ${port}. Run \"litedesign ws run\" to see the error.`,\n )\n }\n\n const state = await waitForValue(() => readState(port), 2000)\n return state ?? { pid: 0, port }\n}\n\n/** Connects to the running bridge, starting it first when necessary. */\nexport async function ensureBridge(port: number): Promise<HubClient> {\n try {\n return await HubClient.connect(port, 500)\n } catch {\n // Nothing listening yet; start it and try once more.\n }\n\n await startDaemon(port)\n\n try {\n return await HubClient.connect(port, 3000)\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n throw new ToolError(`the bridge started but did not accept a connection: ${detail}`)\n }\n}\n\nexport async function stopDaemon(port: number): Promise<boolean> {\n const state = await readState(port)\n\n if (state === undefined) {\n await clearState(port)\n return false\n }\n\n if (isAlive(state.pid)) {\n process.kill(state.pid, 'SIGTERM')\n\n const stopped = await waitFor(async () => !isAlive(state.pid), 3000)\n if (!stopped) throw new ToolError(`the bridge (pid ${state.pid}) did not stop`)\n }\n\n await clearState(port)\n return true\n}\n\nexport async function wsStatus(port: number): Promise<WsStatus> {\n const state = await readState(port)\n const listening = await portOpen(port)\n\n if (!listening) {\n if (state !== undefined) await clearState(port)\n return { running: false, port }\n }\n\n let extensions: number | undefined\n let pages: HubPage[] | undefined\n\n try {\n const client = await HubClient.connect(port, 1000)\n extensions = client.clientCount()\n pages = client.pages()\n await client.close()\n } catch {\n // Listening, but not answering as a bridge; still report it as running.\n }\n\n return {\n running: true,\n port,\n ...(state !== undefined ? { pid: state.pid } : {}),\n ...(extensions !== undefined ? { extensions } : {}),\n ...(pages !== undefined ? { pages } : {}),\n }\n}\n\nasync function waitFor(check: () => Promise<boolean>, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n\n while (Date.now() < deadline) {\n if (await check()) return true\n await delay(100)\n }\n\n return check()\n}\n\nasync function waitForValue<T>(\n read: () => Promise<T | undefined>,\n timeoutMs: number,\n): Promise<T | undefined> {\n const deadline = Date.now() + timeoutMs\n\n while (Date.now() < deadline) {\n const value = await read()\n if (value !== undefined) return value\n await delay(100)\n }\n\n return read()\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n", "import { randomUUID } from 'node:crypto'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport { ToolError } from './mcp/errors.js'\n\nconst PING_INTERVAL = 20000\n\nexport type HubPage = {\n tabId: number\n url: string\n title: string\n version: string\n}\n\nexport type WaitOutcome =\n | { status: 'ready'; page: HubPage }\n | { status: 'timeout' }\n | { status: 'mismatch'; page: HubPage }\n\n/**\n * What the tools and drivers need from the bridge. The daemon implements it\n * in-process; the MCP server uses a client that forwards over a socket.\n */\nexport interface Bridge {\n pages(): HubPage[]\n find(url: string): HubPage | undefined\n request<T>(tabId: number, action: string, payload?: unknown, timeoutMs?: number): Promise<T>\n requestAny<T>(action: string, payload?: unknown, timeoutMs?: number): Promise<T>\n hasClient(): boolean\n clientCount(): number\n waitForPage(url: string, timeoutMs: number): Promise<WaitOutcome>\n close(): Promise<void>\n}\n\ntype Client = HubPage & { socket: WebSocket }\n\ntype Pending = {\n resolve(value: unknown): void\n reject(error: Error): void\n timer: ReturnType<typeof setTimeout>\n socket: WebSocket\n action: string\n /** Set when the request came from an MCP client and the answer goes back to it. */\n controller?: WebSocket\n controllerId?: string\n}\n\ntype Waiter = {\n url: string\n resolve(outcome: WaitOutcome): void\n}\n\n/**\n * The bridge daemon. It owns the WebSocket server and outlives any single MCP\n * session: `litedesign ws start` runs it, `litedesign ws stop` ends it, and\n * every MCP server connects to it as a controller.\n */\nexport class Hub implements Bridge {\n readonly #server: WebSocketServer\n readonly #clients = new Map<number, Client>()\n readonly #socketTab = new Map<WebSocket, number>()\n readonly #sockets = new Set<WebSocket>()\n readonly #controllers = new Set<WebSocket>()\n readonly #pending = new Map<string, Pending>()\n readonly #waiters = new Set<Waiter>()\n #ping: ReturnType<typeof setInterval> | undefined\n #closed = false\n\n private constructor(server: WebSocketServer) {\n this.#server = server\n }\n\n static start(port: number): Promise<Hub> {\n return new Promise((resolve, reject) => {\n const server = new WebSocketServer({ host: '127.0.0.1', port })\n const hub = new Hub(server)\n\n const onError = (error: Error): void => {\n server.off('listening', onListening)\n reject(error)\n }\n\n const onListening = (): void => {\n server.off('error', onError)\n server.on('connection', (socket) => hub.#accept(socket))\n hub.#ping = setInterval(() => hub.#broadcastPing(), PING_INTERVAL)\n resolve(hub)\n }\n\n server.once('error', onError)\n server.once('listening', onListening)\n })\n }\n\n /** Bound port. Useful for tests, which start the hub on port 0. */\n get port(): number {\n const address = this.#server.address()\n return typeof address === 'object' && address !== null ? address.port : 0\n }\n\n pages(): HubPage[] {\n return [...this.#clients.values()].map(({ socket: _socket, ...page }) => page)\n }\n\n find(url: string): HubPage | undefined {\n for (const client of this.#clients.values()) {\n if (sameUrl(client.url, url)) return client\n }\n\n return undefined\n }\n\n async request<T>(\n tabId: number,\n action: string,\n payload?: unknown,\n timeoutMs = 30000,\n ): Promise<T> {\n const client = this.#clients.get(tabId)\n if (client === undefined) {\n throw new ToolError('the page is no longer connected. Call inspect again.')\n }\n\n return this.#ask<T>(client.socket, action, payload, timeoutMs)\n }\n\n /**\n * Asks any connected worker, not a specific tab. This is how the server\n * attaches to a page: the worker picks the tab the human is looking at.\n */\n async requestAny<T>(action: string, payload?: unknown, timeoutMs = 30000): Promise<T> {\n const socket = this.#firstSocket()\n\n if (socket === undefined) {\n throw new ToolError(\n 'the extension is not connected. Is Chrome open with the extension loaded?',\n )\n }\n\n return this.#ask<T>(socket, action, payload, timeoutMs)\n }\n\n /** True when at least one extension worker is connected. */\n hasClient(): boolean {\n return this.#firstSocket() !== undefined\n }\n\n /** Number of connected extension workers, with or without an attached page. */\n clientCount(): number {\n let count = 0\n\n for (const socket of this.#sockets) {\n if (socket.readyState === WebSocket.OPEN) count += 1\n }\n\n return count\n }\n\n #firstSocket(): WebSocket | undefined {\n for (const socket of this.#sockets) {\n if (socket.readyState === WebSocket.OPEN) return socket\n }\n\n return undefined\n }\n\n #ask<T>(socket: WebSocket, action: string, payload: unknown, timeoutMs: number): Promise<T> {\n const id = randomUUID()\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pending.delete(id)\n reject(\n new ToolError(\n `the extension did not answer \"${action}\" within ${Math.round(timeoutMs / 1000)}s`,\n ),\n )\n }, timeoutMs)\n\n this.#pending.set(id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timer,\n socket,\n action,\n })\n\n socket.send(JSON.stringify({ type: 'request', id, action, payload }))\n })\n }\n\n /**\n * Resolves on the next `hello`, or immediately when a matching page is\n * already connected. A page that connects with another URL resolves as\n * `mismatch` so the agent can tell the user exactly what is wrong.\n */\n waitForPage(url: string, timeoutMs: number): Promise<WaitOutcome> {\n const existing = this.find(url)\n if (existing !== undefined) return Promise.resolve({ status: 'ready', page: existing })\n\n return new Promise((resolve) => {\n const waiter: Waiter = {\n url,\n resolve: (outcome) => {\n clearTimeout(timer)\n resolve(outcome)\n },\n }\n\n const timer = setTimeout(() => {\n this.#waiters.delete(waiter)\n resolve({ status: 'timeout' })\n }, timeoutMs)\n\n this.#waiters.add(waiter)\n })\n }\n\n async close(): Promise<void> {\n if (this.#closed) return\n this.#closed = true\n\n if (this.#ping !== undefined) clearInterval(this.#ping)\n this.#ping = undefined\n\n for (const waiter of [...this.#waiters]) waiter.resolve({ status: 'timeout' })\n this.#waiters.clear()\n\n for (const pending of this.#pending.values()) {\n clearTimeout(pending.timer)\n pending.reject(new ToolError('the extension bridge is shutting down'))\n }\n this.#pending.clear()\n\n const sockets = [...this.#sockets]\n for (const socket of sockets) socket.close(1001, 'litedesign server closing')\n\n for (const socket of this.#controllers) socket.close(1001, 'litedesign server closing')\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n for (const socket of sockets) socket.terminate()\n resolve()\n }, 500)\n\n this.#server.close(() => {\n clearTimeout(timer)\n resolve()\n })\n })\n }\n\n #accept(socket: WebSocket): void {\n this.#sockets.add(socket)\n // An extension connects before it has a page to announce. Tell controllers\n // right away, otherwise `hasClient` stays false until the first attach.\n this.#broadcast({ type: 'extensions', count: this.clientCount() })\n\n socket.on('message', (data) => this.#receive(socket, data.toString()))\n socket.on('close', () => this.#drop(socket))\n socket.on('error', () => this.#drop(socket))\n }\n\n #receive(socket: WebSocket, raw: string): void {\n let message: Record<string, unknown>\n\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return\n message = parsed as Record<string, unknown>\n } catch {\n return\n }\n\n switch (message.type) {\n case 'hello':\n if (message.role === 'mcp') this.#controllerHello(socket)\n else this.#hello(socket, message)\n return\n case 'request':\n this.#controllerRequest(socket, message)\n return\n case 'response':\n this.#response(message)\n return\n case 'bye':\n this.#drop(socket)\n socket.close()\n return\n default:\n return\n }\n }\n\n #controllerHello(socket: WebSocket): void {\n this.#sockets.delete(socket)\n this.#controllers.add(socket)\n this.#broadcast({ type: 'extensions', count: this.clientCount() })\n\n socket.send(\n JSON.stringify({ type: 'pages', pages: this.pages(), extensions: this.clientCount() }),\n )\n }\n\n /**\n * An MCP client asks the daemon to run something. The daemon forwards to the\n * right extension socket and routes the answer back.\n */\n #controllerRequest(socket: WebSocket, message: Record<string, unknown>): void {\n const { id, action } = message\n if (typeof id !== 'string' || typeof action !== 'string') return\n\n if (action === 'pages') {\n this.#reply(socket, id, true, this.pages())\n return\n }\n\n if (action === 'has-client') {\n this.#reply(socket, id, true, this.hasClient())\n return\n }\n\n const tabId = typeof message.tabId === 'number' ? message.tabId : undefined\n const target = tabId === undefined ? this.#firstSocket() : this.#clients.get(tabId)?.socket\n\n if (target === undefined || target.readyState !== WebSocket.OPEN) {\n this.#reply(\n socket,\n id,\n false,\n undefined,\n tabId === undefined\n ? 'the extension is not connected. Is Chrome open with the extension loaded?'\n : 'the page is no longer connected. Call inspect again.',\n )\n return\n }\n\n const forwardId = randomUUID()\n\n const timer = setTimeout(() => {\n this.#pending.delete(forwardId)\n this.#reply(\n socket,\n id,\n false,\n undefined,\n `the extension did not answer \"${action}\" within 30s`,\n )\n }, 30000)\n\n this.#pending.set(forwardId, {\n resolve: () => undefined,\n reject: () => undefined,\n timer,\n socket: target,\n action,\n controller: socket,\n controllerId: id,\n })\n\n target.send(\n JSON.stringify({ type: 'request', id: forwardId, action, payload: message.payload }),\n )\n }\n\n #reply(socket: WebSocket, id: string, ok: boolean, result?: unknown, error?: string): void {\n if (socket.readyState !== WebSocket.OPEN) return\n\n socket.send(JSON.stringify({ type: 'response', id, ok, result, error }))\n }\n\n #hello(socket: WebSocket, message: Record<string, unknown>): void {\n const { tabId, url } = message\n\n if (\n typeof tabId !== 'number' ||\n !Number.isInteger(tabId) ||\n typeof url !== 'string' ||\n url === ''\n ) {\n return\n }\n\n const page: HubPage = {\n tabId,\n url,\n title: typeof message.title === 'string' ? message.title : '',\n version: typeof message.version === 'string' ? message.version : '',\n }\n\n const previous = this.#socketTab.get(socket)\n if (previous !== undefined && previous !== tabId) {\n const old = this.#clients.get(previous)\n if (old?.socket === socket) this.#clients.delete(previous)\n }\n\n this.#clients.set(tabId, { ...page, socket })\n this.#socketTab.set(socket, tabId)\n\n this.#broadcast({ type: 'page', page })\n this.#broadcast({ type: 'extensions', count: this.clientCount() })\n\n for (const waiter of [...this.#waiters]) {\n this.#waiters.delete(waiter)\n waiter.resolve(\n sameUrl(page.url, waiter.url) ? { status: 'ready', page } : { status: 'mismatch', page },\n )\n }\n }\n\n #response(message: Record<string, unknown>): void {\n const { id } = message\n if (typeof id !== 'string') return\n\n const pending = this.#pending.get(id)\n if (pending === undefined) return\n\n this.#pending.delete(id)\n clearTimeout(pending.timer)\n\n if (pending.controller !== undefined) {\n const ok = message.ok === true\n this.#reply(\n pending.controller,\n pending.controllerId ?? '',\n ok,\n message.result,\n typeof message.error === 'string' && message.error !== ''\n ? message.error\n : `the extension failed to run \"${pending.action}\"`,\n )\n return\n }\n\n if (message.ok === true) {\n pending.resolve(message.result)\n return\n }\n\n pending.reject(\n new ToolError(\n typeof message.error === 'string' && message.error !== ''\n ? message.error\n : `the extension failed to run \"${pending.action}\"`,\n ),\n )\n }\n\n #broadcast(message: unknown): void {\n const raw = JSON.stringify(message)\n\n for (const socket of this.#controllers) {\n if (socket.readyState === WebSocket.OPEN) socket.send(raw)\n }\n }\n\n #drop(socket: WebSocket): void {\n const tabId = this.#socketTab.get(socket)\n this.#socketTab.delete(socket)\n this.#sockets.delete(socket)\n this.#controllers.delete(socket)\n\n if (tabId !== undefined && this.#clients.get(tabId)?.socket === socket) {\n this.#clients.delete(tabId)\n this.#broadcast({ type: 'page-gone', tabId })\n }\n\n this.#broadcast({ type: 'extensions', count: this.clientCount() })\n\n for (const [id, pending] of this.#pending) {\n if (pending.socket !== socket) continue\n\n this.#pending.delete(id)\n clearTimeout(pending.timer)\n\n if (pending.controller !== undefined) {\n this.#reply(\n pending.controller,\n pending.controllerId ?? '',\n false,\n undefined,\n 'the page disconnected before it answered',\n )\n } else {\n pending.reject(new ToolError('the page disconnected before it answered'))\n }\n }\n }\n\n #broadcastPing(): void {\n for (const socket of this.#sockets) {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify({ type: 'ping' }))\n }\n }\n }\n}\n\nexport function sameUrl(a: string, b: string): boolean {\n return normalize(a) === normalize(b)\n}\n\n/** Hash changes do not change layout, so they do not change the page identity. */\nfunction normalize(url: string): string {\n try {\n const parsed = new URL(url)\n parsed.hash = ''\n return parsed.href\n } catch {\n return url\n }\n}\n\nlet current: Bridge | null = null\nlet currentError: string | null = null\n\nexport function setHub(hub: Bridge): void {\n current = hub\n currentError = null\n}\n\nexport function setHubError(message: string): void {\n current = null\n currentError = message\n}\n\nexport function getHub(): Bridge | null {\n return current\n}\n\nexport function getHubError(): string | null {\n return currentError\n}\n", "/** Copy-pasteable instructions for the human who has to open the page. */\nexport function handoffMessage(url: string): string {\n return [\n `Open ${url} in Chrome and keep it in the active tab.`,\n '',\n 'The extension attaches by itself, so there is nothing to click.',\n 'If nothing connects:',\n '- make sure the extension is loaded unpacked at chrome://extensions',\n '- make sure Chrome is running',\n '',\n 'I am waiting for that page to connect.',\n ].join('\\n')\n}\n\n/** The right page never connected; a different one did. */\nexport function mismatchMessage(expected: string, actual: string): string {\n return [\n `The active tab is ${actual}, but I am waiting for ${expected}.`,\n '',\n `Switch to ${expected} and call await_page,`,\n 'or call inspect again with the URL you actually have open.',\n ].join('\\n')\n}\n", "import { mismatchMessage } from './handoff.js'\n\n/** An error whose message is safe and useful to show to the agent. */\nexport class ToolError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'ToolError'\n }\n}\n\n/**\n * The page is not connected yet. This is not a failure: the agent should tell\n * the human what to do and then wait with `await_page`.\n */\nexport class AwaitingUserError extends ToolError {\n readonly url: string\n\n constructor(url: string) {\n super(`the page ${url} is not connected. Open it and keep it in the active tab.`)\n this.name = 'AwaitingUserError'\n this.url = url\n }\n}\n\n/** The extension attached to a tab, but it is not the page we asked for. */\nexport class MismatchError extends ToolError {\n readonly expected: string\n readonly actual: string\n\n constructor(expected: string, actual: string) {\n super(mismatchMessage(expected, actual))\n this.name = 'MismatchError'\n this.expected = expected\n this.actual = actual\n }\n}\n", "import { randomUUID } from 'node:crypto'\nimport { WebSocket } from 'ws'\nimport type { Bridge, HubPage, WaitOutcome } from './hub.js'\nimport { sameUrl } from './hub.js'\nimport { ToolError } from './mcp/errors.js'\n\ntype Pending = {\n resolve(value: unknown): void\n reject(error: Error): void\n timer: ReturnType<typeof setTimeout>\n}\n\ntype Waiter = {\n url: string\n resolve(outcome: WaitOutcome): void\n}\n\nconst DEFAULT_TIMEOUT = 30000\n\n/**\n * The MCP side of the bridge. It holds one socket to the daemon, keeps a local\n * copy of the page list, and forwards requests. Closing it does not stop the\n * daemon: that belongs to `litedesign ws stop`.\n */\nexport class HubClient implements Bridge {\n readonly #socket: WebSocket\n readonly #pages = new Map<number, HubPage>()\n readonly #pending = new Map<string, Pending>()\n readonly #waiters = new Set<Waiter>()\n #extensions = 0\n #closed = false\n\n private constructor(socket: WebSocket) {\n this.#socket = socket\n }\n\n static connect(port: number, timeoutMs = 2000): Promise<HubClient> {\n return new Promise((resolve, reject) => {\n const socket = new WebSocket(`ws://127.0.0.1:${port}`)\n const client = new HubClient(socket)\n\n const timer = setTimeout(() => {\n socket.terminate()\n reject(new ToolError(`the bridge on port ${port} did not answer`))\n }, timeoutMs)\n\n socket.once('open', () => {\n socket.send(JSON.stringify({ type: 'hello', role: 'mcp' }))\n })\n\n socket.once('error', (error) => {\n clearTimeout(timer)\n reject(error instanceof Error ? error : new ToolError(String(error)))\n })\n\n client.#listen(() => {\n clearTimeout(timer)\n resolve(client)\n })\n })\n }\n\n pages(): HubPage[] {\n return [...this.#pages.values()]\n }\n\n find(url: string): HubPage | undefined {\n for (const page of this.#pages.values()) {\n if (sameUrl(page.url, url)) return page\n }\n\n return undefined\n }\n\n hasClient(): boolean {\n return this.#extensions > 0\n }\n\n clientCount(): number {\n return this.#extensions\n }\n\n async request<T>(\n tabId: number,\n action: string,\n payload?: unknown,\n timeoutMs = DEFAULT_TIMEOUT,\n ): Promise<T> {\n return this.#ask<T>({ tabId, action, payload }, action, timeoutMs)\n }\n\n async requestAny<T>(action: string, payload?: unknown, timeoutMs = DEFAULT_TIMEOUT): Promise<T> {\n return this.#ask<T>({ action, payload }, action, timeoutMs)\n }\n\n waitForPage(url: string, timeoutMs: number): Promise<WaitOutcome> {\n const existing = this.find(url)\n if (existing !== undefined) return Promise.resolve({ status: 'ready', page: existing })\n\n return new Promise((resolve) => {\n const waiter: Waiter = {\n url,\n resolve: (outcome) => {\n clearTimeout(timer)\n resolve(outcome)\n },\n }\n\n const timer = setTimeout(() => {\n this.#waiters.delete(waiter)\n resolve({ status: 'timeout' })\n }, timeoutMs)\n\n this.#waiters.add(waiter)\n })\n }\n\n async close(): Promise<void> {\n if (this.#closed) return\n this.#closed = true\n\n for (const waiter of [...this.#waiters]) waiter.resolve({ status: 'timeout' })\n this.#waiters.clear()\n\n for (const pending of this.#pending.values()) {\n clearTimeout(pending.timer)\n pending.reject(new ToolError('the bridge client is closing'))\n }\n this.#pending.clear()\n\n this.#socket.close(1000, 'mcp session ended')\n }\n\n #ask<T>(\n message: { tabId?: number; action: string; payload?: unknown },\n action: string,\n timeoutMs: number,\n ): Promise<T> {\n if (this.#closed || this.#socket.readyState !== WebSocket.OPEN) {\n return Promise.reject(\n new ToolError('the bridge is not running. Start it with `litedesign ws start`.'),\n )\n }\n\n const id = randomUUID()\n\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pending.delete(id)\n reject(\n new ToolError(\n `the extension did not answer \"${action}\" within ${Math.round(timeoutMs / 1000)}s`,\n ),\n )\n }, timeoutMs)\n\n this.#pending.set(id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timer,\n })\n\n this.#socket.send(JSON.stringify({ type: 'request', id, ...message }))\n })\n }\n\n #listen(ready: () => void): void {\n this.#socket.on('message', (data) => {\n let message: Record<string, unknown>\n\n try {\n const parsed: unknown = JSON.parse(data.toString())\n if (typeof parsed !== 'object' || parsed === null) return\n message = parsed as Record<string, unknown>\n } catch {\n return\n }\n\n switch (message.type) {\n case 'pages':\n this.#takePages(message)\n ready()\n return\n case 'page':\n this.#takePage(message.page)\n return\n case 'page-gone':\n if (typeof message.tabId === 'number') this.#pages.delete(message.tabId)\n return\n case 'extensions':\n if (typeof message.count === 'number') this.#extensions = message.count\n return\n case 'response':\n this.#response(message)\n return\n default:\n return\n }\n })\n\n this.#socket.on('close', () => {\n this.#closed = true\n\n for (const waiter of [...this.#waiters]) waiter.resolve({ status: 'timeout' })\n this.#waiters.clear()\n\n for (const pending of this.#pending.values()) {\n clearTimeout(pending.timer)\n pending.reject(new ToolError('the bridge stopped running'))\n }\n this.#pending.clear()\n })\n }\n\n #takePages(message: Record<string, unknown>): void {\n if (typeof message.extensions === 'number') this.#extensions = message.extensions\n if (!Array.isArray(message.pages)) return\n\n this.#pages.clear()\n for (const page of message.pages) this.#takePage(page)\n }\n\n #takePage(value: unknown): void {\n if (typeof value !== 'object' || value === null) return\n\n const page = value as HubPage\n if (typeof page.tabId !== 'number' || typeof page.url !== 'string') return\n\n this.#pages.set(page.tabId, page)\n\n for (const waiter of [...this.#waiters]) {\n this.#waiters.delete(waiter)\n waiter.resolve(\n sameUrl(page.url, waiter.url) ? { status: 'ready', page } : { status: 'mismatch', page },\n )\n }\n }\n\n #response(message: Record<string, unknown>): void {\n const { id } = message\n if (typeof id !== 'string') return\n\n const pending = this.#pending.get(id)\n if (pending === undefined) return\n\n this.#pending.delete(id)\n clearTimeout(pending.timer)\n\n if (message.ok === true) {\n pending.resolve(message.result)\n return\n }\n\n pending.reject(\n new ToolError(\n typeof message.error === 'string' && message.error !== ''\n ? message.error\n : 'the extension failed to run the request',\n ),\n )\n }\n}\n", "import { existsSync } from 'node:fs'\nimport { cp, mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { readConfig } from '../config.js'\nimport { BUNDLED_EXTENSION, CONFIG, DEFAULT_PORT, EXT_DIR, HOME } from '../paths.js'\n\nexport async function setup(): Promise<void> {\n const source = fileURLToPath(BUNDLED_EXTENSION)\n\n if (!existsSync(source)) {\n throw new Error(\n 'extension assets missing from the package. Reinstall: npm i -g @rahmantech/litedesign',\n )\n }\n\n await mkdir(HOME, { recursive: true })\n await cp(source, EXT_DIR, { recursive: true, force: true })\n\n let configCreated = false\n if (!existsSync(CONFIG)) {\n await writeFile(\n CONFIG,\n `${JSON.stringify({ port: DEFAULT_PORT, mode: 'auto' }, null, 2)}\\n`,\n 'utf8',\n )\n configCreated = true\n }\n\n const config = await readConfig()\n\n // The extension reads this file to find the hub. It is written after the copy\n // so `extension update` never resets a custom port.\n await writeFile(\n path.join(EXT_DIR, 'config.json'),\n `${JSON.stringify({ port: config.port }, null, 2)}\\n`,\n 'utf8',\n )\n\n console.log(`\n litedesign setup\n\n [1/3] extension -> ${EXT_DIR}\n [2/3] config -> ${CONFIG}${configCreated ? '' : ' (already exists)'}\n [3/3] done\n\n One manual step:\n\n 1. open chrome://extensions\n 2. enable Developer mode\n 3. Load unpacked -> ${EXT_DIR}\n\n Register with your MCP client:\n\n {\n \"mcpServers\": {\n \"litedesign\": {\n \"command\": \"litedesign\",\n \"args\": [\"mcp\"]\n }\n }\n }\n\n port ${config.port} \u00B7 mode ${config.mode}\n`)\n}\n", "import { EXT_DIR } from '../paths.js'\nimport { setup } from './setup.js'\n\nexport async function extensionCommand(args: string[]): Promise<void> {\n const sub = args[0]\n\n if (sub === 'path') {\n console.log(EXT_DIR)\n return\n }\n\n if (sub === 'update') {\n await setup()\n return\n }\n\n throw new Error('usage: litedesign extension <path|update>')\n}\n", "import { readConfig } from '../config.js'\nimport { runDaemon, startDaemon, stopDaemon, wsStatus } from '../ws.js'\n\nconst HELP = `\n Usage:\n litedesign ws start start the bridge in the background\n litedesign ws stop stop the bridge\n litedesign ws status show whether it runs and what is connected\n litedesign ws run run it in the foreground (used by start)\n`\n\nexport async function wsCommand(argv: string[]): Promise<void> {\n const [action, ...rest] = argv\n const port = portFrom(rest) ?? (await readConfig()).port\n\n switch (action) {\n case undefined:\n case 'help':\n case '--help':\n console.log(HELP)\n return\n case 'run':\n await runDaemon(port)\n return\n case 'start': {\n const state = await startDaemon(port)\n const pid = state.pid > 0 ? ` \u00B7 pid ${state.pid}` : ''\n console.log(` bridge running \u00B7 ws://127.0.0.1:${state.port}${pid}`)\n return\n }\n case 'stop': {\n const stopped = await stopDaemon(port)\n console.log(stopped ? ' bridge stopped' : ' bridge was not running')\n return\n }\n case 'status':\n await printStatus(port)\n return\n default:\n throw new Error(`unknown ws command: ${action}. Try: litedesign ws --help`)\n }\n}\n\nasync function printStatus(port: number): Promise<void> {\n const status = await wsStatus(port)\n\n if (!status.running) {\n console.log(` bridge stopped \u00B7 port ${port}`)\n return\n }\n\n const pid = status.pid === undefined ? '' : ` \u00B7 pid ${status.pid}`\n const extensions = status.extensions ?? 0\n const pages = status.pages?.length ?? 0\n\n console.log(\n ` bridge running \u00B7 ws://127.0.0.1:${status.port}${pid} \u00B7 ${extensions} extension(s) \u00B7 ${pages} page(s)`,\n )\n\n for (const page of status.pages ?? []) {\n console.log(` tab ${page.tabId} ${page.url}`)\n }\n}\n\nfunction portFrom(args: string[]): number | undefined {\n const index = args.indexOf('--port')\n if (index === -1) return undefined\n\n const value = Number(args[index + 1])\n return Number.isInteger(value) && value > 0 && value < 65536 ? value : undefined\n}\n", "import type { Axis, Rect } from './types.js'\n\nexport function right(rect: Rect): number {\n return rect.x + rect.w\n}\n\nexport function bottom(rect: Rect): number {\n return rect.y + rect.h\n}\n\nexport function centerX(rect: Rect): number {\n return rect.x + rect.w / 2\n}\n\nexport function centerY(rect: Rect): number {\n return rect.y + rect.h / 2\n}\n\nexport function overlaps(a: Rect, b: Rect): boolean {\n return a.x < right(b) && b.x < right(a) && a.y < bottom(b) && b.y < bottom(a)\n}\n\n/**\n * Length of the shared projection of two rects along `axis`.\n *\n * `projectionOverlap(a, b, 'y')` is the vertical extent both rects share, which\n * is what horizontal adjacency cares about.\n */\nexport function projectionOverlap(a: Rect, b: Rect, axis: Axis): number {\n return axis === 'x'\n ? Math.max(0, Math.min(right(a), right(b)) - Math.max(a.x, b.x))\n : Math.max(0, Math.min(bottom(a), bottom(b)) - Math.max(a.y, b.y))\n}\n\n/** Signed distance from the far edge of `a` to the near edge of `b`. */\nexport function axisGap(a: Rect, b: Rect, axis: Axis): number {\n return axis === 'x' ? b.x - right(a) : b.y - bottom(a)\n}\n\n/**\n * True when the projections overlap along `axis` by at least `ratio` of the\n * smaller extent on that same axis. Used to decide whether two boxes share a\n * band: `'y'` for a row, `'x'` for a column.\n */\nexport function overlapsOn(a: Rect, b: Rect, axis: Axis, ratio = 0.5): boolean {\n const shared = projectionOverlap(a, b, axis)\n const smallest = axis === 'x' ? Math.min(a.w, b.w) : Math.min(a.h, b.h)\n return smallest > 0 && shared / smallest >= ratio\n}\n\nexport function isClose(a: number, b: number, tolerance: number): boolean {\n return Math.abs(a - b) <= tolerance\n}\n\nexport function round(value: number, precision = 2): number {\n const factor = 10 ** precision\n return Math.round(value * factor) / factor\n}\n", "import { bottom, centerX, centerY, right, round } from './geometry.js'\nimport type { Axis, GraphNode, Guide, Rect } from './types.js'\n\nconst TOLERANCE = 2\n\ntype EdgeSpec = {\n axis: Axis\n edge: Guide['edge']\n value: (rect: Rect) => number\n}\n\nexport const EDGES: EdgeSpec[] = [\n { axis: 'x', edge: 'left', value: (rect) => rect.x },\n { axis: 'x', edge: 'right', value: right },\n { axis: 'x', edge: 'center', value: centerX },\n { axis: 'y', edge: 'top', value: (rect) => rect.y },\n { axis: 'y', edge: 'bottom', value: bottom },\n { axis: 'y', edge: 'center', value: centerY },\n]\n\n/**\n * Cluster edges with a 2px tolerance. A cluster of two or more nodes becomes a\n * guide. Guides whose members form a single ancestor chain are dropped: a\n * container and its only child share an edge because they are nested, not\n * because anyone aligned them.\n */\nexport function findGuides(nodes: GraphNode[], tolerance = TOLERANCE): Guide[] {\n const byId = new Map(nodes.map((node) => [node.id, node]))\n const guides: Guide[] = []\n\n for (const spec of EDGES) {\n const items = nodes\n .map((node) => ({ node, value: spec.value(node.rect) }))\n .sort((a, b) => a.value - b.value)\n\n let start = 0\n\n for (let i = 1; i <= items.length; i++) {\n const previous = items[i - 1]\n const current = items[i]\n const breaks =\n current === undefined ||\n previous === undefined ||\n current.value - previous.value > tolerance\n if (!breaks) continue\n\n const cluster = items.slice(start, i)\n start = i\n\n if (cluster.length < 2) continue\n\n const members = cluster.map((item) => item.node)\n if (isAncestorChain(members, byId)) continue\n\n const total = cluster.reduce((sum, item) => sum + item.value, 0)\n\n guides.push({\n axis: spec.axis,\n edge: spec.edge,\n value: round(total / cluster.length),\n members: members.map((node) => node.id),\n })\n }\n }\n\n return guides\n}\n\nfunction isAncestorChain(members: GraphNode[], byId: Map<string, GraphNode>): boolean {\n if (members.length < 2) return false\n\n const ids = new Set(members.map((node) => node.id))\n let deepest = members[0]\n\n for (const node of members) {\n if (deepest === undefined || node.depth > deepest.depth) deepest = node\n }\n\n if (deepest === undefined) return false\n\n let hits = 0\n let current = deepest.parent === null ? undefined : byId.get(deepest.parent)\n\n while (current !== undefined) {\n if (ids.has(current.id)) hits++\n current = current.parent === null ? undefined : byId.get(current.parent)\n }\n\n return hits === members.length - 1\n}\n", "export type Rgba = { r: number; g: number; b: number; a: number }\n\n/**\n * Parses the forms `getComputedStyle` actually returns in Chrome: `rgb(...)`,\n * `rgba(...)`, plus hex and `transparent` for hand-written graphs.\n */\nexport function parseColor(value: string): Rgba | null {\n const text = value.trim().toLowerCase()\n\n if (text === '' || text === 'transparent') return null\n if (text.startsWith('#')) return parseHex(text)\n\n const match = text.match(/^rgba?\\(([^)]+)\\)$/)\n if (match === null) return null\n\n const body = match[1]\n if (body === undefined) return null\n\n const parts = body.split(/[,/\\s]+/).filter((part) => part !== '')\n if (parts.length < 3) return null\n\n const [r, g, b, a] = parts\n\n return {\n r: Number(r),\n g: Number(g),\n b: Number(b),\n a: a === undefined ? 1 : parseAlpha(a),\n }\n}\n\nfunction parseAlpha(value: string): number {\n if (value.endsWith('%')) return Number(value.slice(0, -1)) / 100\n return Number(value)\n}\n\nfunction parseHex(text: string): Rgba | null {\n const hex = text.slice(1)\n\n if (hex.length === 3 || hex.length === 4) {\n const [r, g, b, a] = hex.split('')\n if (r === undefined || g === undefined || b === undefined) return null\n\n return {\n r: Number.parseInt(r + r, 16),\n g: Number.parseInt(g + g, 16),\n b: Number.parseInt(b + b, 16),\n a: a === undefined ? 1 : Number.parseInt(a + a, 16) / 255,\n }\n }\n\n if (hex.length === 6 || hex.length === 8) {\n return {\n r: Number.parseInt(hex.slice(0, 2), 16),\n g: Number.parseInt(hex.slice(2, 4), 16),\n b: Number.parseInt(hex.slice(4, 6), 16),\n a: hex.length === 8 ? Number.parseInt(hex.slice(6, 8), 16) / 255 : 1,\n }\n }\n\n return null\n}\n\n/** Source over destination, both in sRGB. */\nexport function blend(source: Rgba, destination: Rgba): Rgba {\n const a = source.a + destination.a * (1 - source.a)\n if (a === 0) return { r: 0, g: 0, b: 0, a: 0 }\n\n const mix = (src: number, dst: number): number =>\n (src * source.a + dst * destination.a * (1 - source.a)) / a\n\n return {\n r: mix(source.r, destination.r),\n g: mix(source.g, destination.g),\n b: mix(source.b, destination.b),\n a,\n }\n}\n\nexport function luminance(color: Rgba): number {\n const channel = (value: number): number => {\n const s = value / 255\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4\n }\n\n return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b)\n}\n\nexport function contrastRatio(a: Rgba, b: Rgba): number {\n const first = luminance(a)\n const second = luminance(b)\n const lighter = Math.max(first, second)\n const darker = Math.min(first, second)\n\n return (lighter + 0.05) / (darker + 0.05)\n}\n", "export const MAX_NODES = 5000\n\n/** Base grid drawn by the overlay. */\nexport const GRID_STEP = 8\n\n/** Spacing scale enforced by the spacing rule. */\nexport const SPACING_SCALE = 4\n\nexport const OVERLAY_HOST_ID = '__litedesign_overlay__'\n\n/** Upper bound on markers drawn per layer, so a full page stays under 16ms. */\nexport const MAX_MARKERS = 250\n", "import { axisGap, bottom, overlapsOn, right, round } from './geometry.js'\nimport type { Axis, Gap, GraphNode } from './types.js'\n\n/**\n * Gaps between consecutive siblings.\n *\n * The axis is decided by geometry, not by `flex-direction`: sort the siblings\n * on an axis and keep consecutive pairs that overlap enough on the cross axis.\n * A column stack therefore produces only vertical gaps, and a row only\n * horizontal ones.\n */\nexport function findSiblingGaps(nodes: GraphNode[]): Gap[] {\n const byParent = new Map<string | null, GraphNode[]>()\n\n for (const node of nodes) {\n const siblings = byParent.get(node.parent)\n if (siblings) siblings.push(node)\n else byParent.set(node.parent, [node])\n }\n\n const gaps: Gap[] = []\n\n for (const siblings of byParent.values()) {\n gaps.push(...axisGaps(siblings, 'x'), ...axisGaps(siblings, 'y'))\n }\n\n return gaps\n}\n\nfunction axisGaps(siblings: GraphNode[], axis: Axis): Gap[] {\n const sorted = [...siblings].sort((a, b) =>\n axis === 'x' ? a.rect.x - b.rect.x : a.rect.y - b.rect.y,\n )\n\n const gaps: Gap[] = []\n\n for (let i = 0; i < sorted.length - 1; i++) {\n const a = sorted[i]\n const b = sorted[i + 1]\n if (a === undefined || b === undefined) continue\n\n const distance = axisGap(a.rect, b.rect, axis)\n if (distance < 0.5) continue\n\n const cross: Axis = axis === 'x' ? 'y' : 'x'\n if (!overlapsOn(a.rect, b.rect, cross)) continue\n\n gaps.push({ a: a.id, b: b.id, axis, distance: round(distance), kind: 'sibling' })\n }\n\n return gaps\n}\n\n/**\n * Nearest neighbour in each direction, even when it is not a sibling.\n *\n * A candidate must share at least half of the smaller rect on the cross axis,\n * so a box does not report a gap to something diagonally adjacent. `a` is\n * always the left/top node and `b` the right/bottom one.\n *\n * Each direction keeps its own sorted index, so the scan starts at the first\n * candidate that could be a neighbour instead of walking the whole list.\n */\nexport function findVisualGaps(nodes: GraphNode[]): Gap[] {\n const seen = new Set<string>()\n const gaps: Gap[] = []\n\n const push = (a: GraphNode, b: GraphNode, axis: Axis, distance: number): void => {\n const key = pairKey(a.id, b.id, axis)\n if (seen.has(key)) return\n seen.add(key)\n gaps.push({ a: a.id, b: b.id, axis, distance: round(distance), kind: 'visual' })\n }\n\n const byX = [...nodes].sort((a, b) => a.rect.x - b.rect.x)\n const byRight = [...nodes].sort((a, b) => right(a.rect) - right(b.rect))\n const byY = [...nodes].sort((a, b) => a.rect.y - b.rect.y)\n const byBottom = [...nodes].sort((a, b) => bottom(a.rect) - bottom(b.rect))\n\n for (const a of nodes) {\n for (let j = firstAtLeast(byX, right(a.rect) - 0.5, (n) => n.rect.x); j < byX.length; j++) {\n const b = byX[j]\n if (b === undefined) continue\n if (!overlapsOn(a.rect, b.rect, 'y')) continue\n push(a, b, 'x', b.rect.x - right(a.rect))\n break\n }\n\n for (let j = lastAtMost(byRight, a.rect.x + 0.5, (n) => right(n.rect)); j >= 0; j--) {\n const b = byRight[j]\n if (b === undefined) continue\n if (!overlapsOn(a.rect, b.rect, 'y')) continue\n push(b, a, 'x', a.rect.x - right(b.rect))\n break\n }\n\n for (let j = firstAtLeast(byY, bottom(a.rect) - 0.5, (n) => n.rect.y); j < byY.length; j++) {\n const b = byY[j]\n if (b === undefined) continue\n if (!overlapsOn(a.rect, b.rect, 'x')) continue\n push(a, b, 'y', b.rect.y - bottom(a.rect))\n break\n }\n\n for (let j = lastAtMost(byBottom, a.rect.y + 0.5, (n) => bottom(n.rect)); j >= 0; j--) {\n const b = byBottom[j]\n if (b === undefined) continue\n if (!overlapsOn(a.rect, b.rect, 'x')) continue\n push(b, a, 'y', a.rect.y - bottom(b.rect))\n break\n }\n }\n\n return gaps\n}\n\n/** Sibling gaps win over the visual gap for the same pair and axis. */\nexport function findGaps(nodes: GraphNode[]): Gap[] {\n const siblings = findSiblingGaps(nodes)\n const claimed = new Set(siblings.map((gap) => pairKey(gap.a, gap.b, gap.axis)))\n const visual = findVisualGaps(nodes).filter(\n (gap) => !claimed.has(pairKey(gap.a, gap.b, gap.axis)),\n )\n\n return [...siblings, ...visual]\n}\n\nfunction pairKey(a: string, b: string, axis: Axis): string {\n return a < b ? `${a}|${b}|${axis}` : `${b}|${a}|${axis}`\n}\n\n/** First index whose value is >= target. */\nfunction firstAtLeast<T>(list: T[], target: number, value: (item: T) => number): number {\n let low = 0\n let high = list.length\n\n while (low < high) {\n const middle = (low + high) >> 1\n const item = list[middle]\n if (item !== undefined && value(item) < target) low = middle + 1\n else high = middle\n }\n\n return low\n}\n\n/** Last index whose value is <= target, or -1. */\nfunction lastAtMost<T>(list: T[], target: number, value: (item: T) => number): number {\n let low = 0\n let high = list.length\n\n while (low < high) {\n const middle = (low + high) >> 1\n const item = list[middle]\n if (item !== undefined && value(item) <= target) low = middle + 1\n else high = middle\n }\n\n return low - 1\n}\n", "import type { Box, GraphNode, Styles } from './types.js'\n\nconst MAX_TEXT = 80\n\nexport function extractNode(\n el: Element,\n id: string,\n parentId: string | null,\n depth: number,\n): GraphNode {\n const rect = el.getBoundingClientRect()\n\n return {\n id,\n selector: id,\n tag: el.tagName.toLowerCase(),\n rect: {\n x: rect.left + window.scrollX,\n y: rect.top + window.scrollY,\n w: rect.width,\n h: rect.height,\n },\n box: readBox(el),\n text: readText(el),\n depth,\n parent: parentId,\n children: [],\n styles: readStyles(el),\n }\n}\n\nfunction readBox(el: Element): Box {\n return {\n scrollW: el.scrollWidth,\n scrollH: el.scrollHeight,\n clientW: el.clientWidth,\n clientH: el.clientHeight,\n }\n}\n\nfunction readText(el: Element): string {\n let text = ''\n\n for (const node of Array.from(el.childNodes)) {\n if (node.nodeType === 3) text += node.textContent ?? ''\n }\n\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_TEXT)\n}\n\nfunction readStyles(el: Element): Styles {\n const style = getComputedStyle(el)\n\n return {\n display: style.display,\n borderRadius: style.borderRadius,\n color: style.color,\n backgroundColor: style.backgroundColor,\n fontSize: style.fontSize,\n fontWeight: style.fontWeight,\n padding: style.padding,\n margin: style.margin,\n gap: style.gap,\n }\n}\n", "import type { Graph, Issue, Severity } from '../types.js'\n\n/**\n * A rule reads a graph and returns issues. No DOM, no async, no I/O.\n *\n * The `id` lives on the function so the MCP bridge can list and validate rule\n * names without keeping a second hand-written list in sync.\n */\nexport type Rule = ((graph: Graph) => Issue[]) & { id: string }\n\nexport function defineRule(id: string, run: (graph: Graph) => Issue[]): Rule {\n return Object.assign(run, { id })\n}\n\ntype IssueInput = {\n rule: string\n selector: string\n severity: Severity\n actual: string\n expected: string\n autoFix: boolean\n /** Disambiguates several issues of the same rule on the same element. */\n key?: string\n}\n\nexport function issue(input: IssueInput): Issue {\n const suffix = input.key === undefined ? '' : `:${input.key}`\n\n return {\n id: `${input.rule}:${input.selector}${suffix}`,\n selector: input.selector,\n rule: input.rule,\n severity: input.severity,\n actual: input.actual,\n expected: input.expected,\n autoFix: input.autoFix,\n }\n}\n", "import { EDGES } from '../align.js'\nimport type { Issue } from '../types.js'\nimport { defineRule, issue } from './rule.js'\n\n/** Anything within this is already a guide, not a problem. */\nconst TOLERANCE = 2\n/** Anything within this but beyond TOLERANCE is a near miss worth reporting. */\nconst WINDOW = 4\n\n/**\n * Edges that almost line up. `findGuides` keeps clusters inside 2px; this rule\n * looks at the band just outside that, where the eye still reads the elements\n * as one column but the numbers disagree.\n *\n * The root node is skipped: the page container has no sibling to align with,\n * and its center is just half the document.\n */\nexport const alignmentNearMiss = defineRule('alignment-near-miss', (graph) => {\n const issues: Issue[] = []\n\n for (const spec of EDGES) {\n const items = graph.nodes\n .filter((node) => node.parent !== null)\n .map((node) => ({ node, value: spec.value(node.rect) }))\n .sort((a, b) => a.value - b.value)\n\n let start = 0\n\n for (let i = 1; i <= items.length; i++) {\n const previous = items[i - 1]\n const current = items[i]\n const breaks =\n current === undefined || previous === undefined || current.value - previous.value > WINDOW\n if (!breaks) continue\n\n const cluster = items.slice(start, i)\n start = i\n\n if (cluster.length < 2) continue\n\n const first = cluster[0]\n const last = cluster[cluster.length - 1]\n if (first === undefined || last === undefined) continue\n if (last.value - first.value <= TOLERANCE) continue\n\n const target = cluster[Math.floor(cluster.length / 2)]\n if (target === undefined) continue\n\n let worst = cluster[0]\n if (worst === undefined) continue\n\n for (const item of cluster) {\n if (Math.abs(item.value - target.value) > Math.abs(worst.value - target.value)) worst = item\n }\n\n issues.push(\n issue({\n rule: 'alignment-near-miss',\n selector: worst.node.id,\n key: spec.edge,\n severity: 'P2',\n actual: `${Math.round(worst.value * 10) / 10}px`,\n expected: `${Math.round(target.value * 10) / 10}px`,\n autoFix: false,\n }),\n )\n }\n }\n\n return issues\n})\n", "import { blend, contrastRatio, parseColor, type Rgba } from '../color.js'\nimport type { GraphNode, Issue } from '../types.js'\nimport { defineRule, issue } from './rule.js'\n\nconst WHITE: Rgba = { r: 255, g: 255, b: 255, a: 1 }\n\nconst NORMAL_MINIMUM = 4.5\nconst LARGE_MINIMUM = 3\n\n/**\n * WCAG contrast for every element that owns text. The background is resolved by\n * walking the parent chain in the graph, so the rule never touches the DOM.\n */\nexport const contrastMinimum = defineRule('contrast', (graph) => {\n const byId = new Map(graph.nodes.map((node) => [node.id, node]))\n const issues: Issue[] = []\n\n for (const node of graph.nodes) {\n if (node.text === '') continue\n\n const foreground = parseColor(node.styles.color)\n if (foreground === null) continue\n\n const background = backgroundOf(node, byId)\n const ratio = contrastRatio(blend(foreground, background), background)\n const minimum = isLargeText(node) ? LARGE_MINIMUM : NORMAL_MINIMUM\n\n if (ratio >= minimum) continue\n\n issues.push(\n issue({\n rule: 'contrast',\n selector: node.id,\n severity: 'P1',\n actual: `${Math.round(ratio * 100) / 100}:1`,\n expected: `>= ${minimum}:1`,\n autoFix: false,\n }),\n )\n }\n\n return issues\n})\n\nfunction isLargeText(node: GraphNode): boolean {\n const size = Number.parseFloat(node.styles.fontSize)\n const weight = Number.parseInt(node.styles.fontWeight, 10)\n\n if (!Number.isFinite(size)) return false\n\n return size >= 24 || (size >= 18.66 && weight >= 700)\n}\n\n/**\n * Composite every background from the nearest ancestor up to the first opaque\n * one, then fall back to white.\n */\nfunction backgroundOf(node: GraphNode, byId: Map<string, GraphNode>): Rgba {\n const layers: Rgba[] = []\n let current: GraphNode | undefined = node\n\n while (current !== undefined) {\n const color = parseColor(current.styles.backgroundColor)\n\n if (color !== null && color.a > 0) {\n layers.push(color)\n if (color.a === 1) break\n }\n\n current = current.parent === null ? undefined : byId.get(current.parent)\n }\n\n let background = WHITE\n\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]\n if (layer === undefined) continue\n background = blend(layer, background)\n }\n\n return background\n}\n", "import type { Issue } from '../types.js'\nimport { defineRule, issue } from './rule.js'\n\n/** Sub-pixel scroll noise is not an overflow. */\nconst SLACK = 1\n\n/**\n * Content wider or taller than its own client box. Visible overflow and\n * clipped overflow both count: the first is a layout bug, the second is content\n * the user cannot reach.\n */\nexport const overflowClipped = defineRule('overflow', (graph) => {\n const issues: Issue[] = []\n\n for (const node of graph.nodes) {\n if (node.styles.display.startsWith('inline')) continue\n if (node.box.clientW === 0 && node.box.clientH === 0) continue\n\n if (node.box.scrollW > node.box.clientW + SLACK) {\n issues.push(\n issue({\n rule: 'overflow',\n selector: node.id,\n key: 'x',\n severity: 'P2',\n actual: `${node.box.scrollW}px content in ${node.box.clientW}px`,\n expected: 'content fits horizontally',\n autoFix: false,\n }),\n )\n }\n\n if (node.box.scrollH > node.box.clientH + SLACK) {\n issues.push(\n issue({\n rule: 'overflow',\n selector: node.id,\n key: 'y',\n severity: 'P2',\n actual: `${node.box.scrollH}px content in ${node.box.clientH}px`,\n expected: 'content fits vertically',\n autoFix: false,\n }),\n )\n }\n }\n\n return issues\n})\n", "import type { GraphNode, Issue } from '../types.js'\nimport { defineRule, issue } from './rule.js'\n\n/** Below this sample size the majority is not a signal. */\nconst MIN_SAMPLES = 4\n\n/**\n * Radius should be a token, not a mood. The most common radius wins; every\n * other value is reported once per node. Pills and circles are skipped: their\n * radius is derived from size, so it is not part of the same scale.\n */\nexport const radiusConsistency = defineRule('radius-consistency', (graph) => {\n const groups = new Map<string, GraphNode[]>()\n\n for (const node of graph.nodes) {\n const radius = normalizeRadius(node.styles.borderRadius)\n if (radius === null) continue\n\n const group = groups.get(radius)\n if (group) group.push(node)\n else groups.set(radius, [node])\n }\n\n if (groups.size < 2) return []\n\n const total = [...groups.values()].reduce((sum, group) => sum + group.length, 0)\n if (total < MIN_SAMPLES) return []\n\n const ranked = [...groups.entries()].sort((a, b) => b[1].length - a[1].length)\n const expected = ranked[0]\n if (expected === undefined) return []\n\n const [expectedValue, expectedNodes] = expected\n const issues: Issue[] = []\n\n for (const [value, nodes] of ranked.slice(1)) {\n if (nodes.length >= expectedNodes.length) continue\n\n for (const node of nodes) {\n if (isPill(node)) continue\n\n issues.push(\n issue({\n rule: 'radius-consistency',\n selector: node.id,\n severity: 'P3',\n actual: value,\n expected: expectedValue,\n autoFix: true,\n }),\n )\n }\n }\n\n return issues\n})\n\nfunction normalizeRadius(value: string): string | null {\n const text = value.trim()\n if (text === '' || text === '0px' || text === '0') return null\n\n const parts = text.split(/\\s+/)\n const unique = [...new Set(parts)]\n\n if (unique.length === 1) return unique[0] ?? null\n\n return parts.join(' ')\n}\n\nfunction isPill(node: GraphNode): boolean {\n const text = node.styles.borderRadius\n if (text.includes('%')) return true\n\n const radius = Number.parseFloat(text)\n if (!Number.isFinite(radius)) return false\n\n return radius >= Math.min(node.rect.w, node.rect.h) / 2\n}\n", "import { SPACING_SCALE } from '../constants.js'\nimport type { Issue } from '../types.js'\nimport { defineRule, issue } from './rule.js'\n\n/**\n * Sibling gaps should sit on the spacing scale. Visual gaps are skipped: they\n * are an observation about two unrelated boxes, not a value anyone authored.\n */\nexport const spacingScale = defineRule('spacing-scale', (graph) => {\n const issues: Issue[] = []\n\n for (const gap of graph.gaps) {\n if (gap.kind !== 'sibling') continue\n\n const actual = Math.round(gap.distance)\n if (actual <= 0 || actual % SPACING_SCALE === 0) continue\n\n issues.push(\n issue({\n rule: 'spacing-scale',\n selector: gap.a,\n key: `${gap.axis}:${gap.b}`,\n severity: 'P2',\n actual: `${actual}px`,\n expected: `${Math.round(actual / SPACING_SCALE) * SPACING_SCALE}px`,\n autoFix: true,\n }),\n )\n }\n\n return issues\n})\n", "import type { Graph, Issue } from '../types.js'\nimport { alignmentNearMiss } from './alignment.js'\nimport { contrastMinimum } from './contrast.js'\nimport { overflowClipped } from './overflow.js'\nimport { radiusConsistency } from './radius.js'\nimport type { Rule } from './rule.js'\nimport { spacingScale } from './spacing.js'\n\nexport const defaultRules: Rule[] = [\n spacingScale,\n alignmentNearMiss,\n radiusConsistency,\n overflowClipped,\n contrastMinimum,\n]\n\n/** Stable names accepted by `find_issues` and `screenshot_annotated`. */\nexport const RULE_IDS: string[] = defaultRules.map((rule) => rule.id)\n\nexport function findIssues(graph: Graph, rules: Rule[] = defaultRules): Issue[] {\n return rules.flatMap((rule) => rule(graph))\n}\n\nexport type { Rule }\n", "import { MAX_NODES, OVERLAY_HOST_ID } from './constants.js'\n\nexport type WalkEntry = {\n el: Element\n /** Structural path, built from the parent path instead of re-walking the DOM. */\n id: string\n depth: number\n /** Index of the nearest included ancestor, or -1 for the root. */\n parent: number\n}\n\nconst SKIP_TAGS = new Set([\n 'script',\n 'style',\n 'link',\n 'meta',\n 'noscript',\n 'template',\n 'head',\n 'title',\n 'base',\n])\n\nconst SHADOW_MARKER = ':host'\n\n/**\n * Structural path, stable across renders as long as sibling order does not\n * change. Not a valid CSS selector across a shadow boundary, which is why the\n * boundary is marked explicitly instead of pretending it is one.\n */\nexport function pathOf(el: Element): string {\n const parts: string[] = []\n let cur: Element | null = el\n\n while (cur !== null) {\n const parent: Element | null = cur.parentElement\n\n if (parent !== null) {\n const index = Array.prototype.indexOf.call(parent.children, cur) + 1\n parts.unshift(`${cur.tagName.toLowerCase()}:nth-child(${index})`)\n cur = parent\n continue\n }\n\n const host = shadowHostOf(cur)\n if (host === null) break\n parts.unshift(SHADOW_MARKER)\n cur = host\n }\n\n return parts.length > 0 ? parts.join(' > ') : el.tagName.toLowerCase()\n}\n\nfunction shadowHostOf(el: Element): Element | null {\n const root = el.getRootNode() as { host?: Element }\n return root.host ?? null\n}\n\n/**\n * Depth-first walk that returns the elements worth measuring.\n *\n * Elements without a box are not measured, but their children still are: an\n * absolutely positioned child of a zero-height wrapper is real layout. The same\n * applies to `display: contents`. Paths still include the skipped element, so\n * they stay unique.\n */\nexport function collectElements(root: Element, maxNodes = MAX_NODES): WalkEntry[] {\n const entries: WalkEntry[] = []\n const rootPath = pathOf(root)\n\n const visit = (\n el: Element,\n parent: number,\n depth: number,\n index: number,\n boundary: boolean,\n parentPath: string | null,\n ): void => {\n if (entries.length >= maxNodes) return\n if (el.id === OVERLAY_HOST_ID) return\n\n const tag = el.tagName.toLowerCase()\n if (SKIP_TAGS.has(tag)) return\n if (!isVisible(el)) return\n\n const marker = boundary ? ` ${SHADOW_MARKER} > ` : ' > '\n const id = parentPath === null ? rootPath : `${parentPath}${marker}${tag}:nth-child(${index})`\n\n let self = parent\n\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 || rect.height > 0) {\n entries.push({ el, id, depth, parent })\n self = entries.length - 1\n }\n\n const children = Array.from(el.children)\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child !== undefined) visit(child, self, depth + 1, i + 1, false, id)\n }\n\n const shadow = el.shadowRoot\n if (shadow !== null) {\n const shadowChildren = Array.from(shadow.children)\n for (let i = 0; i < shadowChildren.length; i++) {\n const child = shadowChildren[i]\n if (child !== undefined) visit(child, self, depth + 1, i + 1, true, id)\n }\n }\n }\n\n visit(root, -1, 0, 0, false, null)\n return entries\n}\n\n/**\n * `checkVisibility` skips `display: none` without building a\n * CSSStyleDeclaration, which halves the style reads per node. Elements with\n * `visibility: hidden` still occupy layout, so they stay measured.\n */\nfunction isVisible(el: Element): boolean {\n if (typeof el.checkVisibility === 'function') return el.checkVisibility()\n return getComputedStyle(el).display !== 'none'\n}\n", "import { findGuides } from './align.js'\nimport { MAX_NODES } from './constants.js'\nimport { extractNode } from './extract.js'\nimport { findGaps } from './gaps.js'\nimport { findIssues } from './rules/index.js'\nimport type { Graph, GraphNode } from './types.js'\nimport { collectElements, pathOf } from './walk.js'\n\n/**\n * Turns the live page into a measurement graph.\n *\n * Everything after `collectElements` is pure data, which is why the rules can\n * be tested in Node without a DOM.\n */\nexport function buildGraph(root: Element | null = null): Graph {\n const start = root ?? (typeof document === 'undefined' ? null : document.body)\n\n if (start === null) return emptyGraph()\n\n const entries = collectElements(start)\n const nodes: GraphNode[] = []\n const byId = new Map<string, GraphNode>()\n const ids: string[] = []\n\n for (const entry of entries) {\n const parentId = entry.parent >= 0 ? (ids[entry.parent] ?? null) : null\n const node = extractNode(entry.el, entry.id, parentId, entry.depth)\n\n ids.push(node.id)\n nodes.push(node)\n byId.set(node.id, node)\n if (parentId !== null) byId.get(parentId)?.children.push(node.id)\n }\n\n const graph: Graph = {\n url: typeof location === 'undefined' ? '' : location.href,\n viewport: {\n w: typeof innerWidth === 'undefined' ? 0 : innerWidth,\n h: typeof innerHeight === 'undefined' ? 0 : innerHeight,\n },\n nodes,\n gaps: findGaps(nodes),\n guides: findGuides(nodes),\n issues: [],\n truncated: entries.length >= MAX_NODES,\n }\n\n graph.issues = findIssues(graph)\n\n return graph\n}\n\n/**\n * Resolves a structural path or a CSS selector to one node in the graph.\n *\n * Structural paths are matched first because they are what `find_issues`\n * returns. Anything else is handed to `document.querySelector` and converted\n * back to a structural path, so both drivers accept the same selectors.\n */\nexport function resolveNode(graph: Graph, selector: string): GraphNode | null {\n const direct = graph.nodes.find((node) => node.id === selector)\n if (direct !== undefined) return direct\n\n if (typeof document === 'undefined') return null\n\n let element: Element | null = null\n\n try {\n element = document.querySelector(selector)\n } catch {\n return null\n }\n\n if (element === null) return null\n\n const id = pathOf(element)\n return graph.nodes.find((node) => node.id === id) ?? null\n}\n\nfunction emptyGraph(): Graph {\n return {\n url: '',\n viewport: { w: 0, h: 0 },\n nodes: [],\n gaps: [],\n guides: [],\n issues: [],\n truncated: false,\n }\n}\n", "import { GRID_STEP, MAX_MARKERS } from '../constants.js'\nimport { bottom, right, round } from '../geometry.js'\nimport type { Graph, GraphNode, Severity } from '../types.js'\n\nexport const LAYERS = ['grid', 'guide', 'gap', 'issue', 'hover'] as const\nexport type LayerName = (typeof LAYERS)[number]\n\nconst GUIDE_COLOR = {\n left: 'rgba(236, 72, 153, 0.55)',\n right: 'rgba(236, 72, 153, 0.55)',\n center: 'rgba(168, 85, 247, 0.55)',\n top: 'rgba(236, 72, 153, 0.55)',\n bottom: 'rgba(236, 72, 153, 0.55)',\n} as const\n\nconst GAP_COLOR = 'rgba(14, 165, 233, 0.9)'\n\nconst GUIDE_PADDING = 8\n\n/** Above this many gaps, labels are unreadable and expensive. */\nconst LABEL_LIMIT = 100\n\nconst SEVERITY_COLOR: Record<Severity, string> = {\n P0: '#dc2626',\n P1: '#f97316',\n P2: '#eab308',\n P3: '#3b82f6',\n}\n\nconst BASE = 'position:absolute;pointer-events:none'\n\nexport function createLayers(shadow: ShadowRoot): Record<LayerName, HTMLDivElement> {\n const layers = {} as Record<LayerName, HTMLDivElement>\n\n for (const name of LAYERS) {\n const layer = document.createElement('div')\n layer.dataset.layer = name\n layer.style.cssText = `${BASE};inset:0`\n shadow.append(layer)\n layers[name] = layer\n }\n\n return layers\n}\n\nexport function drawGrid(layer: HTMLElement): void {\n layer.replaceChildren()\n layer.style.backgroundImage = `repeating-linear-gradient(to right, rgba(59, 130, 246, 0.16) 0 1px, transparent 1px ${GRID_STEP}px)`\n}\n\nexport function drawGuides(layer: HTMLElement, graph: Graph): void {\n layer.replaceChildren()\n\n const byId = new Map(graph.nodes.map((node) => [node.id, node]))\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n for (const guide of graph.guides.slice(0, MAX_MARKERS)) {\n const span = spanOf(guide, byId)\n if (span === null) continue\n\n const color = GUIDE_COLOR[guide.edge]\n const [start, end] = span\n\n if (guide.axis === 'x') {\n box(\n layer,\n `left:${guide.value - scrollX}px;top:${start - scrollY}px;width:1px;height:${end - start}px;background:${color}`,\n )\n } else {\n box(\n layer,\n `top:${guide.value - scrollY}px;left:${start - scrollX}px;height:1px;width:${end - start}px;background:${color}`,\n )\n }\n }\n}\n\n/** Vertical or horizontal extent covered by a guide's members, with padding. */\nfunction spanOf(\n guide: Graph['guides'][number],\n byId: Map<string, GraphNode>,\n): [number, number] | null {\n let start = Number.POSITIVE_INFINITY\n let end = Number.NEGATIVE_INFINITY\n\n for (const id of guide.members) {\n const node = byId.get(id)\n if (node === undefined) continue\n\n const from = guide.axis === 'x' ? node.rect.y : node.rect.x\n const to = guide.axis === 'x' ? bottom(node.rect) : right(node.rect)\n\n start = Math.min(start, from)\n end = Math.max(end, to)\n }\n\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null\n\n return [start - GUIDE_PADDING, end + GUIDE_PADDING]\n}\n\nexport function drawGaps(layer: HTMLElement, graph: Graph): void {\n layer.replaceChildren()\n\n const byId = new Map(graph.nodes.map((node) => [node.id, node]))\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n // On a dense page the labels overlap into noise and double the element count.\n const showLabels = graph.gaps.length <= LABEL_LIMIT\n\n for (const gap of graph.gaps.slice(0, MAX_MARKERS)) {\n const a = byId.get(gap.a)\n const b = byId.get(gap.b)\n if (a === undefined || b === undefined) continue\n\n if (gap.axis === 'x') {\n const start = right(a.rect)\n const middle = (Math.max(a.rect.y, b.rect.y) + Math.min(bottom(a.rect), bottom(b.rect))) / 2\n\n box(\n layer,\n `left:${start - scrollX}px;top:${middle - scrollY}px;width:${gap.distance}px;height:1px;background:${GAP_COLOR}`,\n )\n if (showLabels) {\n label(\n layer,\n `${round(gap.distance, 1)}`,\n start + gap.distance / 2 - scrollX,\n middle - scrollY,\n )\n }\n continue\n }\n\n const start = bottom(a.rect)\n const middle = (Math.max(a.rect.x, b.rect.x) + Math.min(right(a.rect), right(b.rect))) / 2\n\n box(\n layer,\n `left:${middle - scrollX}px;top:${start - scrollY}px;width:1px;height:${gap.distance}px;background:${GAP_COLOR}`,\n )\n if (showLabels) {\n label(\n layer,\n `${round(gap.distance, 1)}`,\n middle - scrollX,\n start + gap.distance / 2 - scrollY,\n )\n }\n }\n}\n\nexport function drawIssues(layer: HTMLElement, graph: Graph): void {\n layer.replaceChildren()\n\n const byId = new Map(graph.nodes.map((node) => [node.id, node]))\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n // On a dense page the labels overlap into noise and double the element count.\n const showLabels = graph.issues.length <= LABEL_LIMIT\n\n for (const item of graph.issues.slice(0, MAX_MARKERS)) {\n const node = byId.get(item.selector)\n if (node === undefined) continue\n\n const color = SEVERITY_COLOR[item.severity]\n const left = node.rect.x - scrollX\n const top = node.rect.y - scrollY\n\n box(\n layer,\n `left:${left}px;top:${top}px;width:${node.rect.w}px;height:${node.rect.h}px;border:1px solid ${color};border-radius:2px`,\n )\n\n if (!showLabels || !onScreen(left, top, node.rect.w, node.rect.h)) continue\n\n tag(layer, `${item.severity} \u00B7 ${item.actual} \u2192 ${item.expected}`, left + 2, top + 2, color)\n }\n}\n\n/** Viewport-space check: labels for boxes scrolled out of view are wasted DOM. */\nfunction onScreen(x: number, y: number, w: number, h: number): boolean {\n return x + w > 0 && y + h > 0 && x < window.innerWidth && y < window.innerHeight\n}\n\nfunction tag(layer: HTMLElement, text: string, x: number, y: number, color: string): void {\n const element = box(\n layer,\n `left:${x}px;top:${y}px;padding:1px 4px;border-radius:3px;background:${color};color:#fff;font:10px/1.3 ui-monospace,monospace;white-space:nowrap`,\n )\n\n element.textContent = text\n}\n\nconst HOVER_BORDER = 'rgba(59, 130, 246, 0.9)'\nconst HOVER_FILL = 'rgba(59, 130, 246, 0.08)'\n\n/**\n * Outline plus box-model card for the hovered node. The node rect is in\n * document space, so scrolling can redraw the hover from the last graph.\n */\nexport function drawHover(layer: HTMLElement, node: GraphNode | null): void {\n layer.replaceChildren()\n if (node === null) return\n\n const left = node.rect.x - window.scrollX\n const top = node.rect.y - window.scrollY\n\n box(\n layer,\n `left:${left}px;top:${top}px;width:${node.rect.w}px;height:${node.rect.h}px;border:1px solid ${HOVER_BORDER};background:${HOVER_FILL}`,\n )\n\n const lines = [\n `${node.tag} ${round(node.rect.w, 0)} \u00D7 ${round(node.rect.h, 0)}`,\n `padding ${node.styles.padding}`,\n `margin ${node.styles.margin}`,\n ]\n\n if (node.styles.gap !== 'normal' && node.styles.gap !== '0px') {\n lines.push(`gap ${node.styles.gap}`)\n }\n\n // Below the top edge the card would leave the viewport; put it inside.\n const above = top > 72\n\n card(\n layer,\n lines.join('\\n'),\n left,\n above ? top - 6 : top + 6,\n above ? 'translateY(-100%)' : 'none',\n )\n}\n\nfunction card(layer: HTMLElement, text: string, x: number, y: number, transform: string): void {\n const element = box(\n layer,\n `left:${x}px;top:${y}px;transform:${transform};padding:6px 8px;border-radius:6px;background:rgba(17, 17, 17, 0.92);color:#fff;font:11px/1.5 ui-monospace,monospace;white-space:pre`,\n )\n\n element.textContent = text\n}\n\nfunction box(layer: HTMLElement, css: string): HTMLDivElement {\n const element = document.createElement('div')\n element.style.cssText = `${BASE};${css}`\n layer.append(element)\n return element\n}\n\nfunction label(layer: HTMLElement, text: string, x: number, y: number): void {\n const element = box(\n layer,\n `left:${x}px;top:${y}px;transform:translate(-50%,-50%);padding:1px 3px;border-radius:3px;background:#111;color:#fff;font:10px/1.2 ui-monospace,monospace;white-space:nowrap`,\n )\n\n element.textContent = text\n}\n", "import { OVERLAY_HOST_ID } from '../constants.js'\nimport type { Graph, GraphNode } from '../types.js'\nimport { pathOf } from '../walk.js'\nimport {\n createLayers,\n drawGaps,\n drawGrid,\n drawGuides,\n drawHover,\n drawIssues,\n LAYERS,\n type LayerName,\n} from './layers.js'\n\nexport type OverlayOptions = {\n layers?: LayerName[]\n /** Extension UI, appended above the layers inside the same shadow root. */\n toolbar?: HTMLElement\n}\n\nexport type OverlayHandle = {\n host: HTMLElement\n update(graph: Graph): void\n setLayers(names: LayerName[]): void\n destroy(): void\n}\n\n/**\n * Mounts a fixed, pointer-transparent overlay in a closed shadow root.\n *\n * The host is appended to `documentElement`, never to `body`, so it cannot\n * affect the page's flow. Coordinates are document-space; scroll and resize\n * redraw from the last graph instead of re-measuring.\n */\nexport function render(graph: Graph, options: OverlayOptions = {}): OverlayHandle {\n const host = document.createElement('div')\n host.id = OVERLAY_HOST_ID\n host.style.cssText =\n 'position:fixed;inset:0;pointer-events:none;z-index:2147483647;contain:strict'\n\n const shadow = host.attachShadow({ mode: 'closed' })\n\n // The overlay is viewport chrome, not page content; never print it.\n const printStyle = document.createElement('style')\n printStyle.textContent = '@media print { :host { display: none !important } }'\n shadow.append(printStyle)\n\n const layers = createLayers(shadow)\n\n if (options.toolbar !== undefined) shadow.append(options.toolbar)\n\n document.documentElement.append(host)\n\n let current = graph\n let byId = indexNodes(graph)\n let hovered: string | null = null\n let hoverTarget: Element | null = null\n let hoverFrame = 0\n let visible = new Set<LayerName>(options.layers ?? LAYERS)\n let frame = 0\n\n const draw = (): void => {\n frame = 0\n\n for (const name of LAYERS) {\n layers[name].style.display = visible.has(name) ? 'block' : 'none'\n }\n\n drawGrid(layers.grid)\n drawGuides(layers.guide, current)\n drawGaps(layers.gap, current)\n drawIssues(layers.issue, current)\n drawHover(layers.hover, hovered === null ? null : (byId.get(hovered) ?? null))\n }\n\n const schedule = (): void => {\n if (frame !== 0) return\n frame = requestAnimationFrame(draw)\n }\n\n const onScroll = (): void => schedule()\n const onResize = (): void => schedule()\n\n const applyHover = (): void => {\n hoverFrame = 0\n const target = hoverTarget\n\n if (target === null) {\n hovered = null\n drawHover(layers.hover, null)\n return\n }\n\n const id = pathOf(target)\n const node = byId.get(id) ?? null\n\n hovered = node === null ? null : id\n drawHover(layers.hover, node)\n }\n\n const scheduleHover = (target: Element | null): void => {\n hoverTarget = target\n if (hoverFrame !== 0) return\n hoverFrame = requestAnimationFrame(applyHover)\n }\n\n const onMouseOver = (event: Event): void => {\n const target = event.target\n const outside = target instanceof Element && target.id === OVERLAY_HOST_ID\n\n scheduleHover(target instanceof Element && !outside ? target : null)\n }\n\n const onMouseOut = (event: Event): void => {\n if (event instanceof MouseEvent && event.relatedTarget === null) scheduleHover(null)\n }\n\n window.addEventListener('scroll', onScroll, { passive: true })\n window.addEventListener('resize', onResize)\n document.addEventListener('mouseover', onMouseOver, { passive: true })\n document.addEventListener('mouseout', onMouseOut, { passive: true })\n\n draw()\n\n return {\n host,\n update(next: Graph): void {\n current = next\n byId = indexNodes(next)\n draw()\n },\n setLayers(names: LayerName[]): void {\n visible = new Set(names)\n draw()\n },\n destroy(): void {\n if (frame !== 0) cancelAnimationFrame(frame)\n if (hoverFrame !== 0) cancelAnimationFrame(hoverFrame)\n window.removeEventListener('scroll', onScroll)\n window.removeEventListener('resize', onResize)\n document.removeEventListener('mouseover', onMouseOver)\n document.removeEventListener('mouseout', onMouseOut)\n host.remove()\n },\n }\n}\n\nfunction indexNodes(graph: Graph): Map<string, GraphNode> {\n return new Map(graph.nodes.map((node) => [node.id, node]))\n}\n", "export { EDGES, findGuides } from './align.js'\nexport * from './color.js'\nexport { GRID_STEP, MAX_MARKERS, MAX_NODES, OVERLAY_HOST_ID, SPACING_SCALE } from './constants.js'\nexport { findGaps, findSiblingGaps, findVisualGaps } from './gaps.js'\nexport * from './geometry.js'\nexport { buildGraph, resolveNode } from './graph.js'\nexport { LAYERS, type LayerName } from './render/layers.js'\nexport { type OverlayHandle, type OverlayOptions, render } from './render/overlay.js'\nexport { defaultRules, findIssues, RULE_IDS, type Rule } from './rules/index.js'\nexport * from './types.js'\nexport { pathOf } from './walk.js'\n\nexport const VERSION = '0.1.0'\n", "import type { Graph, Issue } from '@litedesign/core/types'\nimport { type Bridge, type HubPage, sameUrl } from '../hub.js'\nimport { AwaitingUserError, MismatchError, ToolError } from '../mcp/errors.js'\nimport type {\n AnnotateOptions,\n Driver,\n MeasureResult,\n OverlayOptions,\n OverlayResult,\n ShotOptions,\n WaitResult,\n} from './types.js'\n\ntype ShotPayload = { data: string }\n\n/**\n * Drives the page the user already has open. The extension owns the tab, so\n * this driver never opens, navigates, or closes anything.\n *\n * `open` does not need a click: it asks the connected worker to attach to the\n * tab the human is looking at, then checks that the URL is the expected one.\n */\nexport class ExtensionDriver implements Driver {\n readonly #hub: Bridge\n #target: string | undefined\n\n constructor(hub: Bridge) {\n this.#hub = hub\n }\n\n async open(url: string): Promise<void> {\n this.#target = url\n\n if (this.#hub.find(url) !== undefined) return\n\n if (!this.#hub.hasClient()) throw new AwaitingUserError(url)\n\n const page = await this.#hub.requestAny<HubPage>('attach')\n\n if (!sameUrl(page.url, url)) throw new MismatchError(url, page.url)\n\n this.#target = page.url\n }\n\n async waitForPage(url: string, timeoutMs: number): Promise<WaitResult> {\n const outcome = await this.#hub.waitForPage(url, timeoutMs)\n\n if (outcome.status === 'timeout') return { status: 'timeout' }\n if (outcome.status === 'mismatch') return { status: 'mismatch', url: outcome.page.url }\n\n this.#target = outcome.page.url\n return { status: 'ready', url: outcome.page.url }\n }\n\n async graph(): Promise<Graph> {\n return this.#request<Graph>('graph')\n }\n\n async issues(rules?: string[]): Promise<Issue[]> {\n const graph = await this.graph()\n if (rules === undefined || rules.length === 0) return graph.issues\n\n const wanted = new Set(rules)\n return graph.issues.filter((issue) => wanted.has(issue.rule))\n }\n\n async measure(selector: string): Promise<MeasureResult> {\n return this.#request<MeasureResult>('measure', { selector })\n }\n\n async screenshot(options: ShotOptions = {}): Promise<Buffer> {\n return decode(await this.#request<ShotPayload>('screenshot', options))\n }\n\n async annotate(options: AnnotateOptions = {}): Promise<Buffer> {\n return decode(await this.#request<ShotPayload>('annotate', options))\n }\n\n async overlay(options: OverlayOptions): Promise<OverlayResult> {\n const result = await this.#request<OverlayResult | undefined>('overlay', options)\n\n // An extension built before the overlay tool reported its result answers\n // `{ ok: true }` with no result. Say what to do instead of crashing on\n // `result.enabled`.\n if (result === undefined) {\n throw new ToolError(\n 'the extension did not report the overlay state. Reload the litedesign extension at chrome://extensions, then try again.',\n )\n }\n\n return result\n }\n\n async close(): Promise<void> {\n // The page belongs to the user. Closing it would be hostile.\n }\n\n #request<T>(action: string, payload?: unknown): Promise<T> {\n const page = this.#require()\n return this.#hub.request<T>(page.tabId, action, payload)\n }\n\n #require(): HubPage {\n if (this.#target === undefined) {\n throw new ToolError('no page is open. Call inspect with a url first')\n }\n\n const page = this.#hub.find(this.#target)\n if (page === undefined) {\n throw new ToolError('the page is no longer connected. Open it and call inspect again.')\n }\n\n return page\n }\n}\n\nfunction decode(payload: ShotPayload): Buffer {\n if (typeof payload?.data !== 'string' || payload.data === '') {\n throw new ToolError('the extension returned an empty screenshot')\n }\n\n return Buffer.from(payload.data, 'base64')\n}\n", "import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { LAYERS } from '@litedesign/core'\nimport type { Graph, GraphNode, Issue } from '@litedesign/core/types'\nimport type { Browser, BrowserContext, LaunchOptions, Page } from 'playwright-core'\nimport { ToolError } from '../mcp/errors.js'\nimport type {\n AnnotateOptions,\n Driver,\n MeasureResult,\n OverlayOptions,\n OverlayResult,\n ShotOptions,\n Viewport,\n} from './types.js'\n\ntype Playwright = typeof import('playwright-core')\n\nconst DEFAULT_VIEWPORT = { width: 1280, height: 800 }\n\nexport type PlaywrightDriverOptions = {\n /** Override the injected measurement core. Used by tests and the CLI bundle. */\n corePath?: string\n}\n\nexport class PlaywrightDriver implements Driver {\n readonly #playwright: Playwright\n readonly #corePath: string\n #browser: Browser | undefined\n #context: BrowserContext | undefined\n #page: Page | undefined\n\n constructor(playwright: Playwright, options: PlaywrightDriverOptions = {}) {\n this.#playwright = playwright\n this.#corePath = resolveCorePath(options.corePath)\n }\n\n async open(url: string, viewport?: Viewport): Promise<void> {\n const page = await this.#ensurePage()\n\n await page.setViewportSize(\n viewport === undefined ? DEFAULT_VIEWPORT : { width: viewport.w, height: viewport.h },\n )\n await page.goto(url, { waitUntil: 'load' })\n await this.#inject(page)\n }\n\n async graph(): Promise<Graph> {\n const page = await this.#requirePage()\n await this.#inject(page)\n\n return page.evaluate(() => {\n const core = (\n window as unknown as {\n __litedesign: { buildGraph: (root: Element) => Graph }\n }\n ).__litedesign\n\n return core.buildGraph(document.body)\n })\n }\n\n async issues(rules?: string[]): Promise<Issue[]> {\n const graph = await this.graph()\n if (rules === undefined || rules.length === 0) return graph.issues\n\n const wanted = new Set(rules)\n return graph.issues.filter((issue) => wanted.has(issue.rule))\n }\n\n async measure(selector: string): Promise<MeasureResult> {\n const page = await this.#requirePage()\n await this.#inject(page)\n\n const found = await page.evaluate((target) => {\n const core = (\n window as unknown as {\n __litedesign: {\n buildGraph: (root: Element) => Graph\n resolveNode: (graph: Graph, selector: string) => GraphNode | null\n }\n }\n ).__litedesign\n\n const graph = core.buildGraph(document.body)\n const node = core.resolveNode(graph, target)\n\n if (node === null) return null\n\n const id = node.id\n const gaps = graph.gaps\n .filter((gap) => gap.a === id || gap.b === id)\n .map((gap) => ({\n to: gap.a === id ? gap.b : gap.a,\n axis: gap.axis,\n distance: gap.distance,\n kind: gap.kind,\n }))\n\n return { node, gaps }\n }, selector)\n\n if (found === null) {\n throw new ToolError(`selector \"${selector}\" did not match any element on the page`)\n }\n\n return {\n id: found.node.id,\n selector: found.node.selector,\n tag: found.node.tag,\n rect: found.node.rect,\n styles: found.node.styles,\n gaps: found.gaps,\n }\n }\n\n async screenshot(options: ShotOptions = {}): Promise<Buffer> {\n const page = await this.#requirePage()\n\n if (options.selector !== undefined) {\n const locator = page.locator(options.selector).first()\n if ((await locator.count()) === 0) {\n throw new ToolError(`selector \"${options.selector}\" did not match any element on the page`)\n }\n\n return locator.screenshot({ type: 'png' })\n }\n\n return page.screenshot({ type: 'png', fullPage: options.fullPage ?? false })\n }\n\n async annotate(options: AnnotateOptions = {}): Promise<Buffer> {\n const page = await this.#requirePage()\n await this.#inject(page)\n\n if (options.selector !== undefined) {\n const locator = page.locator(options.selector).first()\n if ((await locator.count()) === 0) {\n throw new ToolError(`selector \"${options.selector}\" did not match any element on the page`)\n }\n\n await locator.scrollIntoViewIfNeeded()\n }\n\n await page.evaluate(\n (input) => {\n const target = window as unknown as {\n __litedesign: {\n buildGraph: (root: Element) => Graph\n render: (graph: Graph, options: { layers: string[] }) => { destroy(): void }\n }\n __litedesign_handle__?: { destroy(): void }\n }\n\n target.__litedesign_handle__?.destroy()\n\n let graph = target.__litedesign.buildGraph(document.body)\n\n if (input.rules !== undefined && input.rules.length > 0) {\n const wanted = new Set(input.rules)\n graph = {\n ...graph,\n issues: graph.issues.filter((issue) => wanted.has(issue.rule)),\n }\n }\n\n target.__litedesign_handle__ = target.__litedesign.render(graph, { layers: input.layers })\n },\n { layers: ['grid', 'guide', 'gap', 'issue'], rules: options.rules },\n )\n\n // The overlay draws synchronously; two frames guarantee it is painted\n // before the screenshot is taken.\n await page.evaluate(\n () =>\n new Promise<void>((resolve) => {\n requestAnimationFrame(() => requestAnimationFrame(() => resolve()))\n }),\n )\n\n // The overlay is fixed to the viewport, so a full-page capture would only\n // annotate the first screen. Keep annotated captures viewport-only.\n return page.screenshot({ type: 'png' })\n }\n\n async overlay(options: OverlayOptions): Promise<OverlayResult> {\n const page = await this.#requirePage()\n await this.#inject(page)\n\n const layers = options.enabled ? (options.layers ?? [...LAYERS]) : []\n\n await page.evaluate(\n (input) => {\n const target = window as unknown as {\n __litedesign: {\n buildGraph: (root: Element) => Graph\n render: (graph: Graph, options: { layers: string[] }) => { destroy(): void }\n }\n __litedesign_handle__?: { destroy(): void }\n }\n\n target.__litedesign_handle__?.destroy()\n target.__litedesign_handle__ = undefined\n\n if (!input.enabled) return\n\n const graph = target.__litedesign.buildGraph(document.body)\n target.__litedesign_handle__ = target.__litedesign.render(graph, { layers: input.layers })\n },\n { enabled: options.enabled, layers },\n )\n\n return { enabled: options.enabled, layers }\n }\n\n async close(): Promise<void> {\n await this.#context?.close().catch(() => undefined)\n await this.#browser?.close().catch(() => undefined)\n\n this.#context = undefined\n this.#browser = undefined\n this.#page = undefined\n }\n\n async #ensurePage(): Promise<Page> {\n if (this.#page !== undefined && !this.#page.isClosed()) return this.#page\n\n const browser = await this.#ensureBrowser()\n const context = await browser.newContext({\n viewport: DEFAULT_VIEWPORT,\n // Injected measurement code must run even on pages with a strict CSP.\n bypassCSP: true,\n })\n const page = await context.newPage()\n\n this.#context = context\n this.#page = page\n return page\n }\n\n async #ensureBrowser(): Promise<Browser> {\n if (this.#browser?.isConnected() === true) return this.#browser\n\n let last: unknown\n\n for (const options of launchCandidates(this.#playwright)) {\n try {\n this.#browser = await this.#playwright.chromium.launch({\n ...options,\n args: ['--no-sandbox'],\n })\n return this.#browser\n } catch (error) {\n last = error\n }\n }\n\n const detail = last instanceof Error ? `: ${last.message}` : ''\n throw new ToolError(`could not launch Chrome for Playwright${detail}`)\n }\n\n async #requirePage(): Promise<Page> {\n if (this.#page === undefined || this.#page.isClosed()) {\n throw new ToolError('no page is open. Call inspect with a url first')\n }\n\n return this.#page\n }\n\n async #inject(page: Page): Promise<void> {\n const ready = await page.evaluate(\n () => typeof (window as unknown as { __litedesign?: unknown }).__litedesign !== 'undefined',\n )\n\n if (ready) return\n\n try {\n await page.addScriptTag({ path: this.#corePath })\n } catch (error) {\n const detail = error instanceof Error ? `: ${error.message}` : ''\n throw new ToolError(`could not inject the measurement core${detail}`)\n }\n }\n}\n\nfunction launchCandidates(playwright: Playwright): LaunchOptions[] {\n const candidates: LaunchOptions[] = []\n\n if (process.env.CHROME_PATH !== undefined) {\n candidates.push({ executablePath: process.env.CHROME_PATH })\n }\n\n // Installed Chrome first: it is the browser the user actually designs in.\n candidates.push({ channel: 'chrome' })\n\n const bundled = playwright.chromium.executablePath()\n if (existsSync(bundled)) candidates.push({ executablePath: bundled })\n\n for (const candidate of [\n '/usr/bin/google-chrome',\n '/usr/bin/chromium',\n '/usr/bin/chromium-browser',\n ]) {\n if (existsSync(candidate)) candidates.push({ executablePath: candidate })\n }\n\n return candidates\n}\n\n/**\n * Resolves the IIFE bundle injected into the page. The first candidate is the\n * built CLI layout, the second is the source layout used by tests.\n */\nexport function resolveCorePath(explicit?: string): string {\n const candidates = [\n explicit,\n process.env.LITEDESIGN_CORE,\n fileURLToPath(new URL('./extension/core.iife.js', import.meta.url)),\n path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n '../../../../core/dist/core.iife.js',\n ),\n ].filter((value): value is string => value !== undefined)\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate\n }\n\n throw new ToolError(\n 'measurement core not found. Run `litedesign setup` or set LITEDESIGN_CORE to core.iife.js',\n )\n}\n", "import type { Mode } from '../config.js'\nimport { getHub, getHubError } from '../hub.js'\nimport { ToolError } from '../mcp/errors.js'\nimport { ExtensionDriver } from './extension.js'\nimport { PlaywrightDriver } from './playwright.js'\nimport type { Driver } from './types.js'\n\ntype Playwright = typeof import('playwright-core')\n\n/** Optional by design: the published package never installs a browser. */\nexport async function loadPlaywright(): Promise<Playwright | null> {\n try {\n return await import('playwright-core')\n } catch {\n return null\n }\n}\n\nexport async function detectPlaywright(): Promise<boolean> {\n return (await loadPlaywright()) !== null\n}\n\n/**\n * Picks the driver once per session. Playwright wins in `auto` because it can\n * open a page without asking the human; the extension is the fallback when no\n * browser automation library is installed.\n */\nexport async function selectDriver(mode: Mode): Promise<Driver> {\n if (mode === 'extension') return extensionDriver()\n\n const playwright = await loadPlaywright()\n if (playwright !== null) return new PlaywrightDriver(playwright)\n\n if (mode === 'playwright') {\n throw new ToolError(\n 'Playwright is not installed. Install it with `npm i -D playwright` (or `pnpm add -D playwright`) and restart the MCP server.',\n )\n }\n\n return extensionDriver()\n}\n\nfunction extensionDriver(): Driver {\n const hub = getHub()\n\n if (hub === null) {\n const reason = getHubError() ?? 'the WebSocket hub is not running'\n throw new ToolError(\n `the extension bridge is unavailable: ${reason}. Free the port, or install Playwright.`,\n )\n }\n\n return new ExtensionDriver(hub)\n}\n", "export type TextContent = { type: 'text'; text: string }\n\nexport type ImageContent = { type: 'image'; data: string; mimeType: string }\n\nexport type ToolResult = {\n content: Array<TextContent | ImageContent>\n isError?: boolean\n}\n\nexport function textResult(value: unknown): ToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] }\n}\n\nexport function imageResult(value: unknown, image: Buffer): ToolResult {\n return {\n content: [\n { type: 'text', text: JSON.stringify(value, null, 2) },\n { type: 'image', data: image.toString('base64'), mimeType: 'image/png' },\n ],\n }\n}\n\n/**\n * Never forwards a stack trace. Unexpected errors are logged to stderr by the\n * caller, so the agent only sees the message it can act on.\n */\nexport function errorResult(error: unknown): ToolResult {\n const message =\n error instanceof Error && error.message !== ''\n ? error.message\n : typeof error === 'string' && error !== ''\n ? error\n : 'unexpected error'\n\n return { isError: true, content: [{ type: 'text', text: message }] }\n}\n", "import type { Mode } from '../config.js'\nimport { selectDriver } from '../drivers/index.js'\nimport type { Driver, Viewport, WaitResult } from '../drivers/types.js'\nimport { ToolError } from './errors.js'\n\ntype Session = {\n driver: Driver\n url: string\n ready: boolean\n}\n\nexport type SessionWait =\n | { status: 'ready'; url: string; expected: string }\n | { status: 'timeout'; expected: string }\n | { status: 'mismatch'; url: string; expected: string }\n\n/**\n * One process serves one agent session, so one open page is enough. Keeping it\n * alive is what lets `measure` run after `inspect` without reopening the URL.\n */\nlet session: Session | null = null\n\nexport async function openPage(mode: Mode, url: string, viewport?: Viewport): Promise<Driver> {\n if (session === null) {\n session = { driver: await selectDriver(mode), url, ready: false }\n }\n\n session.url = url\n await session.driver.open(url, viewport)\n session.ready = true\n\n return session.driver\n}\n\nexport function requirePage(): Driver {\n if (session === null || !session.ready) {\n throw new ToolError('no page is open. Call inspect with a url first')\n }\n\n return session.driver\n}\n\nexport async function waitForPage(timeoutMs: number): Promise<SessionWait> {\n if (session === null || session.url === '') {\n throw new ToolError('no page is requested. Call inspect with a url first')\n }\n\n const expected = session.url\n const driver = session.driver\n\n if (driver.waitForPage === undefined) {\n return { status: 'ready', url: expected, expected }\n }\n\n const result: WaitResult = await driver.waitForPage(expected, timeoutMs)\n\n if (result.status === 'ready') {\n session.ready = true\n return { status: 'ready', url: result.url, expected }\n }\n\n if (result.status === 'timeout') return { status: 'timeout', expected }\n\n return { status: 'mismatch', url: result.url, expected }\n}\n\nexport async function closeSession(): Promise<void> {\n if (session === null) return\n\n const current = session\n session = null\n await current.driver.close()\n}\n", "import { handoffMessage, mismatchMessage } from '../handoff.js'\nimport { type ToolResult, textResult } from '../result.js'\nimport { waitForPage } from '../session.js'\n\nexport type AwaitPageInput = {\n timeoutMs?: number\n}\n\nconst DEFAULT_TIMEOUT = 120000\nconst MAX_TIMEOUT = 600000\n\nexport async function awaitPageTool(input: AwaitPageInput): Promise<ToolResult> {\n const timeoutMs = Math.min(\n Math.max(Math.round(input.timeoutMs ?? DEFAULT_TIMEOUT), 1000),\n MAX_TIMEOUT,\n )\n const result = await waitForPage(timeoutMs)\n\n if (result.status === 'ready') {\n return textResult({\n status: 'ready',\n url: result.url,\n message: 'The page is connected. Call inspect to read it.',\n })\n }\n\n if (result.status === 'timeout') {\n return textResult({\n status: 'timeout',\n url: result.expected,\n message: handoffMessage(result.expected),\n })\n }\n\n return textResult({\n status: 'mismatch',\n expected: result.expected,\n actual: result.url,\n message: mismatchMessage(result.expected, result.url),\n })\n}\n", "import type { Graph, Issue } from '@litedesign/core/types'\n\nconst MAX_TREE_LINES = 200\nconst MAX_DEPTH_INDENT = 12\nconst MAX_TEXT = 48\n\nexport type IssuePayload = {\n issues: Array<Pick<Issue, 'selector' | 'rule' | 'severity' | 'actual' | 'expected' | 'autoFix'>>\n total: number\n truncated: boolean\n}\n\n/**\n * Indented, human-readable tree. Not JSON: the agent reads this to decide what\n * to measure next, and a full graph would blow the token budget.\n */\nexport function formatTree(graph: Graph, maxLines = MAX_TREE_LINES): string {\n const lines: string[] = []\n\n for (const node of graph.nodes) {\n if (lines.length >= maxLines) break\n\n const indent = ' '.repeat(Math.min(node.depth, MAX_DEPTH_INDENT))\n const size = `${Math.round(node.rect.w)}\u00D7${Math.round(node.rect.h)}`\n const text = node.text === '' ? '' : ` ${clip(node.text)}`\n\n lines.push(`${indent}${node.tag} ${size}${text}`)\n }\n\n if (graph.nodes.length > maxLines) {\n lines.push(`\u2026 ${graph.nodes.length - maxLines} more nodes`)\n }\n\n return lines.join('\\n')\n}\n\nexport function issuePayload(issues: Issue[], limit: number): IssuePayload {\n return {\n issues: issues.slice(0, limit).map((issue) => ({\n selector: issue.selector,\n rule: issue.rule,\n severity: issue.severity,\n actual: issue.actual,\n expected: issue.expected,\n autoFix: issue.autoFix,\n })),\n total: issues.length,\n truncated: issues.length > limit,\n }\n}\n\n/** PNG dimensions live in the IHDR chunk, so no image library is needed. */\nexport function pngSize(buffer: Buffer): { width: number; height: number } {\n if (buffer.length < 24 || buffer.toString('ascii', 1, 4) !== 'PNG') {\n return { width: 0, height: 0 }\n }\n\n return { width: buffer.readUInt32BE(16), height: buffer.readUInt32BE(20) }\n}\n\nfunction clip(text: string): string {\n return text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT - 1)}\u2026` : text\n}\n", "import { RULE_IDS } from '@litedesign/core'\nimport { ToolError } from './errors.js'\n\n/**\n * Validates rule names once, for both `find_issues` and\n * `screenshot_annotated`. An empty list means \"all rules\".\n */\nexport function validateRules(rules: string[]): string[] | undefined {\n const unknown = rules.filter((rule) => !RULE_IDS.includes(rule))\n\n if (unknown.length > 0) {\n const label = unknown.length === 1 ? 'rule' : 'rules'\n throw new ToolError(\n `unknown ${label}: ${unknown.join(', ')}. Valid rules: ${RULE_IDS.join(', ')}`,\n )\n }\n\n return rules.length === 0 ? undefined : rules\n}\n", "import { issuePayload } from '../format.js'\nimport { type ToolResult, textResult } from '../result.js'\nimport { validateRules } from '../rules.js'\nimport { requirePage } from '../session.js'\n\nexport type FindIssuesInput = {\n rules?: string[]\n limit?: number\n}\n\nconst DEFAULT_LIMIT = 50\nconst MAX_LIMIT = 200\n\nexport async function findIssuesTool(input: FindIssuesInput): Promise<ToolResult> {\n const rules = validateRules(input.rules ?? [])\n const limit = clamp(input.limit ?? DEFAULT_LIMIT, 1, MAX_LIMIT)\n const issues = await requirePage().issues(rules)\n\n return textResult(issuePayload(issues, limit))\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(Math.round(value), min), max)\n}\n", "import { readConfig } from '../../config.js'\nimport type { Viewport } from '../../drivers/types.js'\nimport { AwaitingUserError, MismatchError } from '../errors.js'\nimport { formatTree } from '../format.js'\nimport { handoffMessage } from '../handoff.js'\nimport { imageResult, type ToolResult, textResult } from '../result.js'\nimport { openPage } from '../session.js'\n\nexport type InspectInput = {\n url: string\n viewport?: Viewport\n screenshot?: boolean\n}\n\nexport async function inspectTool(input: InspectInput): Promise<ToolResult> {\n const config = await readConfig()\n\n let driver: Awaited<ReturnType<typeof openPage>>\n\n try {\n driver = await openPage(config.mode, input.url, input.viewport)\n } catch (error) {\n if (error instanceof AwaitingUserError) {\n return textResult({\n status: 'awaiting_user',\n url: input.url,\n next: 'await_page',\n message: handoffMessage(input.url),\n })\n }\n\n if (error instanceof MismatchError) {\n return textResult({\n status: 'mismatch',\n expected: error.expected,\n actual: error.actual,\n next: 'await_page',\n message: error.message,\n })\n }\n\n throw error\n }\n\n const graph = await driver.graph()\n const payload = {\n status: 'ready',\n url: graph.url,\n viewport: graph.viewport,\n summary: {\n nodes: graph.nodes.length,\n issues: graph.issues.length,\n truncated: graph.truncated,\n },\n tree: formatTree(graph),\n }\n\n // The image costs the agent a lot of context, so it is off unless asked for.\n // Everything the agent needs to judge spacing and alignment is already in\n // `payload`, measured from the DOM.\n if (input.screenshot !== true) return textResult(payload)\n\n const image = await driver.screenshot()\n return imageResult(payload, image)\n}\n", "import { type ToolResult, textResult } from '../result.js'\nimport { requirePage } from '../session.js'\n\nexport type MeasureInput = {\n selector: string\n}\n\nexport async function measureTool(input: MeasureInput): Promise<ToolResult> {\n const measured = await requirePage().measure(input.selector)\n return textResult(measured)\n}\n", "import { LAYERS, type LayerName } from '@litedesign/core'\nimport { ToolError } from '../errors.js'\nimport { type ToolResult, textResult } from '../result.js'\nimport { requirePage } from '../session.js'\n\nexport type OverlayInput = {\n enabled?: boolean\n layers?: string[]\n}\n\n/**\n * Shows or hides the measurement overlay in the page the human is looking at.\n * This is how the agent puts the grid on screen without asking for a click.\n *\n * The answer comes from the page, not from the request: the tool reports the\n * state the page says it is in, so `shown` cannot be true while the grid is\n * not on screen.\n */\nexport async function overlayTool(input: OverlayInput): Promise<ToolResult> {\n const driver = requirePage()\n const enabled = input.enabled !== false\n const layers = parseLayers(input.layers)\n\n const result = await driver.overlay({ enabled, layers })\n\n return textResult({\n status: result.enabled ? 'shown' : 'hidden',\n layers: result.layers,\n })\n}\n\nfunction parseLayers(requested: string[] | undefined): LayerName[] | undefined {\n if (requested === undefined || requested.length === 0) return undefined\n\n const valid = new Set<string>(LAYERS)\n const unknown = requested.filter((name) => !valid.has(name))\n\n if (unknown.length > 0) {\n throw new ToolError(`unknown layer: ${unknown.join(', ')}. Valid layers: ${LAYERS.join(', ')}`)\n }\n\n return requested as LayerName[]\n}\n", "import { pngSize } from '../format.js'\nimport { imageResult, type ToolResult } from '../result.js'\nimport { requirePage } from '../session.js'\n\nexport type ScreenshotInput = {\n selector?: string\n fullPage?: boolean\n}\n\nexport async function screenshotTool(input: ScreenshotInput): Promise<ToolResult> {\n const image = await requirePage().screenshot(input)\n return imageResult({ ...pngSize(image), bytes: image.length }, image)\n}\n", "import { pngSize } from '../format.js'\nimport { imageResult, type ToolResult } from '../result.js'\nimport { validateRules } from '../rules.js'\nimport { requirePage } from '../session.js'\n\nexport type ScreenshotAnnotatedInput = {\n selector?: string\n rules?: string[]\n}\n\nexport async function screenshotAnnotatedTool(\n input: ScreenshotAnnotatedInput,\n): Promise<ToolResult> {\n const rules = validateRules(input.rules ?? [])\n const image = await requirePage().annotate({\n selector: input.selector,\n rules,\n })\n\n return imageResult({ ...pngSize(image), bytes: image.length }, image)\n}\n", "import { LAYERS, RULE_IDS } from '@litedesign/core'\nimport { readConfig } from '../config.js'\nimport { detectPlaywright } from '../drivers/index.js'\nimport { getHub, getHubError, setHub, setHubError } from '../hub.js'\nimport { VERSION } from '../version.js'\nimport { ensureBridge } from '../ws.js'\nimport { ToolError } from './errors.js'\nimport { errorResult, type ToolResult, textResult } from './result.js'\nimport { closeSession } from './session.js'\nimport { awaitPageTool } from './tools/await-page.js'\nimport { findIssuesTool } from './tools/find-issues.js'\nimport { inspectTool } from './tools/inspect.js'\nimport { measureTool } from './tools/measure.js'\nimport { overlayTool } from './tools/overlay.js'\nimport { screenshotTool } from './tools/screenshot.js'\nimport { screenshotAnnotatedTool } from './tools/screenshot-annotated.js'\n\nasync function guard(run: () => Promise<ToolResult>): Promise<ToolResult> {\n try {\n return await run()\n } catch (error) {\n if (error instanceof ToolError) return errorResult(error)\n\n // Keep the stack on stderr; the agent only gets the actionable message.\n console.error('[litedesign] unexpected tool error:', error)\n return errorResult(error)\n }\n}\n\nexport async function runMcpServer(): Promise<void> {\n const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js')\n const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js')\n const { z } = await import('zod')\n\n const config = await readConfig()\n\n // The bridge is its own process so it survives an MCP restart and the human\n // can start or stop it with `litedesign ws`. Start it when it is missing.\n try {\n setHub(await ensureBridge(config.port))\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n setHubError(reason)\n console.error(`[litedesign] extension bridge disabled: ${reason}`)\n }\n\n const server = new McpServer({ name: 'litedesign', version: VERSION })\n\n const viewport = z\n .object({\n w: z.number().int().positive().describe('Viewport width in CSS pixels'),\n h: z.number().int().positive().describe('Viewport height in CSS pixels'),\n })\n .optional()\n\n server.registerTool(\n 'capabilities',\n {\n title: 'Capabilities',\n description:\n 'Server version, available drivers, active mode, connected extension pages, and valid rule names.',\n inputSchema: {},\n },\n async () => {\n const playwright = await detectPlaywright()\n const hub = getHub()\n\n return textResult({\n version: VERSION,\n drivers: { playwright, extension: hub !== null },\n mode: config.mode,\n port: config.port,\n rules: RULE_IDS,\n extension: {\n connected: hub?.clientCount() ?? 0,\n pages: hub?.pages() ?? [],\n error: getHubError(),\n },\n })\n },\n )\n\n server.registerTool(\n 'inspect',\n {\n title: 'Inspect page',\n description:\n 'Open a page and return a tree summary. Call this before measure, find_issues, overlay, screenshot, or screenshot_annotated. No image by default: the numbers the agent needs come from the DOM, so set screenshot to true only when you really need to see the page. With the extension driver this attaches to the active tab by itself; returns \"awaiting_user\" when no extension is connected and \"mismatch\" when the active tab is a different page.',\n inputSchema: {\n url: z.string().url(),\n viewport,\n screenshot: z\n .boolean()\n .optional()\n .describe(\n 'Set true to also return a viewport PNG. Off by default: ask for it only when visual context is essential.',\n ),\n },\n },\n async (input) => guard(() => inspectTool(input)),\n )\n\n server.registerTool(\n 'await_page',\n {\n title: 'Await page',\n description:\n 'Block until the page from the last inspect call connects through the extension. Use this after inspect returns awaiting_user. Returns ready, timeout, or mismatch; timeout is not an error.',\n inputSchema: {\n timeoutMs: z\n .number()\n .int()\n .min(1000)\n .max(600000)\n .optional()\n .describe('How long to wait in milliseconds (default 120000)'),\n },\n },\n async (input) => guard(() => awaitPageTool(input)),\n )\n\n server.registerTool(\n 'measure',\n {\n title: 'Measure element',\n description:\n 'Return the box model, computed styles, and gaps to neighbours for one element. Accepts a CSS selector or a structural selector returned by find_issues. Call inspect first.',\n inputSchema: {\n selector: z\n .string()\n .min(1)\n .describe('CSS selector or a structural selector returned by find_issues'),\n },\n },\n async (input) => guard(() => measureTool(input)),\n )\n\n server.registerTool(\n 'find_issues',\n {\n title: 'Find issues',\n description:\n 'Run the rule engine on the open page and return violations with selector, actual, expected, severity, and autoFix. Call inspect first.',\n inputSchema: {\n rules: z\n .array(z.string())\n .optional()\n .describe(`Rules to run. Default: all. Valid: ${RULE_IDS.join(', ')}`),\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe('Maximum issues to return (default 50)'),\n },\n },\n async (input) => guard(() => findIssuesTool(input)),\n )\n\n server.registerTool(\n 'overlay',\n {\n title: 'Overlay',\n description:\n 'Show or hide the measurement overlay in the page the human is looking at: grid, guides, gap labels, and issue boxes. Use it to let the human see spacing without clicking anything. Call inspect first.',\n inputSchema: {\n enabled: z.boolean().optional().describe('false hides the overlay (default true)'),\n layers: z\n .array(z.string())\n .optional()\n .describe(`Layers to draw. Default: all. Valid: ${LAYERS.join(', ')}`),\n },\n },\n async (input) => guard(() => overlayTool(input)),\n )\n\n server.registerTool(\n 'screenshot',\n {\n title: 'Screenshot',\n description: 'Capture a PNG of the viewport or of one element. Call inspect first.',\n inputSchema: {\n selector: z.string().min(1).optional().describe('Capture only this element'),\n fullPage: z\n .boolean()\n .optional()\n .describe('Capture the full scrollable page (ignored when selector is set)'),\n },\n },\n async (input) => guard(() => screenshotTool(input)),\n )\n\n server.registerTool(\n 'screenshot_annotated',\n {\n title: 'Annotated screenshot',\n description:\n 'Render the measurement overlay (grid, guides, gaps, issue boxes with severity and actual \u2192 expected labels) and capture a viewport PNG. Call inspect first.',\n inputSchema: {\n selector: z\n .string()\n .min(1)\n .optional()\n .describe('Scroll this element into view before capturing'),\n rules: z.array(z.string()).optional().describe('Annotate only these rules. Default: all'),\n },\n },\n async (input) => guard(() => screenshotAnnotatedTool(input)),\n )\n\n let closing = false\n\n const shutdown = (): void => {\n if (closing) return\n closing = true\n\n void closeSession()\n .catch(() => undefined)\n .finally(() => getHub()?.close())\n .finally(() => process.exit(0))\n }\n\n process.once('SIGINT', shutdown)\n process.once('SIGTERM', shutdown)\n // The client closes stdin when the session ends; do not leave Chrome behind.\n process.stdin.once('end', shutdown)\n process.stdin.once('close', shutdown)\n\n // stdout carries the protocol. Every log must go to stderr.\n await server.connect(new StdioServerTransport())\n console.error(`[litedesign] MCP server v${VERSION} ready (stdio)`)\n}\n", "import { doctor } from './commands/doctor.js'\nimport { extensionCommand } from './commands/extension.js'\nimport { setup } from './commands/setup.js'\nimport { wsCommand } from './commands/ws.js'\nimport { runMcpServer } from './mcp/server.js'\nimport { VERSION } from './version.js'\n\nconst HELP = `\n litedesign v${VERSION}\n\n Usage:\n litedesign setup scaffold extension + config\n litedesign extension path print the folder to load unpacked\n litedesign extension update re-copy after an upgrade\n litedesign doctor check node, extension, and port\n litedesign ws start start the bridge in the background\n litedesign ws stop stop the bridge\n litedesign ws status show the bridge and connected pages\n litedesign mcp start the MCP server (stdio)\n\n Options:\n -h, --help show this help\n -v, --version show the version\n`\n\nexport async function run(argv: string[]): Promise<void> {\n const [command, ...rest] = argv\n\n switch (command) {\n case undefined:\n case 'help':\n case '-h':\n case '--help':\n console.log(HELP)\n return\n case '-v':\n case '--version':\n console.log(VERSION)\n return\n case 'setup':\n await setup()\n return\n case 'extension':\n await extensionCommand(rest)\n return\n case 'doctor':\n await doctor()\n return\n case 'ws':\n await wsCommand(rest)\n return\n case 'mcp':\n await runMcpServer()\n return\n default:\n throw new Error(`unknown command: ${command}. Try: litedesign --help`)\n }\n}\n", "#!/usr/bin/env node\nimport { run } from './cli.js'\n\nrun(process.argv.slice(2)).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n console.error(`\\n error: ${message}\\n`)\n process.exit(1)\n})\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["existsSync", "readFile", "path", "existsSync", "readFile", "randomUUID", "WebSocket", "WebSocket", "randomUUID", "existsSync", "readFile", "state", "path", "existsSync", "readFile", "existsSync", "writeFile", "path", "existsSync", "writeFile", "path", "run", "TOLERANCE", "current", "issue", "existsSync", "path", "fileURLToPath", "issue", "existsSync", "fileURLToPath", "path", "current", "DEFAULT_TIMEOUT", "issue", "run", "HELP"]
|
|
7
|
-
}
|