bb-browser 0.11.1 → 0.11.2

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/dist/cli.js CHANGED
@@ -2655,7 +2655,7 @@ function formatUptime(ms) {
2655
2655
  }
2656
2656
 
2657
2657
  // packages/cli/src/index.ts
2658
- var VERSION = "0.11.1";
2658
+ var VERSION = "0.11.2";
2659
2659
  var HELP_TEXT = `
2660
2660
  bb-browser - AI Agent \u6D4F\u89C8\u5668\u81EA\u52A8\u5316\u5DE5\u5177
2661
2661
 
package/dist/daemon.js CHANGED
@@ -1018,11 +1018,15 @@ var HttpServer = class {
1018
1018
  (_, reject) => setTimeout(() => reject(new Error("CDP connection timeout")), COMMAND_TIMEOUT)
1019
1019
  )
1020
1020
  ]);
1021
- } catch (error) {
1021
+ } catch {
1022
+ const cdpTarget = `${this.cdp.host}:${this.cdp.port}`;
1023
+ const reason = this.cdp.lastError || "unknown";
1022
1024
  this.sendJson(res, 503, {
1023
1025
  id: request.id,
1024
1026
  success: false,
1025
- error: error instanceof Error ? error.message : "CDP not ready"
1027
+ error: `Chrome not connected (CDP at ${cdpTarget})`,
1028
+ reason,
1029
+ hint: "Make sure Chrome is running. Try: bb-browser daemon shutdown && bb-browser tab list"
1026
1030
  });
1027
1031
  return;
1028
1032
  }
@@ -1148,6 +1152,8 @@ var CdpConnection = class {
1148
1152
  currentTargetId;
1149
1153
  connectionPromise = null;
1150
1154
  _connected = false;
1155
+ /** Last connection error (for diagnostics in 503 responses). */
1156
+ lastError = null;
1151
1157
  /** Resolvers for commands queued before CDP is ready. */
1152
1158
  readyWaiters = [];
1153
1159
  constructor(host, port, tabManager) {
@@ -1171,6 +1177,15 @@ var CdpConnection = class {
1171
1177
  this.connectionPromise = this.doConnect();
1172
1178
  try {
1173
1179
  await this.connectionPromise;
1180
+ this.lastError = null;
1181
+ } catch (err) {
1182
+ this.lastError = err instanceof Error ? err.message : String(err);
1183
+ const connErr = new Error(this.lastError);
1184
+ for (const waiter of this.readyWaiters) {
1185
+ waiter.reject(connErr);
1186
+ }
1187
+ this.readyWaiters = [];
1188
+ throw err;
1174
1189
  } finally {
1175
1190
  this.connectionPromise = null;
1176
1191
  }
@@ -1202,6 +1217,7 @@ var CdpConnection = class {
1202
1217
  /** Wait until CDP connection is established (for two-phase startup). */
1203
1218
  waitUntilReady() {
1204
1219
  if (this._connected) return Promise.resolve();
1220
+ if (this.lastError) return Promise.reject(new Error(this.lastError));
1205
1221
  return new Promise((resolve, reject) => {
1206
1222
  this.readyWaiters.push({ resolve, reject });
1207
1223
  });
@@ -1308,10 +1324,16 @@ var CdpConnection = class {
1308
1324
  ws.on("close", () => {
1309
1325
  this._connected = false;
1310
1326
  this.socket = null;
1327
+ this.lastError = "CDP WebSocket closed unexpectedly";
1311
1328
  for (const p of this.pending.values()) {
1312
1329
  p.reject(new Error("CDP connection closed"));
1313
1330
  }
1314
1331
  this.pending.clear();
1332
+ const closeErr = new Error(this.lastError);
1333
+ for (const waiter of this.readyWaiters) {
1334
+ waiter.reject(closeErr);
1335
+ }
1336
+ this.readyWaiters = [];
1315
1337
  });
1316
1338
  ws.on("error", () => {
1317
1339
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../packages/daemon/src/index.ts","../packages/daemon/src/http-server.ts","../packages/daemon/src/command-dispatch.ts","../packages/daemon/src/cdp-connection.ts","../packages/daemon/src/ring-buffer.ts","../packages/daemon/src/tab-state.ts"],"sourcesContent":["/**\n * bb-browser Daemon — CDP-direct backend\n *\n * Unified daemon that handles ALL browser commands (operations + observation)\n * via direct Chrome DevTools Protocol connection.\n *\n * Two-phase startup:\n * 1. HTTP server starts immediately (commands queue until CDP is ready)\n * 2. CDP connection established asynchronously\n */\n\nimport { parseArgs } from \"node:util\";\nimport { writeFileSync, unlinkSync, existsSync, readFileSync } from \"node:fs\";\nimport { mkdirSync } from \"node:fs\";\nimport { randomBytes } from \"node:crypto\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { DAEMON_PORT, DAEMON_HOST } from \"@bb-browser/shared\";\nimport { HttpServer } from \"./http-server.js\";\nimport { CdpConnection } from \"./cdp-connection.js\";\nimport { TabStateManager } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DAEMON_DIR = process.env.BB_BROWSER_HOME || path.join(os.homedir(), \".bb-browser\");\nconst DAEMON_JSON = path.join(DAEMON_DIR, \"daemon.json\");\nconst DEFAULT_CDP_PORT = 19825;\n\n// ---------------------------------------------------------------------------\n// CLI argument parsing\n// ---------------------------------------------------------------------------\n\ninterface DaemonOptions {\n host: string;\n port: number;\n cdpHost: string;\n cdpPort: number;\n token: string;\n}\n\nfunction parseOptions(): DaemonOptions {\n const { values } = parseArgs({\n allowPositionals: true,\n options: {\n host: {\n type: \"string\",\n short: \"H\",\n default: DAEMON_HOST,\n },\n port: {\n type: \"string\",\n short: \"p\",\n default: String(DAEMON_PORT),\n },\n \"cdp-host\": {\n type: \"string\",\n default: \"127.0.0.1\",\n },\n \"cdp-port\": {\n type: \"string\",\n default: String(DEFAULT_CDP_PORT),\n },\n token: {\n type: \"string\",\n default: \"\",\n },\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n },\n });\n\n if (values.help) {\n console.error(`\nbb-browser-daemon — CDP-direct backend for bb-browser\n\nUsage:\n bb-browser-daemon [options]\n\nOptions:\n -H, --host <host> HTTP server host (default: ${DAEMON_HOST})\n -p, --port <port> HTTP server port (default: ${DAEMON_PORT})\n --cdp-host <host> Chrome CDP host (default: 127.0.0.1)\n --cdp-port <port> Chrome CDP port (default: ${DEFAULT_CDP_PORT})\n --token <token> Bearer auth token (auto-generated if empty)\n -h, --help Show this help message\n\nEndpoints:\n POST /command Send command and get result (via CDP)\n GET /status Daemon health + per-tab stats\n POST /shutdown Graceful shutdown\n`);\n process.exit(0);\n }\n\n // Auto-generate token if not provided\n let token = values.token ?? \"\";\n if (!token) {\n token = randomBytes(16).toString(\"hex\");\n }\n\n return {\n host: values.host ?? DAEMON_HOST,\n port: parseInt(values.port ?? String(DAEMON_PORT), 10),\n cdpHost: values[\"cdp-host\"] ?? \"127.0.0.1\",\n cdpPort: parseInt(values[\"cdp-port\"] ?? String(DEFAULT_CDP_PORT), 10),\n token,\n };\n}\n\n// ---------------------------------------------------------------------------\n// daemon.json management\n// ---------------------------------------------------------------------------\n\ninterface DaemonInfo {\n pid: number;\n host: string;\n port: number;\n token: string;\n}\n\nfunction writeDaemonJson(info: DaemonInfo): void {\n try {\n mkdirSync(DAEMON_DIR, { recursive: true });\n writeFileSync(DAEMON_JSON, JSON.stringify(info), { mode: 0o600 });\n } catch {}\n}\n\nfunction cleanupDaemonJson(): void {\n if (existsSync(DAEMON_JSON)) {\n try {\n unlinkSync(DAEMON_JSON);\n } catch {}\n }\n}\n\n// ---------------------------------------------------------------------------\n// CDP port discovery (simplified — daemon is told the port)\n// ---------------------------------------------------------------------------\n\nasync function discoverCdpPort(host: string, port: number): Promise<{ host: string; port: number }> {\n // Try connecting to the specified port first\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n try {\n const response = await fetch(`http://${host}:${port}/json/version`, {\n signal: controller.signal,\n });\n if (response.ok) {\n return { host, port };\n }\n } finally {\n clearTimeout(timer);\n }\n } catch {}\n\n // Try reading managed browser port file\n const managedPortFile = path.join(DAEMON_DIR, \"browser\", \"cdp-port\");\n try {\n const rawPort = readFileSync(managedPortFile, \"utf8\").trim();\n const managedPort = parseInt(rawPort, 10);\n if (Number.isInteger(managedPort) && managedPort > 0) {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n try {\n const response = await fetch(`http://127.0.0.1:${managedPort}/json/version`, {\n signal: controller.signal,\n });\n if (response.ok) {\n return { host: \"127.0.0.1\", port: managedPort };\n }\n } finally {\n clearTimeout(timer);\n }\n } catch {}\n }\n } catch {}\n\n throw new Error(\n `Cannot connect to Chrome CDP at ${host}:${port}. ` +\n `Make sure Chrome is running with --remote-debugging-port=${port}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nasync function main(): Promise<void> {\n const options = parseOptions();\n\n // Create tab state manager and CDP connection\n const tabManager = new TabStateManager();\n let cdpEndpoint: { host: string; port: number };\n\n try {\n cdpEndpoint = await discoverCdpPort(options.cdpHost, options.cdpPort);\n } catch (error) {\n console.error(\n `[Daemon] ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n\n const cdp = new CdpConnection(cdpEndpoint.host, cdpEndpoint.port, tabManager);\n\n // Graceful shutdown handler (guarded against double-call)\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.error(\"[Daemon] Shutting down...\");\n cdp.disconnect();\n await httpServer.stop();\n cleanupDaemonJson();\n process.exit(0);\n };\n\n // Phase 1: Start HTTP server immediately\n const httpServer = new HttpServer({\n host: options.host,\n port: options.port,\n token: options.token,\n cdp,\n onShutdown: shutdown,\n });\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n await httpServer.start();\n writeDaemonJson({\n pid: process.pid,\n host: options.host,\n port: options.port,\n token: options.token,\n });\n\n console.error(\n `[Daemon] HTTP server listening on http://${options.host}:${options.port}`,\n );\n console.error(`[Daemon] Auth token: ${options.token}`);\n\n // Phase 2: Connect to CDP asynchronously\n console.error(\n `[Daemon] Connecting to Chrome CDP at ${cdpEndpoint.host}:${cdpEndpoint.port}...`,\n );\n\n try {\n await cdp.connect();\n const tabCount = tabManager.tabCount;\n console.error(\n `[Daemon] CDP connected, monitoring ${tabCount} tab(s)`,\n );\n } catch (error) {\n console.error(\n `[Daemon] Failed to connect to CDP: ${error instanceof Error ? error.message : String(error)}`,\n );\n console.error(\"[Daemon] HTTP server is running, but commands will fail until CDP connects.\");\n }\n}\n\nmain().catch((error) => {\n console.error(\"[Daemon] Fatal error:\", error);\n cleanupDaemonJson();\n process.exit(1);\n});\n","/**\n * HTTP Server for the CDP-direct daemon.\n *\n * Endpoints:\n * POST /command — receive Request, dispatch via CDP, return Response\n * GET /status — daemon health + per-tab stats\n * POST /shutdown — graceful shutdown\n *\n * Bearer token authentication (optional, but enforced when token is set).\n * Two-phase startup: HTTP server starts immediately, CDP connects async.\n * Commands received before CDP is ready queue and wait.\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { Request } from \"@bb-browser/shared\";\nimport { COMMAND_TIMEOUT, DAEMON_PORT } from \"@bb-browser/shared\";\nimport { CdpConnection } from \"./cdp-connection.js\";\nimport { dispatchRequest } from \"./command-dispatch.js\";\n\nexport interface HttpServerOptions {\n host?: string;\n port?: number;\n token?: string;\n cdp: CdpConnection;\n onShutdown?: () => void;\n}\n\nexport class HttpServer {\n private server: Server | null = null;\n private readonly host: string;\n private readonly port: number;\n private readonly token: string | null;\n private readonly cdp: CdpConnection;\n private readonly onShutdown?: () => void;\n private startTime = 0;\n\n constructor(options: HttpServerOptions) {\n this.host = options.host ?? \"127.0.0.1\";\n this.port = options.port ?? DAEMON_PORT;\n this.token = options.token ?? null;\n this.cdp = options.cdp;\n this.onShutdown = options.onShutdown;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n this.server.on(\"error\", reject);\n\n this.server.listen(this.port, this.host, () => {\n this.startTime = Date.now();\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n if (this.server) {\n return new Promise((resolve) => {\n this.server!.close(() => resolve());\n });\n }\n }\n\n get uptime(): number {\n if (this.startTime === 0) return 0;\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n // ---------------------------------------------------------------------------\n // Auth\n // ---------------------------------------------------------------------------\n\n private checkAuth(req: IncomingMessage, res: ServerResponse): boolean {\n if (!this.token) return true;\n const auth = req.headers.authorization ?? \"\";\n if (auth === `Bearer ${this.token}`) return true;\n this.sendJson(res, 401, { error: \"Unauthorized\" });\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Routing\n // ---------------------------------------------------------------------------\n\n private handleRequest(req: IncomingMessage, res: ServerResponse): void {\n // CORS\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (!this.checkAuth(req, res)) return;\n\n const url = req.url ?? \"/\";\n\n if (req.method === \"POST\" && url === \"/command\") {\n this.handleCommand(req, res);\n } else if (req.method === \"GET\" && url === \"/status\") {\n this.handleStatus(req, res);\n } else if (req.method === \"POST\" && url === \"/shutdown\") {\n this.handleShutdown(req, res);\n } else {\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n }\n\n // ---------------------------------------------------------------------------\n // POST /command\n // ---------------------------------------------------------------------------\n\n private async handleCommand(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n const body = await this.readBody(req);\n const request = JSON.parse(body) as Request;\n\n // Wait for CDP to be ready (two-phase startup)\n if (!this.cdp.connected) {\n try {\n await Promise.race([\n this.cdp.waitUntilReady(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"CDP connection timeout\")), COMMAND_TIMEOUT),\n ),\n ]);\n } catch (error) {\n this.sendJson(res, 503, {\n id: request.id,\n success: false,\n error: error instanceof Error ? error.message : \"CDP not ready\",\n });\n return;\n }\n }\n\n // Dispatch with timeout\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"Command timeout\")), COMMAND_TIMEOUT),\n );\n const response = await Promise.race([\n dispatchRequest(this.cdp, request),\n timeout,\n ]);\n this.sendJson(res, 200, response);\n } catch (error) {\n this.sendJson(res, 400, {\n success: false,\n error: error instanceof Error ? error.message : \"Invalid request\",\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // GET /status\n // ---------------------------------------------------------------------------\n\n private handleStatus(_req: IncomingMessage, res: ServerResponse): void {\n const tabs = this.cdp.tabManager.allTabs().map((tab) => ({\n shortId: tab.shortId,\n targetId: tab.targetId,\n networkRequests: tab.networkRequests.size,\n consoleMessages: tab.consoleMessages.size,\n jsErrors: tab.jsErrors.size,\n lastActionSeq: tab.lastActionSeq,\n }));\n\n this.sendJson(res, 200, {\n running: true,\n cdpConnected: this.cdp.connected,\n uptime: this.uptime,\n currentSeq: this.cdp.tabManager.currentSeq(),\n currentTargetId: this.cdp.currentTargetId,\n tabs,\n });\n }\n\n // ---------------------------------------------------------------------------\n // POST /shutdown\n // ---------------------------------------------------------------------------\n\n private handleShutdown(_req: IncomingMessage, res: ServerResponse): void {\n this.sendJson(res, 200, { code: 0, message: \"Shutting down\" });\n\n setTimeout(() => {\n if (this.onShutdown) {\n this.onShutdown();\n }\n }, 100);\n }\n\n // ---------------------------------------------------------------------------\n // Utility\n // ---------------------------------------------------------------------------\n\n private readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n req.on(\"error\", reject);\n });\n }\n\n private sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n });\n res.end(body);\n }\n}\n","/**\n * Command dispatch — handles all browser commands via CDP.\n *\n * Ported from cli/cdp-client.ts dispatchRequest, adapted to use\n * CdpConnection + TabStateManager for per-tab state and seq tracking.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type {\n Request,\n Response,\n ResponseData,\n RefInfo,\n SnapshotData,\n TraceEvent,\n TraceStatus,\n} from \"@bb-browser/shared\";\nimport { CdpConnection, type CdpTargetInfo } from \"./cdp-connection.js\";\nimport type { TabState } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface RawDomTextNode {\n type: \"TEXT_NODE\";\n text: string;\n isVisible: boolean;\n}\n\ninterface RawDomElementNode {\n tagName: string;\n xpath: string | null;\n attributes: Record<string, string>;\n children: string[];\n isVisible?: boolean;\n isInteractive?: boolean;\n isTopElement?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n}\n\ntype RawDomTreeNode = RawDomTextNode | RawDomElementNode;\n\ninterface BuildDomTreeResult {\n rootId: string;\n map: Record<string, RawDomTreeNode>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildRequestError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Extended response data with daemon-specific fields.\n * Relaxes frameInfo.frameId to accept string (CDP uses string frame IDs).\n */\ntype ExtResponseData = Omit<ResponseData, \"tabs\" | \"frameInfo\"> & {\n tabs?: Array<Record<string, unknown>>;\n frameInfo?: {\n selector?: string;\n name?: string;\n url?: string;\n frameId?: string | number;\n };\n};\n\nfunction ok(id: string, data?: ExtResponseData): Response {\n return { id, success: true, data: data as ResponseData };\n}\n\nfunction fail(id: string, error: unknown): Response {\n return { id, success: false, error: buildRequestError(error).message };\n}\n\n// ---------------------------------------------------------------------------\n// buildDomTree script loading\n// ---------------------------------------------------------------------------\n\nlet cachedBuildDomTreeScript: string | null = null;\n\nfunction loadBuildDomTreeScript(): string {\n if (cachedBuildDomTreeScript) return cachedBuildDomTreeScript;\n\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n // Built dist: dist/daemon.js → ../packages/shared/buildDomTree.js\n path.resolve(currentDir, \"../packages/shared/buildDomTree.js\"),\n // Dev mode: packages/daemon/src/ → ../../shared/buildDomTree.js\n path.resolve(currentDir, \"../../shared/buildDomTree.js\"),\n // npm installed: dist/daemon.js → same level\n path.resolve(currentDir, \"./buildDomTree.js\"),\n path.resolve(currentDir, \"../buildDomTree.js\"),\n ];\n for (const candidate of candidates) {\n try {\n cachedBuildDomTreeScript = readFileSync(candidate, \"utf8\");\n return cachedBuildDomTreeScript;\n } catch {}\n }\n throw new Error(\"Cannot find buildDomTree.js\");\n}\n\n// ---------------------------------------------------------------------------\n// Snapshot building\n// ---------------------------------------------------------------------------\n\nfunction convertBuildDomTreeResult(\n result: BuildDomTreeResult,\n options: { interactiveOnly: boolean; compact: boolean; maxDepth?: number; selector?: string },\n): SnapshotData {\n const { interactiveOnly, compact, maxDepth, selector } = options;\n const { rootId, map } = result;\n const refs: Record<string, RefInfo> = {};\n const lines: string[] = [];\n\n const getRole = (node: RawDomElementNode): string => {\n const tagName = node.tagName.toLowerCase();\n const role = node.attributes?.role;\n if (role) return role;\n const type = node.attributes?.type?.toLowerCase() || \"text\";\n const inputRoleMap: Record<string, string> = {\n text: \"textbox\", password: \"textbox\", email: \"textbox\", url: \"textbox\", tel: \"textbox\",\n search: \"searchbox\", number: \"spinbutton\", range: \"slider\", checkbox: \"checkbox\",\n radio: \"radio\", button: \"button\", submit: \"button\", reset: \"button\", file: \"button\",\n };\n const roleMap: Record<string, string> = {\n a: \"link\", button: \"button\", input: inputRoleMap[type] || \"textbox\", select: \"combobox\",\n textarea: \"textbox\", img: \"image\", nav: \"navigation\", main: \"main\", header: \"banner\",\n footer: \"contentinfo\", aside: \"complementary\", form: \"form\", table: \"table\", ul: \"list\",\n ol: \"list\", li: \"listitem\", h1: \"heading\", h2: \"heading\", h3: \"heading\", h4: \"heading\",\n h5: \"heading\", h6: \"heading\", dialog: \"dialog\", article: \"article\", section: \"region\",\n label: \"label\", details: \"group\", summary: \"button\",\n };\n return roleMap[tagName] || tagName;\n };\n\n const collectTextContent = (node: RawDomElementNode, nodeMap: Record<string, RawDomTreeNode>, depthLimit = 5): string => {\n const texts: string[] = [];\n const visit = (nodeId: string, depth: number): void => {\n if (depth > depthLimit) return;\n const currentNode = nodeMap[nodeId];\n if (!currentNode) return;\n if (\"type\" in currentNode && currentNode.type === \"TEXT_NODE\") {\n const text = currentNode.text.trim();\n if (text) texts.push(text);\n return;\n }\n for (const childId of (currentNode as RawDomElementNode).children || []) visit(childId, depth + 1);\n };\n for (const childId of node.children || []) visit(childId, 0);\n return texts.join(\" \").trim();\n };\n\n const getName = (node: RawDomElementNode): string | undefined => {\n const attrs = node.attributes || {};\n return attrs[\"aria-label\"] || attrs.title || attrs.placeholder || attrs.alt || attrs.value || collectTextContent(node, map) || attrs.name || undefined;\n };\n\n const truncateText = (text: string, length = 50): string =>\n text.length <= length ? text : `${text.slice(0, length - 3)}...`;\n\n const selectorText = selector?.trim().toLowerCase();\n const matchesSelector = (node: RawDomElementNode, role: string, name?: string): boolean => {\n if (!selectorText) return true;\n const haystack = [node.tagName, role, name, node.xpath || \"\", ...Object.values(node.attributes || {})].join(\" \").toLowerCase();\n return haystack.includes(selectorText);\n };\n\n if (interactiveOnly) {\n const interactiveNodes = Object.entries(map)\n .filter(([, node]) => !(\"type\" in node) && node.highlightIndex !== undefined && node.highlightIndex !== null)\n .map(([id, node]) => ({ id, node: node as RawDomElementNode }))\n .sort((a, b) => (a.node.highlightIndex ?? 0) - (b.node.highlightIndex ?? 0));\n\n for (const { node } of interactiveNodes) {\n const refId = String(node.highlightIndex);\n const role = getRole(node);\n const name = getName(node);\n if (!matchesSelector(node, role, name)) continue;\n let line = `${role} [ref=${refId}]`;\n if (name) line += ` ${JSON.stringify(truncateText(name))}`;\n lines.push(line);\n refs[refId] = { xpath: node.xpath || \"\", role, name, tagName: node.tagName.toLowerCase() } as RefInfo;\n }\n return { snapshot: lines.join(\"\\n\"), refs };\n }\n\n const walk = (nodeId: string, depth: number): void => {\n if (maxDepth !== undefined && depth > maxDepth) return;\n const node = map[nodeId];\n if (!node) return;\n\n if (\"type\" in node && node.type === \"TEXT_NODE\") {\n const text = node.text.trim();\n if (!text) return;\n lines.push(`${\" \".repeat(depth)}- text ${JSON.stringify(truncateText(text, compact ? 80 : 120))}`);\n return;\n }\n\n const el = node as RawDomElementNode;\n const role = getRole(el);\n const name = getName(el);\n if (!matchesSelector(el, role, name)) {\n for (const childId of el.children || []) walk(childId, depth + 1);\n return;\n }\n\n const indent = \" \".repeat(depth);\n const refId = el.highlightIndex !== undefined && el.highlightIndex !== null ? String(el.highlightIndex) : null;\n let line = `${indent}- ${role}`;\n if (refId) line += ` [ref=${refId}]`;\n if (name) line += ` ${JSON.stringify(truncateText(name, compact ? 50 : 80))}`;\n if (!compact) line += ` <${el.tagName.toLowerCase()}>`;\n lines.push(line);\n\n if (refId) {\n refs[refId] = { xpath: el.xpath || \"\", role, name, tagName: el.tagName.toLowerCase() } as RefInfo;\n }\n\n for (const childId of el.children || []) walk(childId, depth + 1);\n };\n\n walk(rootId, 0);\n return { snapshot: lines.join(\"\\n\"), refs };\n}\n\nasync function buildSnapshot(\n cdp: CdpConnection,\n targetId: string,\n tab: TabState,\n request: Request,\n): Promise<SnapshotData> {\n const script = loadBuildDomTreeScript();\n const buildArgs = {\n showHighlightElements: true,\n focusHighlightIndex: -1,\n viewportExpansion: -1,\n debugMode: false,\n startId: 0,\n startHighlightIndex: 0,\n };\n const expression = `(() => { ${script}; const fn = globalThis.buildDomTree ?? (typeof window !== 'undefined' ? window.buildDomTree : undefined); if (typeof fn !== 'function') { throw new Error('buildDomTree is not available after script injection'); } return fn(${JSON.stringify(buildArgs)}); })()`;\n const value = await cdp.evaluate<BuildDomTreeResult | null>(targetId, expression, true);\n\n if (!value || !value.map || !value.rootId) {\n const title = await cdp.evaluate<string>(targetId, \"document.title\", true);\n const pageUrl = await cdp.evaluate<string>(targetId, \"location.href\", true);\n tab.refs = {};\n return { snapshot: title || pageUrl, refs: {} };\n }\n\n const snapshot = convertBuildDomTreeResult(value, {\n interactiveOnly: !!request.interactive,\n compact: !!request.compact,\n maxDepth: request.maxDepth,\n selector: request.selector,\n });\n tab.refs = snapshot.refs || {};\n return snapshot;\n}\n\n// ---------------------------------------------------------------------------\n// Ref resolution\n// ---------------------------------------------------------------------------\n\nasync function resolveBackendNodeIdByXPath(\n cdp: CdpConnection,\n targetId: string,\n xpath: string,\n): Promise<number> {\n await cdp.sessionCommand(targetId, \"DOM.getDocument\", { depth: 0 });\n const search = await cdp.sessionCommand<{ searchId: string; resultCount: number }>(\n targetId,\n \"DOM.performSearch\",\n { query: xpath, includeUserAgentShadowDOM: true },\n );\n\n try {\n if (!search.resultCount) {\n throw new Error(`Unknown ref xpath: ${xpath}`);\n }\n const { nodeIds } = await cdp.sessionCommand<{ nodeIds: number[] }>(\n targetId,\n \"DOM.getSearchResults\",\n { searchId: search.searchId, fromIndex: 0, toIndex: search.resultCount },\n );\n\n for (const nodeId of nodeIds) {\n const described = await cdp.sessionCommand<{\n node: { backendNodeId?: number };\n }>(targetId, \"DOM.describeNode\", { nodeId });\n if (described.node.backendNodeId) {\n return described.node.backendNodeId;\n }\n }\n throw new Error(`XPath resolved but no backend node id found: ${xpath}`);\n } finally {\n await cdp.sessionCommand(targetId, \"DOM.discardSearchResults\", { searchId: search.searchId }).catch(() => {});\n }\n}\n\nasync function parseRef(cdp: CdpConnection, targetId: string, tab: TabState, ref: string): Promise<number> {\n const found = tab.refs[ref];\n if (!found) {\n throw new Error(`Unknown ref: ${ref}. Run snapshot first.`);\n }\n if (found.backendDOMNodeId) {\n return found.backendDOMNodeId;\n }\n if (found.xpath) {\n const backendDOMNodeId = await resolveBackendNodeIdByXPath(cdp, targetId, found.xpath);\n found.backendDOMNodeId = backendDOMNodeId;\n return backendDOMNodeId;\n }\n throw new Error(`Unknown ref: ${ref}. Run snapshot first.`);\n}\n\n// ---------------------------------------------------------------------------\n// Input helpers\n// ---------------------------------------------------------------------------\n\nasync function getInteractablePoint(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n): Promise<{ x: number; y: number }> {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{\n result: { value?: { x?: number; y?: number } };\n exceptionDetails?: { text?: string };\n }>(targetId, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() {\n if (!(this instanceof Element)) {\n throw new Error('Ref does not resolve to an element');\n }\n this.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' });\n const rect = this.getBoundingClientRect();\n if (!rect || rect.width <= 0 || rect.height <= 0) {\n throw new Error('Element is not visible');\n }\n return {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n }`,\n returnByValue: true,\n });\n\n if (call.exceptionDetails) {\n throw new Error(call.exceptionDetails.text || \"Failed to resolve element point\");\n }\n\n const point = call.result.value;\n if (\n !point ||\n typeof point.x !== \"number\" ||\n typeof point.y !== \"number\" ||\n !Number.isFinite(point.x) ||\n !Number.isFinite(point.y)\n ) {\n throw new Error(\"Failed to resolve element point\");\n }\n return point as { x: number; y: number };\n}\n\nasync function mouseClick(cdp: CdpConnection, targetId: string, x: number, y: number): Promise<void> {\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mouseMoved\", x, y, button: \"none\",\n });\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mousePressed\", x, y, button: \"left\", clickCount: 1,\n });\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mouseReleased\", x, y, button: \"left\", clickCount: 1,\n });\n}\n\nasync function insertTextIntoNode(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n text: string,\n clearFirst: boolean,\n): Promise<void> {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n\n await cdp.sessionCommand(targetId, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function(clearFirst) {\n if (typeof this.scrollIntoView === 'function') {\n this.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' });\n }\n if (typeof this.focus === 'function') this.focus();\n if (this instanceof HTMLInputElement || this instanceof HTMLTextAreaElement) {\n if (clearFirst) {\n this.value = '';\n this.dispatchEvent(new Event('input', { bubbles: true }));\n }\n if (typeof this.setSelectionRange === 'function') {\n const end = this.value.length;\n this.setSelectionRange(end, end);\n }\n return true;\n }\n if (this instanceof HTMLElement && this.isContentEditable) {\n if (clearFirst) {\n this.textContent = '';\n this.dispatchEvent(new Event('input', { bubbles: true }));\n }\n const selection = window.getSelection();\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(this);\n range.collapse(false);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n return true;\n }\n return false;\n }`,\n arguments: [{ value: clearFirst }],\n returnByValue: true,\n });\n\n if (text) {\n await cdp.sessionCommand(targetId, \"DOM.focus\", { backendNodeId });\n await cdp.sessionCommand(targetId, \"Input.insertText\", { text });\n }\n}\n\nasync function getAttributeValue(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n attribute: string,\n): Promise<string> {\n if (attribute === \"text\") {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{ result: { value: string } }>(\n targetId,\n \"Runtime.callFunctionOn\",\n {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { return (this instanceof HTMLElement ? this.innerText : this.textContent || '').trim(); }`,\n returnByValue: true,\n },\n );\n return String(call.result.value ?? \"\");\n }\n const result = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{ result: { value: string } }>(\n targetId,\n \"Runtime.callFunctionOn\",\n {\n objectId: result.object.objectId,\n functionDeclaration: `function() { if (${JSON.stringify(attribute)} === 'url') return this.href || this.src || location.href; if (${JSON.stringify(attribute)} === 'title') return document.title; return this.getAttribute(${JSON.stringify(attribute)}) || ''; }`,\n returnByValue: true,\n },\n );\n return String(call.result.value ?? \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Trace state (global, not per-tab — matches original behavior)\n// ---------------------------------------------------------------------------\n\nlet traceRecording = false;\nconst traceEvents: TraceEvent[] = [];\n\n// ---------------------------------------------------------------------------\n// Main dispatch\n// ---------------------------------------------------------------------------\n\n/**\n * Dispatch a command request. This is the core function that handles all\n * browser automation commands via CDP.\n */\nexport async function dispatchRequest(\n cdp: CdpConnection,\n request: Request,\n): Promise<Response> {\n // Resolve target from request.tabId (supports short IDs)\n const tabRef = request.tabId;\n\n // tab_new must work even when there are no existing tabs,\n // so handle it before ensurePageTarget().\n if (request.action === \"tab_new\") {\n const url = request.url ?? \"about:blank\";\n const created = await cdp.browserCommand<{ targetId: string }>(\n \"Target.createTarget\",\n { url, background: true },\n );\n await cdp.attachAndEnable(created.targetId);\n const newTab = cdp.tabManager.getTab(created.targetId);\n return ok(request.id, {\n tabId: created.targetId,\n url,\n tab: newTab?.shortId ?? created.targetId.slice(-4).toLowerCase(),\n seq: newTab?.recordAction(),\n });\n }\n\n const target = await cdp.ensurePageTarget(\n tabRef !== undefined ? String(tabRef) : undefined,\n );\n const tab = cdp.tabManager.getTab(target.id);\n if (!tab) throw new Error(\"Internal error: tab state not found\");\n\n const shortId = tab.shortId;\n\n switch (request.action) {\n // -----------------------------------------------------------------------\n // Navigation\n // -----------------------------------------------------------------------\n case \"open\": {\n if (!request.url) return fail(request.id, \"Missing url parameter\");\n const seq = tab.recordAction();\n if (tabRef === undefined) {\n // No specific tab requested — open in new tab\n const created = await cdp.browserCommand<{ targetId: string }>(\n \"Target.createTarget\",\n { url: request.url, background: true },\n );\n const newTarget = await cdp.ensurePageTarget(created.targetId);\n const newTab = cdp.tabManager.getTab(newTarget.id);\n return ok(request.id, {\n url: request.url,\n tabId: newTarget.id,\n tab: newTab?.shortId ?? shortId,\n seq,\n });\n }\n await cdp.pageCommand(target.id, \"Page.navigate\", { url: request.url });\n tab.refs = {};\n return ok(request.id, {\n url: request.url,\n title: target.title,\n tabId: target.id,\n tab: shortId,\n seq,\n });\n }\n\n case \"back\": {\n const seq = tab.recordAction();\n await cdp.evaluate(target.id, \"history.back(); undefined\");\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"forward\": {\n const seq = tab.recordAction();\n await cdp.evaluate(target.id, \"history.forward(); undefined\");\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"refresh\": {\n const seq = tab.recordAction();\n await cdp.sessionCommand(target.id, \"Page.reload\", { ignoreCache: false });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"close\": {\n const seq = tab.recordAction();\n await cdp.browserCommand(\"Target.closeTarget\", { targetId: target.id });\n tab.refs = {};\n return ok(request.id, { tab: shortId, seq });\n }\n\n // -----------------------------------------------------------------------\n // Snapshot / observation\n // -----------------------------------------------------------------------\n case \"snapshot\": {\n const snapshotData = await buildSnapshot(cdp, target.id, tab, request);\n return ok(request.id, {\n title: target.title,\n url: target.url,\n snapshotData,\n tab: shortId,\n });\n }\n\n case \"screenshot\": {\n const result = await cdp.sessionCommand<{ data: string }>(\n target.id,\n \"Page.captureScreenshot\",\n { format: \"png\", fromSurface: true },\n );\n return ok(request.id, {\n dataUrl: `data:image/png;base64,${result.data}`,\n tab: shortId,\n });\n }\n\n // -----------------------------------------------------------------------\n // Element interaction\n // -----------------------------------------------------------------------\n case \"click\":\n case \"hover\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const point = await getInteractablePoint(cdp, target.id, backendNodeId);\n await cdp.sessionCommand(target.id, \"Input.dispatchMouseEvent\", {\n type: \"mouseMoved\", x: point.x, y: point.y, button: \"none\",\n });\n if (request.action === \"click\") {\n await mouseClick(cdp, target.id, point.x, point.y);\n }\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"fill\":\n case \"type\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n if (request.text == null) return fail(request.id, \"Missing text parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n await insertTextIntoNode(cdp, target.id, backendNodeId, request.text, request.action === \"fill\");\n return ok(request.id, {\n value: request.text,\n tab: shortId,\n seq,\n });\n }\n\n case \"check\":\n case \"uncheck\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const seq = tab.recordAction();\n const desired = request.action === \"check\";\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n target.id,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n await cdp.sessionCommand(target.id, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { this.checked = ${desired}; this.dispatchEvent(new Event('input', { bubbles: true })); this.dispatchEvent(new Event('change', { bubbles: true })); }`,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"select\": {\n if (!request.ref || request.value == null) return fail(request.id, \"Missing ref or value parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n target.id,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n await cdp.sessionCommand(target.id, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { this.value = ${JSON.stringify(request.value)}; this.dispatchEvent(new Event('input', { bubbles: true })); this.dispatchEvent(new Event('change', { bubbles: true })); }`,\n });\n return ok(request.id, {\n value: request.value,\n tab: shortId,\n seq,\n });\n }\n\n case \"get\": {\n if (!request.attribute) return fail(request.id, \"Missing attribute parameter\");\n if (request.attribute === \"url\" && !request.ref) {\n return ok(request.id, {\n value: await cdp.evaluate<string>(target.id, \"location.href\", true),\n tab: shortId,\n });\n }\n if (request.attribute === \"title\" && !request.ref) {\n return ok(request.id, {\n value: await cdp.evaluate<string>(target.id, \"document.title\", true),\n tab: shortId,\n });\n }\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const value = await getAttributeValue(\n cdp,\n target.id,\n await parseRef(cdp, target.id, tab, request.ref),\n request.attribute,\n );\n return ok(request.id, { value, tab: shortId });\n }\n\n case \"press\": {\n if (!request.key) return fail(request.id, \"Missing key parameter\");\n const seq = tab.recordAction();\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"keyDown\", key: request.key,\n });\n if (request.key.length === 1) {\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"char\", text: request.key, key: request.key,\n });\n }\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"keyUp\", key: request.key,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"scroll\": {\n const seq = tab.recordAction();\n const deltaY = request.direction === \"up\"\n ? -(request.pixels ?? 300)\n : (request.pixels ?? 300);\n await cdp.sessionCommand(target.id, \"Input.dispatchMouseEvent\", {\n type: \"mouseWheel\", x: 0, y: 0, deltaX: 0, deltaY,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"wait\": {\n await new Promise((resolve) => setTimeout(resolve, request.ms ?? 1000));\n return ok(request.id, { tab: shortId });\n }\n\n case \"eval\": {\n if (!request.script) return fail(request.id, \"Missing script parameter\");\n const seq = tab.recordAction();\n const result = await cdp.evaluate<unknown>(target.id, request.script, true);\n return ok(request.id, {\n result,\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Tab management\n // -----------------------------------------------------------------------\n case \"tab_list\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n const tabs = targets.map((t, index) => {\n const tState = cdp.tabManager.getTab(t.id);\n return {\n index,\n url: t.url,\n title: t.title,\n active: t.id === cdp.currentTargetId || (!cdp.currentTargetId && index === 0),\n tabId: t.id,\n tab: tState?.shortId ?? t.id.slice(-4).toLowerCase(),\n };\n });\n return ok(request.id, {\n tabs,\n activeIndex: tabs.findIndex((t) => t.active),\n });\n }\n\n // tab_new is handled before ensurePageTarget() above\n\n case \"tab_select\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n let selected: CdpTargetInfo | undefined;\n\n if (request.tabId !== undefined) {\n const tabIdStr = String(request.tabId);\n // Try short ID\n const resolvedId = cdp.tabManager.resolveShortId(tabIdStr);\n if (resolvedId) {\n selected = targets.find((t) => t.id === resolvedId);\n }\n // Try full target ID\n if (!selected) {\n selected = targets.find((t) => t.id === tabIdStr);\n }\n // Try numeric index\n if (!selected) {\n const num = Number(tabIdStr);\n if (!Number.isNaN(num)) {\n selected = targets[num];\n }\n }\n } else {\n selected = targets[request.index ?? 0];\n }\n\n if (!selected) return fail(request.id, \"Tab not found\");\n cdp.currentTargetId = selected.id;\n await cdp.attachAndEnable(selected.id);\n const selTab = cdp.tabManager.getTab(selected.id);\n return ok(request.id, {\n tabId: selected.id,\n url: selected.url,\n title: selected.title,\n tab: selTab?.shortId,\n });\n }\n\n case \"tab_close\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n let selected: CdpTargetInfo | undefined;\n\n if (request.tabId !== undefined) {\n const tabIdStr = String(request.tabId);\n const resolvedId = cdp.tabManager.resolveShortId(tabIdStr);\n if (resolvedId) {\n selected = targets.find((t) => t.id === resolvedId);\n }\n if (!selected) {\n selected = targets.find((t) => t.id === tabIdStr);\n }\n if (!selected) {\n const num = Number(tabIdStr);\n if (!Number.isNaN(num)) {\n selected = targets[num];\n }\n }\n } else {\n selected = targets[request.index ?? 0];\n }\n\n if (!selected) return fail(request.id, \"Tab not found\");\n const closedTab = cdp.tabManager.getTab(selected.id);\n const closedShort = closedTab?.shortId;\n await cdp.browserCommand(\"Target.closeTarget\", { targetId: selected.id });\n if (cdp.currentTargetId === selected.id) {\n cdp.currentTargetId = undefined;\n }\n return ok(request.id, {\n tabId: selected.id,\n tab: closedShort,\n });\n }\n\n // -----------------------------------------------------------------------\n // Frame navigation\n // -----------------------------------------------------------------------\n case \"frame\": {\n if (!request.selector) return fail(request.id, \"Missing selector parameter\");\n const seq = tab.recordAction();\n const document = await cdp.pageCommand<{ root: { nodeId: number } }>(\n target.id,\n \"DOM.getDocument\",\n {},\n );\n const node = await cdp.pageCommand<{ nodeId: number }>(\n target.id,\n \"DOM.querySelector\",\n { nodeId: document.root.nodeId, selector: request.selector },\n );\n if (!node.nodeId) return fail(request.id, `iframe not found: ${request.selector}`);\n const described = await cdp.pageCommand<{\n node: { frameId?: string; nodeName?: string; attributes?: string[] };\n }>(target.id, \"DOM.describeNode\", { nodeId: node.nodeId });\n const frameId = described.node.frameId;\n const nodeName = String(described.node.nodeName ?? \"\").toLowerCase();\n if (!frameId) return fail(request.id, `Cannot get iframe frameId: ${request.selector}`);\n if (nodeName && nodeName !== \"iframe\" && nodeName !== \"frame\") {\n return fail(request.id, `Element is not an iframe: ${nodeName}`);\n }\n tab.activeFrameId = frameId;\n const attributes = described.node.attributes ?? [];\n const attrMap: Record<string, string> = {};\n for (let i = 0; i < attributes.length; i += 2) {\n attrMap[String(attributes[i])] = String(attributes[i + 1] ?? \"\");\n }\n return ok(request.id, {\n frameInfo: {\n selector: request.selector,\n name: attrMap.name ?? \"\",\n url: attrMap.src ?? \"\",\n frameId,\n },\n tab: shortId,\n seq,\n });\n }\n\n case \"frame_main\": {\n const seq = tab.recordAction();\n tab.activeFrameId = null;\n return ok(request.id, {\n frameInfo: { frameId: 0 },\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Dialog\n // -----------------------------------------------------------------------\n case \"dialog\": {\n const seq = tab.recordAction();\n tab.dialogHandler = {\n accept: request.dialogResponse !== \"dismiss\",\n ...(request.promptText !== undefined ? { promptText: request.promptText } : {}),\n };\n await cdp.sessionCommand(target.id, \"Page.enable\");\n return ok(request.id, {\n dialogInfo: {\n type: \"armed\",\n message: `Dialog handler armed: ${request.dialogResponse ?? \"accept\"}`,\n handled: false,\n },\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Network observation\n // -----------------------------------------------------------------------\n case \"network\": {\n const subCommand = request.networkCommand ?? \"requests\";\n switch (subCommand) {\n case \"requests\": {\n const queryResult = tab.getNetworkRequests({\n since: request.since,\n filter: request.filter,\n method: request.method,\n status: request.status,\n limit: request.limit,\n });\n\n const items = queryResult.items;\n // Fetch response bodies if requested\n if (request.withBody) {\n await Promise.all(\n items.map(async (item) => {\n if (item.failed || item.responseBody !== undefined || item.bodyError !== undefined) return;\n try {\n const body = await cdp.sessionCommand<{ body: string; base64Encoded: boolean }>(\n target.id,\n \"Network.getResponseBody\",\n { requestId: item.requestId },\n );\n item.responseBody = body.body;\n item.responseBodyBase64 = body.base64Encoded;\n } catch (error) {\n item.bodyError = error instanceof Error ? error.message : String(error);\n }\n }),\n );\n }\n\n return ok(request.id, {\n networkRequests: items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"route\":\n return ok(request.id, { routeCount: 0, tab: shortId });\n case \"unroute\":\n return ok(request.id, { routeCount: 0, tab: shortId });\n case \"clear\":\n tab.clearNetwork();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown network subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // Console observation\n // -----------------------------------------------------------------------\n case \"console\": {\n const subCommand = request.consoleCommand ?? \"get\";\n switch (subCommand) {\n case \"get\": {\n const queryResult = tab.getConsoleMessages({\n since: request.since,\n filter: request.filter,\n limit: request.limit,\n });\n return ok(request.id, {\n consoleMessages: queryResult.items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"clear\":\n tab.clearConsole();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown console subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // JS Errors observation\n // -----------------------------------------------------------------------\n case \"errors\": {\n const subCommand = request.errorsCommand ?? \"get\";\n switch (subCommand) {\n case \"get\": {\n const queryResult = tab.getJSErrors({\n since: request.since,\n filter: request.filter,\n limit: request.limit,\n });\n return ok(request.id, {\n jsErrors: queryResult.items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"clear\":\n tab.clearErrors();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown errors subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // Trace\n // -----------------------------------------------------------------------\n case \"trace\": {\n const subCommand = request.traceCommand ?? \"status\";\n switch (subCommand) {\n case \"start\":\n traceRecording = true;\n traceEvents.length = 0;\n return ok(request.id, {\n traceStatus: { recording: true, eventCount: 0 } satisfies TraceStatus,\n tab: shortId,\n });\n case \"stop\": {\n traceRecording = false;\n return ok(request.id, {\n traceEvents: [...traceEvents],\n traceStatus: { recording: false, eventCount: traceEvents.length } satisfies TraceStatus,\n tab: shortId,\n });\n }\n case \"status\":\n return ok(request.id, {\n traceStatus: { recording: traceRecording, eventCount: traceEvents.length } satisfies TraceStatus,\n tab: shortId,\n });\n default:\n return fail(request.id, `Unknown trace subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // History (not implemented in daemon yet)\n // -----------------------------------------------------------------------\n case \"history\": {\n return fail(request.id, \"History command is not supported in daemon mode\");\n }\n\n default:\n return fail(request.id, `Unknown action: ${request.action}`);\n }\n}\n","/**\n * CdpConnection — manages the browser-level WebSocket to Chrome DevTools\n * Protocol. Handles target discovery, auto-attach, session multiplexing,\n * and routes per-target session events to the TabStateManager.\n *\n * Merged from cli/cdp-client.ts (connection management) and\n * cli/cdp-monitor.ts (persistent connection + event listening).\n */\n\nimport { request as httpRequest } from \"node:http\";\nimport WebSocket from \"ws\";\nimport { TabStateManager } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype JsonObject = Record<string, unknown>;\n\ninterface PendingCommand {\n resolve: (value: unknown) => void;\n reject: (reason?: unknown) => void;\n method: string;\n}\n\nexport interface CdpTargetInfo {\n id: string;\n type: string;\n title: string;\n url: string;\n}\n\n// ---------------------------------------------------------------------------\n// CDP helpers\n// ---------------------------------------------------------------------------\n\nfunction fetchJson(url: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const req = httpRequest(url, { method: \"GET\" }, (res) => {\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk: Buffer) => chunks.push(Buffer.from(chunk)));\n res.on(\"end\", () => {\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n if ((res.statusCode ?? 500) >= 400) {\n reject(new Error(`HTTP ${res.statusCode ?? 500}: ${raw}`));\n return;\n }\n try {\n resolve(JSON.parse(raw));\n } catch (error) {\n reject(error);\n }\n });\n });\n req.on(\"error\", reject);\n req.end();\n });\n}\n\nfunction connectWebSocket(url: string): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url);\n ws.once(\"open\", () => resolve(ws));\n ws.once(\"error\", reject);\n });\n}\n\nfunction normalizeHeaders(headers: unknown): Record<string, string> | undefined {\n if (!headers || typeof headers !== \"object\") return undefined;\n return Object.fromEntries(\n Object.entries(headers as Record<string, unknown>).map(([key, value]) => [key, String(value)]),\n );\n}\n\n// ---------------------------------------------------------------------------\n// CdpConnection\n// ---------------------------------------------------------------------------\n\nexport class CdpConnection {\n private socket: WebSocket | null = null;\n private pending = new Map<number, PendingCommand>();\n private nextId = 1;\n\n /** targetId -> sessionId (flat-mode) */\n private sessions = new Map<string, string>();\n /** sessionId -> targetId */\n private attachedTargets = new Map<string, string>();\n\n readonly host: string;\n readonly port: number;\n readonly tabManager: TabStateManager;\n\n /** Current (most recently selected) target ID. */\n currentTargetId: string | undefined;\n\n private connectionPromise: Promise<void> | null = null;\n private _connected = false;\n\n /** Resolvers for commands queued before CDP is ready. */\n private readyWaiters: Array<{ resolve: () => void; reject: (err: Error) => void }> = [];\n\n constructor(host: string, port: number, tabManager: TabStateManager) {\n this.host = host;\n this.port = port;\n this.tabManager = tabManager;\n }\n\n get connected(): boolean {\n return this._connected && this.socket !== null && this.socket.readyState === WebSocket.OPEN;\n }\n\n // ---------------------------------------------------------------------------\n // Connection lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Connect to Chrome's browser-level WebSocket endpoint.\n * Idempotent — returns immediately if already connected.\n */\n async connect(): Promise<void> {\n if (this._connected) return;\n if (this.connectionPromise) return this.connectionPromise;\n\n this.connectionPromise = this.doConnect();\n try {\n await this.connectionPromise;\n } finally {\n this.connectionPromise = null;\n }\n }\n\n private async doConnect(): Promise<void> {\n const versionData = (await fetchJson(\n `http://${this.host}:${this.port}/json/version`,\n )) as JsonObject;\n const wsUrl = versionData.webSocketDebuggerUrl;\n if (typeof wsUrl !== \"string\" || !wsUrl) {\n throw new Error(\"CDP endpoint missing webSocketDebuggerUrl\");\n }\n\n const ws = await connectWebSocket(wsUrl);\n this.socket = ws;\n this._connected = true;\n this.setupListeners(ws);\n\n // Discover + auto-attach existing page targets\n await this.browserCommand(\"Target.setDiscoverTargets\", { discover: true });\n const result = await this.browserCommand<{\n targetInfos: Array<{ targetId: string; type: string; title: string; url: string }>;\n }>(\"Target.getTargets\");\n\n const pages = (result.targetInfos || []).filter((t) => t.type === \"page\");\n for (const page of pages) {\n await this.attachAndEnable(page.targetId).catch(() => {});\n }\n\n // Notify any waiters that CDP is ready\n for (const waiter of this.readyWaiters) {\n waiter.resolve();\n }\n this.readyWaiters = [];\n }\n\n /** Wait until CDP connection is established (for two-phase startup). */\n waitUntilReady(): Promise<void> {\n if (this._connected) return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n this.readyWaiters.push({ resolve, reject });\n });\n }\n\n /** Gracefully close the CDP connection. */\n disconnect(): void {\n if (this.socket) {\n try {\n this.socket.close();\n } catch {}\n }\n this.socket = null;\n this._connected = false;\n\n for (const p of this.pending.values()) {\n p.reject(new Error(\"CDP connection closed\"));\n }\n this.pending.clear();\n\n // Reject any waiters\n for (const waiter of this.readyWaiters) {\n waiter.reject(new Error(\"CDP connection closed before ready\"));\n }\n this.readyWaiters = [];\n }\n\n // ---------------------------------------------------------------------------\n // WebSocket message handling\n // ---------------------------------------------------------------------------\n\n private setupListeners(ws: WebSocket): void {\n ws.on(\"message\", (raw) => {\n const message = JSON.parse(raw.toString()) as JsonObject;\n\n // Response to a browser-level command\n if (typeof message.id === \"number\") {\n const p = this.pending.get(message.id);\n if (!p) return;\n this.pending.delete(message.id);\n if (message.error) {\n p.reject(\n new Error(\n `${p.method}: ${(message.error as JsonObject).message ?? \"Unknown CDP error\"}`,\n ),\n );\n } else {\n p.resolve(message.result);\n }\n return;\n }\n\n // Flat-mode attach\n if (message.method === \"Target.attachedToTarget\") {\n const params = message.params as JsonObject;\n const sessionId = params.sessionId;\n const targetInfo = params.targetInfo as JsonObject;\n if (typeof sessionId === \"string\" && typeof targetInfo?.targetId === \"string\") {\n this.sessions.set(targetInfo.targetId, sessionId);\n this.attachedTargets.set(sessionId, targetInfo.targetId);\n }\n return;\n }\n\n if (message.method === \"Target.detachedFromTarget\") {\n const params = message.params as JsonObject;\n const sessionId = params.sessionId;\n if (typeof sessionId === \"string\") {\n const targetId = this.attachedTargets.get(sessionId);\n if (targetId) {\n this.sessions.delete(targetId);\n this.attachedTargets.delete(sessionId);\n this.tabManager.removeTab(targetId);\n if (this.currentTargetId === targetId) {\n this.currentTargetId = undefined;\n }\n }\n }\n return;\n }\n\n // New target auto-attach\n if (message.method === \"Target.targetCreated\") {\n const params = message.params as JsonObject;\n const targetInfo = params.targetInfo as JsonObject;\n if (targetInfo?.type === \"page\" && typeof targetInfo.targetId === \"string\") {\n this.attachAndEnable(targetInfo.targetId).catch(() => {});\n }\n return;\n }\n\n if (message.method === \"Target.targetDestroyed\") {\n const params = message.params as JsonObject;\n const targetId = params.targetId;\n if (typeof targetId === \"string\") {\n const sessionId = this.sessions.get(targetId);\n if (sessionId) {\n this.sessions.delete(targetId);\n this.attachedTargets.delete(sessionId);\n }\n this.tabManager.removeTab(targetId);\n if (this.currentTargetId === targetId) {\n this.currentTargetId = undefined;\n }\n }\n return;\n }\n\n // Flat protocol: session events carry sessionId directly\n if (typeof message.sessionId === \"string\" && typeof message.method === \"string\") {\n const targetId = this.attachedTargets.get(message.sessionId as string);\n if (targetId) {\n this.handleSessionEvent(targetId, message).catch(() => {});\n }\n }\n });\n\n ws.on(\"close\", () => {\n this._connected = false;\n this.socket = null;\n for (const p of this.pending.values()) {\n p.reject(new Error(\"CDP connection closed\"));\n }\n this.pending.clear();\n });\n\n ws.on(\"error\", () => {});\n }\n\n // ---------------------------------------------------------------------------\n // Session event routing (network, console, errors, dialog)\n // ---------------------------------------------------------------------------\n\n private async handleSessionEvent(targetId: string, event: JsonObject): Promise<void> {\n const method = event.method;\n const params = (event.params ?? {}) as JsonObject;\n if (typeof method !== \"string\") return;\n\n const tab = this.tabManager.getTab(targetId);\n if (!tab) return;\n\n // Dialog handling\n if (method === \"Page.javascriptDialogOpening\") {\n if (tab.dialogHandler) {\n await this.sessionCommand(targetId, \"Page.handleJavaScriptDialog\", {\n accept: tab.dialogHandler.accept,\n ...(tab.dialogHandler.promptText !== undefined\n ? { promptText: tab.dialogHandler.promptText }\n : {}),\n });\n }\n return;\n }\n\n // Network events\n if (method === \"Network.requestWillBeSent\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n const request = params.request as JsonObject | undefined;\n if (!requestId || !request) return;\n tab.addNetworkRequest(requestId, {\n url: String(request.url ?? \"\"),\n method: String(request.method ?? \"GET\"),\n type: String(params.type ?? \"Other\"),\n timestamp: Math.round(Number(params.timestamp ?? Date.now()) * 1000),\n requestHeaders: normalizeHeaders(request.headers),\n requestBody: typeof request.postData === \"string\" ? request.postData : undefined,\n });\n return;\n }\n\n if (method === \"Network.responseReceived\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n const response = params.response as JsonObject | undefined;\n if (!requestId || !response) return;\n tab.updateNetworkResponse(requestId, {\n status: typeof response.status === \"number\" ? response.status : undefined,\n statusText: typeof response.statusText === \"string\" ? response.statusText : undefined,\n responseHeaders: normalizeHeaders(response.headers),\n mimeType: typeof response.mimeType === \"string\" ? response.mimeType : undefined,\n });\n return;\n }\n\n if (method === \"Network.loadingFailed\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n if (!requestId) return;\n tab.updateNetworkFailure(\n requestId,\n typeof params.errorText === \"string\" ? params.errorText : \"Unknown error\",\n );\n return;\n }\n\n // Console events\n if (method === \"Runtime.consoleAPICalled\") {\n const type = String(params.type ?? \"log\");\n const args = Array.isArray(params.args) ? (params.args as JsonObject[]) : [];\n const text = args\n .map((arg) => {\n if (typeof arg.value === \"string\") return arg.value;\n if (arg.value !== undefined) return String(arg.value);\n if (typeof arg.description === \"string\") return arg.description;\n return \"\";\n })\n .filter(Boolean)\n .join(\" \");\n const stack = params.stackTrace as JsonObject | undefined;\n const firstCallFrame = Array.isArray(stack?.callFrames)\n ? (stack?.callFrames[0] as JsonObject | undefined)\n : undefined;\n // Chrome CDP sends \"warning\" for console.warn(); normalize it\n const consoleTypeMap: Record<string, string> = { warning: \"warn\" };\n const normalizedType = consoleTypeMap[type] || type;\n tab.addConsoleMessage({\n type: [\"log\", \"info\", \"warn\", \"error\", \"debug\"].includes(normalizedType)\n ? (normalizedType as \"log\" | \"info\" | \"warn\" | \"error\" | \"debug\")\n : \"log\",\n text,\n timestamp: Math.round(Number(params.timestamp ?? Date.now())),\n url:\n typeof firstCallFrame?.url === \"string\" ? firstCallFrame.url : undefined,\n lineNumber:\n typeof firstCallFrame?.lineNumber === \"number\"\n ? firstCallFrame.lineNumber\n : undefined,\n });\n return;\n }\n\n // JS Error events\n if (method === \"Runtime.exceptionThrown\") {\n const details = params.exceptionDetails as JsonObject | undefined;\n if (!details) return;\n const exception = details.exception as JsonObject | undefined;\n const stackTrace = details.stackTrace as JsonObject | undefined;\n const callFrames = Array.isArray(stackTrace?.callFrames)\n ? (stackTrace.callFrames as JsonObject[])\n : [];\n tab.addJSError({\n message:\n typeof exception?.description === \"string\"\n ? exception.description\n : String(details.text ?? \"JavaScript exception\"),\n url:\n typeof details.url === \"string\"\n ? details.url\n : typeof callFrames[0]?.url === \"string\"\n ? String(callFrames[0].url)\n : undefined,\n lineNumber:\n typeof details.lineNumber === \"number\" ? details.lineNumber : undefined,\n columnNumber:\n typeof details.columnNumber === \"number\" ? details.columnNumber : undefined,\n stackTrace:\n callFrames.length > 0\n ? callFrames\n .map(\n (frame) =>\n `${String(frame.functionName ?? \"<anonymous>\")} (${String(frame.url ?? \"\")}:${String(frame.lineNumber ?? 0)}:${String(frame.columnNumber ?? 0)})`,\n )\n .join(\"\\n\")\n : undefined,\n timestamp: Date.now(),\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // Target management\n // ---------------------------------------------------------------------------\n\n /** Attach to a target and enable required CDP domains. */\n async attachAndEnable(targetId: string): Promise<string> {\n if (this.sessions.has(targetId)) {\n // Already attached — register tab state if not present\n this.tabManager.addTab(targetId);\n return this.sessions.get(targetId)!;\n }\n\n const result = await this.browserCommand<{ sessionId: string }>(\n \"Target.attachToTarget\",\n { targetId, flatten: true },\n );\n this.sessions.set(targetId, result.sessionId);\n this.attachedTargets.set(result.sessionId, targetId);\n\n // Register in tab state manager\n this.tabManager.addTab(targetId);\n\n // Enable domains\n await this.sessionCommand(targetId, \"Page.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Runtime.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Network.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"DOM.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Accessibility.enable\").catch(() => {});\n\n return result.sessionId;\n }\n\n /** Get all targets via CDP Target.getTargets. */\n async getTargets(): Promise<CdpTargetInfo[]> {\n const result = await this.browserCommand<{\n targetInfos: Array<{\n targetId: string;\n type: string;\n title: string;\n url: string;\n }>;\n }>(\"Target.getTargets\");\n\n return (result.targetInfos || []).map((t) => ({\n id: t.targetId,\n type: t.type,\n title: t.title,\n url: t.url,\n }));\n }\n\n /**\n * Ensure we have a valid page target and return it. Supports resolution by:\n * - short ID string\n * - full target ID string\n * - numeric index\n * - undefined (use currentTargetId or first page)\n */\n async ensurePageTarget(tabRef?: string | number): Promise<CdpTargetInfo> {\n const targets = (await this.getTargets()).filter((t) => t.type === \"page\");\n if (targets.length === 0) throw new Error(\"No page target found\");\n\n let target: CdpTargetInfo | undefined;\n\n if (typeof tabRef === \"string\") {\n // Try short ID first\n const resolvedTargetId = this.tabManager.resolveShortId(tabRef);\n if (resolvedTargetId) {\n target = targets.find((t) => t.id === resolvedTargetId);\n }\n // Then try full target ID\n if (!target) {\n target = targets.find((t) => t.id === tabRef);\n }\n // Then try as numeric index\n if (!target) {\n const num = Number(tabRef);\n if (!Number.isNaN(num)) {\n target = targets[num];\n }\n }\n } else if (typeof tabRef === \"number\") {\n target = targets[tabRef];\n } else if (this.currentTargetId) {\n target = targets.find((t) => t.id === this.currentTargetId);\n }\n\n if (typeof tabRef === \"string\" && !target) {\n throw new Error(`Tab not found: ${tabRef}`);\n }\n\n target ??= targets[0];\n this.currentTargetId = target.id;\n await this.attachAndEnable(target.id);\n return target;\n }\n\n /** Check if a session exists for a given targetId. */\n hasSession(targetId: string): boolean {\n return this.sessions.has(targetId);\n }\n\n // ---------------------------------------------------------------------------\n // CDP command sending\n // ---------------------------------------------------------------------------\n\n /** Send a browser-level CDP command. */\n async browserCommand<T = unknown>(method: string, params: JsonObject = {}): Promise<T> {\n if (!this.socket) throw new Error(\"CDP not connected\");\n const id = this.nextId++;\n const payload = JSON.stringify({ id, method, params });\n return new Promise<T>((resolve, reject) => {\n this.pending.set(id, {\n resolve: resolve as (v: unknown) => void,\n reject,\n method,\n });\n this.socket!.send(payload);\n });\n }\n\n /** Send a session-level CDP command (flat protocol). */\n async sessionCommand<T = unknown>(\n targetId: string,\n method: string,\n params: JsonObject = {},\n ): Promise<T> {\n if (!this.socket) throw new Error(\"CDP not connected\");\n const sessionId =\n this.sessions.get(targetId) ?? (await this.attachAndEnable(targetId));\n const id = this.nextId++;\n const payload = JSON.stringify({ id, method, params, sessionId });\n return new Promise<T>((resolve, reject) => {\n const check = (raw: WebSocket.RawData) => {\n const msg = JSON.parse(raw.toString()) as JsonObject;\n if (msg.id === id && msg.sessionId === sessionId) {\n this.socket!.off(\"message\", check);\n if (msg.error) {\n reject(\n new Error(\n `${method}: ${(msg.error as JsonObject).message ?? \"Unknown CDP error\"}`,\n ),\n );\n } else {\n resolve(msg.result as T);\n }\n }\n };\n this.socket!.on(\"message\", check);\n this.socket!.send(payload);\n });\n }\n\n /**\n * Send a page-scoped command. If the tab has an active iframe,\n * the frameId is injected into the params.\n */\n async pageCommand<T = unknown>(\n targetId: string,\n method: string,\n params: JsonObject = {},\n ): Promise<T> {\n const tab = this.tabManager.getTab(targetId);\n const frameId = tab?.activeFrameId;\n return this.sessionCommand<T>(\n targetId,\n method,\n frameId ? { ...params, frameId } : params,\n );\n }\n\n /**\n * Evaluate JavaScript expression on a target.\n */\n async evaluate<T>(\n targetId: string,\n expression: string,\n returnByValue = true,\n ): Promise<T> {\n const result = await this.sessionCommand<{\n result: { type?: string; value?: T; objectId?: string };\n exceptionDetails?: { text?: string; exception?: { description?: string } };\n }>(targetId, \"Runtime.evaluate\", {\n expression,\n awaitPromise: true,\n returnByValue,\n });\n if (result.exceptionDetails) {\n throw new Error(\n result.exceptionDetails.exception?.description ||\n result.exceptionDetails.text ||\n \"Runtime.evaluate failed\",\n );\n }\n return (result.result.value ?? result.result) as T;\n }\n}\n","/**\n * RingBuffer — fixed-capacity circular buffer for bounded event storage.\n *\n * When the buffer is full, the oldest entries are silently discarded.\n * Supports iteration and filtering while keeping memory usage constant.\n */\nexport class RingBuffer<T> {\n private readonly items: (T | undefined)[];\n private head = 0; // next write position\n private count = 0;\n readonly capacity: number;\n\n constructor(capacity: number) {\n if (capacity < 1) throw new Error(\"RingBuffer capacity must be >= 1\");\n this.capacity = capacity;\n this.items = new Array<T | undefined>(capacity);\n }\n\n /** Number of elements currently stored. */\n get size(): number {\n return this.count;\n }\n\n /** Push a new element, evicting the oldest if at capacity. */\n push(item: T): void {\n this.items[this.head] = item;\n this.head = (this.head + 1) % this.capacity;\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /** Return all stored elements in insertion order (oldest first). */\n toArray(): T[] {\n if (this.count === 0) return [];\n const result: T[] = new Array(this.count);\n const start = this.count < this.capacity ? 0 : this.head;\n for (let i = 0; i < this.count; i++) {\n result[i] = this.items[(start + i) % this.capacity] as T;\n }\n return result;\n }\n\n /** Remove all elements. */\n clear(): void {\n this.items.fill(undefined);\n this.head = 0;\n this.count = 0;\n }\n}\n","/**\n * TabState — per-tab event state with global seq counter.\n *\n * Each tab maintains its own ring-buffered event collections:\n * - networkRequests (max 500)\n * - consoleMessages (max 200)\n * - jsErrors (max 100)\n *\n * A global monotonic `seq` counter is shared across all events and\n * operations. Each event or action increments seq so that callers can\n * use the `since` mechanism for incremental queries.\n */\n\nimport type {\n NetworkRequestInfo,\n ConsoleMessageInfo,\n JSErrorInfo,\n RefInfo,\n} from \"@bb-browser/shared\";\nimport { RingBuffer } from \"./ring-buffer.js\";\n\n// ---------------------------------------------------------------------------\n// Seq-tagged event wrappers\n// ---------------------------------------------------------------------------\n\nexport type SeqNetworkRequest = NetworkRequestInfo & { seq: number };\nexport type SeqConsoleMessage = ConsoleMessageInfo & { seq: number };\nexport type SeqJSError = JSErrorInfo & { seq: number };\n\n// ---------------------------------------------------------------------------\n// Per-tab state\n// ---------------------------------------------------------------------------\n\nconst NETWORK_CAPACITY = 500;\nconst CONSOLE_CAPACITY = 200;\nconst ERRORS_CAPACITY = 100;\n\nexport class TabState {\n readonly targetId: string;\n shortId: string;\n\n networkRequests = new RingBuffer<SeqNetworkRequest>(NETWORK_CAPACITY);\n consoleMessages = new RingBuffer<SeqConsoleMessage>(CONSOLE_CAPACITY);\n jsErrors = new RingBuffer<SeqJSError>(ERRORS_CAPACITY);\n\n /** Lookup in-flight network requests by requestId for response/failure updates. */\n private networkByRequestId = new Map<string, SeqNetworkRequest>();\n\n /** seq of the last user-initiated action on this tab. */\n lastActionSeq = 0;\n\n /** Element refs from the most recent snapshot. */\n refs: Record<string, RefInfo> = {};\n\n /** Active frame ID for iframe navigation, null = main frame. */\n activeFrameId: string | null = null;\n\n /** Dialog auto-handler config. */\n dialogHandler: { accept: boolean; promptText?: string } | null = null;\n\n constructor(\n targetId: string,\n shortId: string,\n private readonly nextSeq: () => number,\n ) {\n this.targetId = targetId;\n this.shortId = shortId;\n }\n\n // --------------- Action seq ---------------\n\n /** Increment global seq and record it as this tab's last action. */\n recordAction(): number {\n const seq = this.nextSeq();\n this.lastActionSeq = seq;\n return seq;\n }\n\n // --------------- Network events ---------------\n\n addNetworkRequest(requestId: string, info: Omit<NetworkRequestInfo, \"requestId\">): void {\n const seq = this.nextSeq();\n const entry: SeqNetworkRequest = { ...info, requestId, seq };\n this.networkRequests.push(entry);\n this.networkByRequestId.set(requestId, entry);\n }\n\n updateNetworkResponse(\n requestId: string,\n data: {\n status?: number;\n statusText?: string;\n responseHeaders?: Record<string, string>;\n mimeType?: string;\n },\n ): void {\n const existing = this.networkByRequestId.get(requestId);\n if (!existing) return;\n if (data.status !== undefined) existing.status = data.status;\n if (data.statusText !== undefined) existing.statusText = data.statusText;\n if (data.responseHeaders !== undefined) existing.responseHeaders = data.responseHeaders;\n if (data.mimeType !== undefined) existing.mimeType = data.mimeType;\n }\n\n updateNetworkFailure(requestId: string, reason: string): void {\n const existing = this.networkByRequestId.get(requestId);\n if (!existing) return;\n existing.failed = true;\n existing.failureReason = reason;\n }\n\n // --------------- Console events ---------------\n\n addConsoleMessage(info: Omit<ConsoleMessageInfo, never>): void {\n const seq = this.nextSeq();\n this.consoleMessages.push({ ...info, seq });\n }\n\n // --------------- JS Error events ---------------\n\n addJSError(info: Omit<JSErrorInfo, never>): void {\n const seq = this.nextSeq();\n this.jsErrors.push({ ...info, seq });\n }\n\n // --------------- Query helpers ---------------\n\n getNetworkRequests(options?: {\n since?: number | \"last_action\";\n filter?: string;\n method?: string;\n status?: string;\n limit?: number;\n }): { items: SeqNetworkRequest[]; cursor: number } {\n let items = this.networkRequests.toArray();\n\n // since\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n // filter (URL substring)\n if (options?.filter) {\n const f = options.filter;\n items = items.filter((item) => item.url.includes(f));\n }\n\n // method\n if (options?.method) {\n const m = options.method.toUpperCase();\n items = items.filter((item) => item.method === m);\n }\n\n // status\n if (options?.status) {\n const s = options.status;\n if (s === \"4xx\") {\n items = items.filter((item) => item.status !== undefined && item.status >= 400 && item.status < 500);\n } else if (s === \"5xx\") {\n items = items.filter((item) => item.status !== undefined && item.status >= 500 && item.status < 600);\n } else {\n const code = Number(s);\n if (!Number.isNaN(code)) {\n items = items.filter((item) => item.status === code);\n }\n }\n }\n\n // limit\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n getConsoleMessages(options?: {\n since?: number | \"last_action\";\n filter?: string;\n limit?: number;\n }): { items: SeqConsoleMessage[]; cursor: number } {\n let items = this.consoleMessages.toArray();\n\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n if (options?.filter) {\n const f = options.filter;\n items = items.filter((item) => item.text.includes(f));\n }\n\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n getJSErrors(options?: {\n since?: number | \"last_action\";\n filter?: string;\n limit?: number;\n }): { items: SeqJSError[]; cursor: number } {\n let items = this.jsErrors.toArray();\n\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n if (options?.filter) {\n const f = options.filter;\n items = items.filter(\n (item) => item.message.includes(f) || (item.url?.includes(f) ?? false),\n );\n }\n\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n // --------------- Clear helpers ---------------\n\n clearNetwork(): void {\n this.networkRequests.clear();\n this.networkByRequestId.clear();\n }\n\n clearConsole(): void {\n this.consoleMessages.clear();\n }\n\n clearErrors(): void {\n this.jsErrors.clear();\n }\n}\n\n// ---------------------------------------------------------------------------\n// TabStateManager — manages all tabs + global seq\n// ---------------------------------------------------------------------------\n\nexport class TabStateManager {\n private seq = 0;\n private tabs = new Map<string, TabState>(); // targetId -> TabState\n private shortToTarget = new Map<string, string>(); // shortId -> targetId\n private targetToShort = new Map<string, string>(); // targetId -> shortId\n\n /** Generate a globally unique short ID for a target. */\n private generateShortId(targetId: string): string {\n for (let len = 4; len <= targetId.length; len++) {\n const candidate = targetId.slice(-len).toLowerCase();\n if (!this.shortToTarget.has(candidate)) {\n return candidate;\n }\n }\n // Extremely unlikely fallback\n return targetId.toLowerCase();\n }\n\n /** Get next seq (globally monotonic). */\n nextSeq(): number {\n return ++this.seq;\n }\n\n /** Get current seq without incrementing. */\n currentSeq(): number {\n return this.seq;\n }\n\n /** Register a new tab. Returns the TabState. */\n addTab(targetId: string): TabState {\n const existing = this.tabs.get(targetId);\n if (existing) return existing;\n\n const shortId = this.generateShortId(targetId);\n const tab = new TabState(targetId, shortId, () => this.nextSeq());\n this.tabs.set(targetId, tab);\n this.shortToTarget.set(shortId, targetId);\n this.targetToShort.set(targetId, shortId);\n return tab;\n }\n\n /** Remove a tab (on targetDestroyed / detach). */\n removeTab(targetId: string): void {\n const tab = this.tabs.get(targetId);\n if (!tab) return;\n this.shortToTarget.delete(tab.shortId);\n this.targetToShort.delete(targetId);\n this.tabs.delete(targetId);\n }\n\n /** Get tab by targetId. */\n getTab(targetId: string): TabState | undefined {\n return this.tabs.get(targetId);\n }\n\n /** Resolve a short ID to a targetId. */\n resolveShortId(shortId: string): string | undefined {\n return this.shortToTarget.get(shortId);\n }\n\n /** Get the short ID for a targetId. */\n getShortId(targetId: string): string | undefined {\n return this.targetToShort.get(targetId);\n }\n\n /** Get all active tabs. */\n allTabs(): TabState[] {\n return Array.from(this.tabs.values());\n }\n\n /** Get tab count. */\n get tabCount(): number {\n return this.tabs.size;\n }\n}\n"],"mappings":"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","names":["readFileSync","path","call","path","readFileSync"]}
1
+ {"version":3,"sources":["../packages/daemon/src/index.ts","../packages/daemon/src/http-server.ts","../packages/daemon/src/command-dispatch.ts","../packages/daemon/src/cdp-connection.ts","../packages/daemon/src/ring-buffer.ts","../packages/daemon/src/tab-state.ts"],"sourcesContent":["/**\n * bb-browser Daemon — CDP-direct backend\n *\n * Unified daemon that handles ALL browser commands (operations + observation)\n * via direct Chrome DevTools Protocol connection.\n *\n * Two-phase startup:\n * 1. HTTP server starts immediately (commands queue until CDP is ready)\n * 2. CDP connection established asynchronously\n */\n\nimport { parseArgs } from \"node:util\";\nimport { writeFileSync, unlinkSync, existsSync, readFileSync } from \"node:fs\";\nimport { mkdirSync } from \"node:fs\";\nimport { randomBytes } from \"node:crypto\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { DAEMON_PORT, DAEMON_HOST } from \"@bb-browser/shared\";\nimport { HttpServer } from \"./http-server.js\";\nimport { CdpConnection } from \"./cdp-connection.js\";\nimport { TabStateManager } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DAEMON_DIR = process.env.BB_BROWSER_HOME || path.join(os.homedir(), \".bb-browser\");\nconst DAEMON_JSON = path.join(DAEMON_DIR, \"daemon.json\");\nconst DEFAULT_CDP_PORT = 19825;\n\n// ---------------------------------------------------------------------------\n// CLI argument parsing\n// ---------------------------------------------------------------------------\n\ninterface DaemonOptions {\n host: string;\n port: number;\n cdpHost: string;\n cdpPort: number;\n token: string;\n}\n\nfunction parseOptions(): DaemonOptions {\n const { values } = parseArgs({\n allowPositionals: true,\n options: {\n host: {\n type: \"string\",\n short: \"H\",\n default: DAEMON_HOST,\n },\n port: {\n type: \"string\",\n short: \"p\",\n default: String(DAEMON_PORT),\n },\n \"cdp-host\": {\n type: \"string\",\n default: \"127.0.0.1\",\n },\n \"cdp-port\": {\n type: \"string\",\n default: String(DEFAULT_CDP_PORT),\n },\n token: {\n type: \"string\",\n default: \"\",\n },\n help: {\n type: \"boolean\",\n short: \"h\",\n default: false,\n },\n },\n });\n\n if (values.help) {\n console.error(`\nbb-browser-daemon — CDP-direct backend for bb-browser\n\nUsage:\n bb-browser-daemon [options]\n\nOptions:\n -H, --host <host> HTTP server host (default: ${DAEMON_HOST})\n -p, --port <port> HTTP server port (default: ${DAEMON_PORT})\n --cdp-host <host> Chrome CDP host (default: 127.0.0.1)\n --cdp-port <port> Chrome CDP port (default: ${DEFAULT_CDP_PORT})\n --token <token> Bearer auth token (auto-generated if empty)\n -h, --help Show this help message\n\nEndpoints:\n POST /command Send command and get result (via CDP)\n GET /status Daemon health + per-tab stats\n POST /shutdown Graceful shutdown\n`);\n process.exit(0);\n }\n\n // Auto-generate token if not provided\n let token = values.token ?? \"\";\n if (!token) {\n token = randomBytes(16).toString(\"hex\");\n }\n\n return {\n host: values.host ?? DAEMON_HOST,\n port: parseInt(values.port ?? String(DAEMON_PORT), 10),\n cdpHost: values[\"cdp-host\"] ?? \"127.0.0.1\",\n cdpPort: parseInt(values[\"cdp-port\"] ?? String(DEFAULT_CDP_PORT), 10),\n token,\n };\n}\n\n// ---------------------------------------------------------------------------\n// daemon.json management\n// ---------------------------------------------------------------------------\n\ninterface DaemonInfo {\n pid: number;\n host: string;\n port: number;\n token: string;\n}\n\nfunction writeDaemonJson(info: DaemonInfo): void {\n try {\n mkdirSync(DAEMON_DIR, { recursive: true });\n writeFileSync(DAEMON_JSON, JSON.stringify(info), { mode: 0o600 });\n } catch {}\n}\n\nfunction cleanupDaemonJson(): void {\n if (existsSync(DAEMON_JSON)) {\n try {\n unlinkSync(DAEMON_JSON);\n } catch {}\n }\n}\n\n// ---------------------------------------------------------------------------\n// CDP port discovery (simplified — daemon is told the port)\n// ---------------------------------------------------------------------------\n\nasync function discoverCdpPort(host: string, port: number): Promise<{ host: string; port: number }> {\n // Try connecting to the specified port first\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n try {\n const response = await fetch(`http://${host}:${port}/json/version`, {\n signal: controller.signal,\n });\n if (response.ok) {\n return { host, port };\n }\n } finally {\n clearTimeout(timer);\n }\n } catch {}\n\n // Try reading managed browser port file\n const managedPortFile = path.join(DAEMON_DIR, \"browser\", \"cdp-port\");\n try {\n const rawPort = readFileSync(managedPortFile, \"utf8\").trim();\n const managedPort = parseInt(rawPort, 10);\n if (Number.isInteger(managedPort) && managedPort > 0) {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n try {\n const response = await fetch(`http://127.0.0.1:${managedPort}/json/version`, {\n signal: controller.signal,\n });\n if (response.ok) {\n return { host: \"127.0.0.1\", port: managedPort };\n }\n } finally {\n clearTimeout(timer);\n }\n } catch {}\n }\n } catch {}\n\n throw new Error(\n `Cannot connect to Chrome CDP at ${host}:${port}. ` +\n `Make sure Chrome is running with --remote-debugging-port=${port}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nasync function main(): Promise<void> {\n const options = parseOptions();\n\n // Create tab state manager and CDP connection\n const tabManager = new TabStateManager();\n let cdpEndpoint: { host: string; port: number };\n\n try {\n cdpEndpoint = await discoverCdpPort(options.cdpHost, options.cdpPort);\n } catch (error) {\n console.error(\n `[Daemon] ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n\n const cdp = new CdpConnection(cdpEndpoint.host, cdpEndpoint.port, tabManager);\n\n // Graceful shutdown handler (guarded against double-call)\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.error(\"[Daemon] Shutting down...\");\n cdp.disconnect();\n await httpServer.stop();\n cleanupDaemonJson();\n process.exit(0);\n };\n\n // Phase 1: Start HTTP server immediately\n const httpServer = new HttpServer({\n host: options.host,\n port: options.port,\n token: options.token,\n cdp,\n onShutdown: shutdown,\n });\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n await httpServer.start();\n writeDaemonJson({\n pid: process.pid,\n host: options.host,\n port: options.port,\n token: options.token,\n });\n\n console.error(\n `[Daemon] HTTP server listening on http://${options.host}:${options.port}`,\n );\n console.error(`[Daemon] Auth token: ${options.token}`);\n\n // Phase 2: Connect to CDP asynchronously\n console.error(\n `[Daemon] Connecting to Chrome CDP at ${cdpEndpoint.host}:${cdpEndpoint.port}...`,\n );\n\n try {\n await cdp.connect();\n const tabCount = tabManager.tabCount;\n console.error(\n `[Daemon] CDP connected, monitoring ${tabCount} tab(s)`,\n );\n } catch (error) {\n console.error(\n `[Daemon] Failed to connect to CDP: ${error instanceof Error ? error.message : String(error)}`,\n );\n console.error(\"[Daemon] HTTP server is running, but commands will fail until CDP connects.\");\n }\n}\n\nmain().catch((error) => {\n console.error(\"[Daemon] Fatal error:\", error);\n cleanupDaemonJson();\n process.exit(1);\n});\n","/**\n * HTTP Server for the CDP-direct daemon.\n *\n * Endpoints:\n * POST /command — receive Request, dispatch via CDP, return Response\n * GET /status — daemon health + per-tab stats\n * POST /shutdown — graceful shutdown\n *\n * Bearer token authentication (optional, but enforced when token is set).\n * Two-phase startup: HTTP server starts immediately, CDP connects async.\n * Commands received before CDP is ready queue and wait.\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { Request } from \"@bb-browser/shared\";\nimport { COMMAND_TIMEOUT, DAEMON_PORT } from \"@bb-browser/shared\";\nimport { CdpConnection } from \"./cdp-connection.js\";\nimport { dispatchRequest } from \"./command-dispatch.js\";\n\nexport interface HttpServerOptions {\n host?: string;\n port?: number;\n token?: string;\n cdp: CdpConnection;\n onShutdown?: () => void;\n}\n\nexport class HttpServer {\n private server: Server | null = null;\n private readonly host: string;\n private readonly port: number;\n private readonly token: string | null;\n private readonly cdp: CdpConnection;\n private readonly onShutdown?: () => void;\n private startTime = 0;\n\n constructor(options: HttpServerOptions) {\n this.host = options.host ?? \"127.0.0.1\";\n this.port = options.port ?? DAEMON_PORT;\n this.token = options.token ?? null;\n this.cdp = options.cdp;\n this.onShutdown = options.onShutdown;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res);\n });\n\n this.server.on(\"error\", reject);\n\n this.server.listen(this.port, this.host, () => {\n this.startTime = Date.now();\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n if (this.server) {\n return new Promise((resolve) => {\n this.server!.close(() => resolve());\n });\n }\n }\n\n get uptime(): number {\n if (this.startTime === 0) return 0;\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n // ---------------------------------------------------------------------------\n // Auth\n // ---------------------------------------------------------------------------\n\n private checkAuth(req: IncomingMessage, res: ServerResponse): boolean {\n if (!this.token) return true;\n const auth = req.headers.authorization ?? \"\";\n if (auth === `Bearer ${this.token}`) return true;\n this.sendJson(res, 401, { error: \"Unauthorized\" });\n return false;\n }\n\n // ---------------------------------------------------------------------------\n // Routing\n // ---------------------------------------------------------------------------\n\n private handleRequest(req: IncomingMessage, res: ServerResponse): void {\n // CORS\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (!this.checkAuth(req, res)) return;\n\n const url = req.url ?? \"/\";\n\n if (req.method === \"POST\" && url === \"/command\") {\n this.handleCommand(req, res);\n } else if (req.method === \"GET\" && url === \"/status\") {\n this.handleStatus(req, res);\n } else if (req.method === \"POST\" && url === \"/shutdown\") {\n this.handleShutdown(req, res);\n } else {\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n }\n\n // ---------------------------------------------------------------------------\n // POST /command\n // ---------------------------------------------------------------------------\n\n private async handleCommand(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n const body = await this.readBody(req);\n const request = JSON.parse(body) as Request;\n\n // Wait for CDP to be ready (two-phase startup)\n if (!this.cdp.connected) {\n try {\n await Promise.race([\n this.cdp.waitUntilReady(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"CDP connection timeout\")), COMMAND_TIMEOUT),\n ),\n ]);\n } catch {\n const cdpTarget = `${this.cdp.host}:${this.cdp.port}`;\n const reason = this.cdp.lastError || \"unknown\";\n this.sendJson(res, 503, {\n id: request.id,\n success: false,\n error: `Chrome not connected (CDP at ${cdpTarget})`,\n reason,\n hint: \"Make sure Chrome is running. Try: bb-browser daemon shutdown && bb-browser tab list\",\n });\n return;\n }\n }\n\n // Dispatch with timeout\n const timeout = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"Command timeout\")), COMMAND_TIMEOUT),\n );\n const response = await Promise.race([\n dispatchRequest(this.cdp, request),\n timeout,\n ]);\n this.sendJson(res, 200, response);\n } catch (error) {\n this.sendJson(res, 400, {\n success: false,\n error: error instanceof Error ? error.message : \"Invalid request\",\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // GET /status\n // ---------------------------------------------------------------------------\n\n private handleStatus(_req: IncomingMessage, res: ServerResponse): void {\n const tabs = this.cdp.tabManager.allTabs().map((tab) => ({\n shortId: tab.shortId,\n targetId: tab.targetId,\n networkRequests: tab.networkRequests.size,\n consoleMessages: tab.consoleMessages.size,\n jsErrors: tab.jsErrors.size,\n lastActionSeq: tab.lastActionSeq,\n }));\n\n this.sendJson(res, 200, {\n running: true,\n cdpConnected: this.cdp.connected,\n uptime: this.uptime,\n currentSeq: this.cdp.tabManager.currentSeq(),\n currentTargetId: this.cdp.currentTargetId,\n tabs,\n });\n }\n\n // ---------------------------------------------------------------------------\n // POST /shutdown\n // ---------------------------------------------------------------------------\n\n private handleShutdown(_req: IncomingMessage, res: ServerResponse): void {\n this.sendJson(res, 200, { code: 0, message: \"Shutting down\" });\n\n setTimeout(() => {\n if (this.onShutdown) {\n this.onShutdown();\n }\n }, 100);\n }\n\n // ---------------------------------------------------------------------------\n // Utility\n // ---------------------------------------------------------------------------\n\n private readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n req.on(\"error\", reject);\n });\n }\n\n private sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n });\n res.end(body);\n }\n}\n","/**\n * Command dispatch — handles all browser commands via CDP.\n *\n * Ported from cli/cdp-client.ts dispatchRequest, adapted to use\n * CdpConnection + TabStateManager for per-tab state and seq tracking.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type {\n Request,\n Response,\n ResponseData,\n RefInfo,\n SnapshotData,\n TraceEvent,\n TraceStatus,\n} from \"@bb-browser/shared\";\nimport { CdpConnection, type CdpTargetInfo } from \"./cdp-connection.js\";\nimport type { TabState } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface RawDomTextNode {\n type: \"TEXT_NODE\";\n text: string;\n isVisible: boolean;\n}\n\ninterface RawDomElementNode {\n tagName: string;\n xpath: string | null;\n attributes: Record<string, string>;\n children: string[];\n isVisible?: boolean;\n isInteractive?: boolean;\n isTopElement?: boolean;\n isInViewport?: boolean;\n highlightIndex?: number;\n shadowRoot?: boolean;\n}\n\ntype RawDomTreeNode = RawDomTextNode | RawDomElementNode;\n\ninterface BuildDomTreeResult {\n rootId: string;\n map: Record<string, RawDomTreeNode>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildRequestError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/**\n * Extended response data with daemon-specific fields.\n * Relaxes frameInfo.frameId to accept string (CDP uses string frame IDs).\n */\ntype ExtResponseData = Omit<ResponseData, \"tabs\" | \"frameInfo\"> & {\n tabs?: Array<Record<string, unknown>>;\n frameInfo?: {\n selector?: string;\n name?: string;\n url?: string;\n frameId?: string | number;\n };\n};\n\nfunction ok(id: string, data?: ExtResponseData): Response {\n return { id, success: true, data: data as ResponseData };\n}\n\nfunction fail(id: string, error: unknown): Response {\n return { id, success: false, error: buildRequestError(error).message };\n}\n\n// ---------------------------------------------------------------------------\n// buildDomTree script loading\n// ---------------------------------------------------------------------------\n\nlet cachedBuildDomTreeScript: string | null = null;\n\nfunction loadBuildDomTreeScript(): string {\n if (cachedBuildDomTreeScript) return cachedBuildDomTreeScript;\n\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n // Built dist: dist/daemon.js → ../packages/shared/buildDomTree.js\n path.resolve(currentDir, \"../packages/shared/buildDomTree.js\"),\n // Dev mode: packages/daemon/src/ → ../../shared/buildDomTree.js\n path.resolve(currentDir, \"../../shared/buildDomTree.js\"),\n // npm installed: dist/daemon.js → same level\n path.resolve(currentDir, \"./buildDomTree.js\"),\n path.resolve(currentDir, \"../buildDomTree.js\"),\n ];\n for (const candidate of candidates) {\n try {\n cachedBuildDomTreeScript = readFileSync(candidate, \"utf8\");\n return cachedBuildDomTreeScript;\n } catch {}\n }\n throw new Error(\"Cannot find buildDomTree.js\");\n}\n\n// ---------------------------------------------------------------------------\n// Snapshot building\n// ---------------------------------------------------------------------------\n\nfunction convertBuildDomTreeResult(\n result: BuildDomTreeResult,\n options: { interactiveOnly: boolean; compact: boolean; maxDepth?: number; selector?: string },\n): SnapshotData {\n const { interactiveOnly, compact, maxDepth, selector } = options;\n const { rootId, map } = result;\n const refs: Record<string, RefInfo> = {};\n const lines: string[] = [];\n\n const getRole = (node: RawDomElementNode): string => {\n const tagName = node.tagName.toLowerCase();\n const role = node.attributes?.role;\n if (role) return role;\n const type = node.attributes?.type?.toLowerCase() || \"text\";\n const inputRoleMap: Record<string, string> = {\n text: \"textbox\", password: \"textbox\", email: \"textbox\", url: \"textbox\", tel: \"textbox\",\n search: \"searchbox\", number: \"spinbutton\", range: \"slider\", checkbox: \"checkbox\",\n radio: \"radio\", button: \"button\", submit: \"button\", reset: \"button\", file: \"button\",\n };\n const roleMap: Record<string, string> = {\n a: \"link\", button: \"button\", input: inputRoleMap[type] || \"textbox\", select: \"combobox\",\n textarea: \"textbox\", img: \"image\", nav: \"navigation\", main: \"main\", header: \"banner\",\n footer: \"contentinfo\", aside: \"complementary\", form: \"form\", table: \"table\", ul: \"list\",\n ol: \"list\", li: \"listitem\", h1: \"heading\", h2: \"heading\", h3: \"heading\", h4: \"heading\",\n h5: \"heading\", h6: \"heading\", dialog: \"dialog\", article: \"article\", section: \"region\",\n label: \"label\", details: \"group\", summary: \"button\",\n };\n return roleMap[tagName] || tagName;\n };\n\n const collectTextContent = (node: RawDomElementNode, nodeMap: Record<string, RawDomTreeNode>, depthLimit = 5): string => {\n const texts: string[] = [];\n const visit = (nodeId: string, depth: number): void => {\n if (depth > depthLimit) return;\n const currentNode = nodeMap[nodeId];\n if (!currentNode) return;\n if (\"type\" in currentNode && currentNode.type === \"TEXT_NODE\") {\n const text = currentNode.text.trim();\n if (text) texts.push(text);\n return;\n }\n for (const childId of (currentNode as RawDomElementNode).children || []) visit(childId, depth + 1);\n };\n for (const childId of node.children || []) visit(childId, 0);\n return texts.join(\" \").trim();\n };\n\n const getName = (node: RawDomElementNode): string | undefined => {\n const attrs = node.attributes || {};\n return attrs[\"aria-label\"] || attrs.title || attrs.placeholder || attrs.alt || attrs.value || collectTextContent(node, map) || attrs.name || undefined;\n };\n\n const truncateText = (text: string, length = 50): string =>\n text.length <= length ? text : `${text.slice(0, length - 3)}...`;\n\n const selectorText = selector?.trim().toLowerCase();\n const matchesSelector = (node: RawDomElementNode, role: string, name?: string): boolean => {\n if (!selectorText) return true;\n const haystack = [node.tagName, role, name, node.xpath || \"\", ...Object.values(node.attributes || {})].join(\" \").toLowerCase();\n return haystack.includes(selectorText);\n };\n\n if (interactiveOnly) {\n const interactiveNodes = Object.entries(map)\n .filter(([, node]) => !(\"type\" in node) && node.highlightIndex !== undefined && node.highlightIndex !== null)\n .map(([id, node]) => ({ id, node: node as RawDomElementNode }))\n .sort((a, b) => (a.node.highlightIndex ?? 0) - (b.node.highlightIndex ?? 0));\n\n for (const { node } of interactiveNodes) {\n const refId = String(node.highlightIndex);\n const role = getRole(node);\n const name = getName(node);\n if (!matchesSelector(node, role, name)) continue;\n let line = `${role} [ref=${refId}]`;\n if (name) line += ` ${JSON.stringify(truncateText(name))}`;\n lines.push(line);\n refs[refId] = { xpath: node.xpath || \"\", role, name, tagName: node.tagName.toLowerCase() } as RefInfo;\n }\n return { snapshot: lines.join(\"\\n\"), refs };\n }\n\n const walk = (nodeId: string, depth: number): void => {\n if (maxDepth !== undefined && depth > maxDepth) return;\n const node = map[nodeId];\n if (!node) return;\n\n if (\"type\" in node && node.type === \"TEXT_NODE\") {\n const text = node.text.trim();\n if (!text) return;\n lines.push(`${\" \".repeat(depth)}- text ${JSON.stringify(truncateText(text, compact ? 80 : 120))}`);\n return;\n }\n\n const el = node as RawDomElementNode;\n const role = getRole(el);\n const name = getName(el);\n if (!matchesSelector(el, role, name)) {\n for (const childId of el.children || []) walk(childId, depth + 1);\n return;\n }\n\n const indent = \" \".repeat(depth);\n const refId = el.highlightIndex !== undefined && el.highlightIndex !== null ? String(el.highlightIndex) : null;\n let line = `${indent}- ${role}`;\n if (refId) line += ` [ref=${refId}]`;\n if (name) line += ` ${JSON.stringify(truncateText(name, compact ? 50 : 80))}`;\n if (!compact) line += ` <${el.tagName.toLowerCase()}>`;\n lines.push(line);\n\n if (refId) {\n refs[refId] = { xpath: el.xpath || \"\", role, name, tagName: el.tagName.toLowerCase() } as RefInfo;\n }\n\n for (const childId of el.children || []) walk(childId, depth + 1);\n };\n\n walk(rootId, 0);\n return { snapshot: lines.join(\"\\n\"), refs };\n}\n\nasync function buildSnapshot(\n cdp: CdpConnection,\n targetId: string,\n tab: TabState,\n request: Request,\n): Promise<SnapshotData> {\n const script = loadBuildDomTreeScript();\n const buildArgs = {\n showHighlightElements: true,\n focusHighlightIndex: -1,\n viewportExpansion: -1,\n debugMode: false,\n startId: 0,\n startHighlightIndex: 0,\n };\n const expression = `(() => { ${script}; const fn = globalThis.buildDomTree ?? (typeof window !== 'undefined' ? window.buildDomTree : undefined); if (typeof fn !== 'function') { throw new Error('buildDomTree is not available after script injection'); } return fn(${JSON.stringify(buildArgs)}); })()`;\n const value = await cdp.evaluate<BuildDomTreeResult | null>(targetId, expression, true);\n\n if (!value || !value.map || !value.rootId) {\n const title = await cdp.evaluate<string>(targetId, \"document.title\", true);\n const pageUrl = await cdp.evaluate<string>(targetId, \"location.href\", true);\n tab.refs = {};\n return { snapshot: title || pageUrl, refs: {} };\n }\n\n const snapshot = convertBuildDomTreeResult(value, {\n interactiveOnly: !!request.interactive,\n compact: !!request.compact,\n maxDepth: request.maxDepth,\n selector: request.selector,\n });\n tab.refs = snapshot.refs || {};\n return snapshot;\n}\n\n// ---------------------------------------------------------------------------\n// Ref resolution\n// ---------------------------------------------------------------------------\n\nasync function resolveBackendNodeIdByXPath(\n cdp: CdpConnection,\n targetId: string,\n xpath: string,\n): Promise<number> {\n await cdp.sessionCommand(targetId, \"DOM.getDocument\", { depth: 0 });\n const search = await cdp.sessionCommand<{ searchId: string; resultCount: number }>(\n targetId,\n \"DOM.performSearch\",\n { query: xpath, includeUserAgentShadowDOM: true },\n );\n\n try {\n if (!search.resultCount) {\n throw new Error(`Unknown ref xpath: ${xpath}`);\n }\n const { nodeIds } = await cdp.sessionCommand<{ nodeIds: number[] }>(\n targetId,\n \"DOM.getSearchResults\",\n { searchId: search.searchId, fromIndex: 0, toIndex: search.resultCount },\n );\n\n for (const nodeId of nodeIds) {\n const described = await cdp.sessionCommand<{\n node: { backendNodeId?: number };\n }>(targetId, \"DOM.describeNode\", { nodeId });\n if (described.node.backendNodeId) {\n return described.node.backendNodeId;\n }\n }\n throw new Error(`XPath resolved but no backend node id found: ${xpath}`);\n } finally {\n await cdp.sessionCommand(targetId, \"DOM.discardSearchResults\", { searchId: search.searchId }).catch(() => {});\n }\n}\n\nasync function parseRef(cdp: CdpConnection, targetId: string, tab: TabState, ref: string): Promise<number> {\n const found = tab.refs[ref];\n if (!found) {\n throw new Error(`Unknown ref: ${ref}. Run snapshot first.`);\n }\n if (found.backendDOMNodeId) {\n return found.backendDOMNodeId;\n }\n if (found.xpath) {\n const backendDOMNodeId = await resolveBackendNodeIdByXPath(cdp, targetId, found.xpath);\n found.backendDOMNodeId = backendDOMNodeId;\n return backendDOMNodeId;\n }\n throw new Error(`Unknown ref: ${ref}. Run snapshot first.`);\n}\n\n// ---------------------------------------------------------------------------\n// Input helpers\n// ---------------------------------------------------------------------------\n\nasync function getInteractablePoint(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n): Promise<{ x: number; y: number }> {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{\n result: { value?: { x?: number; y?: number } };\n exceptionDetails?: { text?: string };\n }>(targetId, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() {\n if (!(this instanceof Element)) {\n throw new Error('Ref does not resolve to an element');\n }\n this.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' });\n const rect = this.getBoundingClientRect();\n if (!rect || rect.width <= 0 || rect.height <= 0) {\n throw new Error('Element is not visible');\n }\n return {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n }`,\n returnByValue: true,\n });\n\n if (call.exceptionDetails) {\n throw new Error(call.exceptionDetails.text || \"Failed to resolve element point\");\n }\n\n const point = call.result.value;\n if (\n !point ||\n typeof point.x !== \"number\" ||\n typeof point.y !== \"number\" ||\n !Number.isFinite(point.x) ||\n !Number.isFinite(point.y)\n ) {\n throw new Error(\"Failed to resolve element point\");\n }\n return point as { x: number; y: number };\n}\n\nasync function mouseClick(cdp: CdpConnection, targetId: string, x: number, y: number): Promise<void> {\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mouseMoved\", x, y, button: \"none\",\n });\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mousePressed\", x, y, button: \"left\", clickCount: 1,\n });\n await cdp.sessionCommand(targetId, \"Input.dispatchMouseEvent\", {\n type: \"mouseReleased\", x, y, button: \"left\", clickCount: 1,\n });\n}\n\nasync function insertTextIntoNode(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n text: string,\n clearFirst: boolean,\n): Promise<void> {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n\n await cdp.sessionCommand(targetId, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function(clearFirst) {\n if (typeof this.scrollIntoView === 'function') {\n this.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'center' });\n }\n if (typeof this.focus === 'function') this.focus();\n if (this instanceof HTMLInputElement || this instanceof HTMLTextAreaElement) {\n if (clearFirst) {\n this.value = '';\n this.dispatchEvent(new Event('input', { bubbles: true }));\n }\n if (typeof this.setSelectionRange === 'function') {\n const end = this.value.length;\n this.setSelectionRange(end, end);\n }\n return true;\n }\n if (this instanceof HTMLElement && this.isContentEditable) {\n if (clearFirst) {\n this.textContent = '';\n this.dispatchEvent(new Event('input', { bubbles: true }));\n }\n const selection = window.getSelection();\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(this);\n range.collapse(false);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n return true;\n }\n return false;\n }`,\n arguments: [{ value: clearFirst }],\n returnByValue: true,\n });\n\n if (text) {\n await cdp.sessionCommand(targetId, \"DOM.focus\", { backendNodeId });\n await cdp.sessionCommand(targetId, \"Input.insertText\", { text });\n }\n}\n\nasync function getAttributeValue(\n cdp: CdpConnection,\n targetId: string,\n backendNodeId: number,\n attribute: string,\n): Promise<string> {\n if (attribute === \"text\") {\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{ result: { value: string } }>(\n targetId,\n \"Runtime.callFunctionOn\",\n {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { return (this instanceof HTMLElement ? this.innerText : this.textContent || '').trim(); }`,\n returnByValue: true,\n },\n );\n return String(call.result.value ?? \"\");\n }\n const result = await cdp.sessionCommand<{ object: { objectId: string } }>(\n targetId,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n const call = await cdp.sessionCommand<{ result: { value: string } }>(\n targetId,\n \"Runtime.callFunctionOn\",\n {\n objectId: result.object.objectId,\n functionDeclaration: `function() { if (${JSON.stringify(attribute)} === 'url') return this.href || this.src || location.href; if (${JSON.stringify(attribute)} === 'title') return document.title; return this.getAttribute(${JSON.stringify(attribute)}) || ''; }`,\n returnByValue: true,\n },\n );\n return String(call.result.value ?? \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Trace state (global, not per-tab — matches original behavior)\n// ---------------------------------------------------------------------------\n\nlet traceRecording = false;\nconst traceEvents: TraceEvent[] = [];\n\n// ---------------------------------------------------------------------------\n// Main dispatch\n// ---------------------------------------------------------------------------\n\n/**\n * Dispatch a command request. This is the core function that handles all\n * browser automation commands via CDP.\n */\nexport async function dispatchRequest(\n cdp: CdpConnection,\n request: Request,\n): Promise<Response> {\n // Resolve target from request.tabId (supports short IDs)\n const tabRef = request.tabId;\n\n // tab_new must work even when there are no existing tabs,\n // so handle it before ensurePageTarget().\n if (request.action === \"tab_new\") {\n const url = request.url ?? \"about:blank\";\n const created = await cdp.browserCommand<{ targetId: string }>(\n \"Target.createTarget\",\n { url, background: true },\n );\n await cdp.attachAndEnable(created.targetId);\n const newTab = cdp.tabManager.getTab(created.targetId);\n return ok(request.id, {\n tabId: created.targetId,\n url,\n tab: newTab?.shortId ?? created.targetId.slice(-4).toLowerCase(),\n seq: newTab?.recordAction(),\n });\n }\n\n const target = await cdp.ensurePageTarget(\n tabRef !== undefined ? String(tabRef) : undefined,\n );\n const tab = cdp.tabManager.getTab(target.id);\n if (!tab) throw new Error(\"Internal error: tab state not found\");\n\n const shortId = tab.shortId;\n\n switch (request.action) {\n // -----------------------------------------------------------------------\n // Navigation\n // -----------------------------------------------------------------------\n case \"open\": {\n if (!request.url) return fail(request.id, \"Missing url parameter\");\n const seq = tab.recordAction();\n if (tabRef === undefined) {\n // No specific tab requested — open in new tab\n const created = await cdp.browserCommand<{ targetId: string }>(\n \"Target.createTarget\",\n { url: request.url, background: true },\n );\n const newTarget = await cdp.ensurePageTarget(created.targetId);\n const newTab = cdp.tabManager.getTab(newTarget.id);\n return ok(request.id, {\n url: request.url,\n tabId: newTarget.id,\n tab: newTab?.shortId ?? shortId,\n seq,\n });\n }\n await cdp.pageCommand(target.id, \"Page.navigate\", { url: request.url });\n tab.refs = {};\n return ok(request.id, {\n url: request.url,\n title: target.title,\n tabId: target.id,\n tab: shortId,\n seq,\n });\n }\n\n case \"back\": {\n const seq = tab.recordAction();\n await cdp.evaluate(target.id, \"history.back(); undefined\");\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"forward\": {\n const seq = tab.recordAction();\n await cdp.evaluate(target.id, \"history.forward(); undefined\");\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"refresh\": {\n const seq = tab.recordAction();\n await cdp.sessionCommand(target.id, \"Page.reload\", { ignoreCache: false });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"close\": {\n const seq = tab.recordAction();\n await cdp.browserCommand(\"Target.closeTarget\", { targetId: target.id });\n tab.refs = {};\n return ok(request.id, { tab: shortId, seq });\n }\n\n // -----------------------------------------------------------------------\n // Snapshot / observation\n // -----------------------------------------------------------------------\n case \"snapshot\": {\n const snapshotData = await buildSnapshot(cdp, target.id, tab, request);\n return ok(request.id, {\n title: target.title,\n url: target.url,\n snapshotData,\n tab: shortId,\n });\n }\n\n case \"screenshot\": {\n const result = await cdp.sessionCommand<{ data: string }>(\n target.id,\n \"Page.captureScreenshot\",\n { format: \"png\", fromSurface: true },\n );\n return ok(request.id, {\n dataUrl: `data:image/png;base64,${result.data}`,\n tab: shortId,\n });\n }\n\n // -----------------------------------------------------------------------\n // Element interaction\n // -----------------------------------------------------------------------\n case \"click\":\n case \"hover\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const point = await getInteractablePoint(cdp, target.id, backendNodeId);\n await cdp.sessionCommand(target.id, \"Input.dispatchMouseEvent\", {\n type: \"mouseMoved\", x: point.x, y: point.y, button: \"none\",\n });\n if (request.action === \"click\") {\n await mouseClick(cdp, target.id, point.x, point.y);\n }\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"fill\":\n case \"type\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n if (request.text == null) return fail(request.id, \"Missing text parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n await insertTextIntoNode(cdp, target.id, backendNodeId, request.text, request.action === \"fill\");\n return ok(request.id, {\n value: request.text,\n tab: shortId,\n seq,\n });\n }\n\n case \"check\":\n case \"uncheck\": {\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const seq = tab.recordAction();\n const desired = request.action === \"check\";\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n target.id,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n await cdp.sessionCommand(target.id, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { this.checked = ${desired}; this.dispatchEvent(new Event('input', { bubbles: true })); this.dispatchEvent(new Event('change', { bubbles: true })); }`,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"select\": {\n if (!request.ref || request.value == null) return fail(request.id, \"Missing ref or value parameter\");\n const seq = tab.recordAction();\n const backendNodeId = await parseRef(cdp, target.id, tab, request.ref);\n const resolved = await cdp.sessionCommand<{ object: { objectId: string } }>(\n target.id,\n \"DOM.resolveNode\",\n { backendNodeId },\n );\n await cdp.sessionCommand(target.id, \"Runtime.callFunctionOn\", {\n objectId: resolved.object.objectId,\n functionDeclaration: `function() { this.value = ${JSON.stringify(request.value)}; this.dispatchEvent(new Event('input', { bubbles: true })); this.dispatchEvent(new Event('change', { bubbles: true })); }`,\n });\n return ok(request.id, {\n value: request.value,\n tab: shortId,\n seq,\n });\n }\n\n case \"get\": {\n if (!request.attribute) return fail(request.id, \"Missing attribute parameter\");\n if (request.attribute === \"url\" && !request.ref) {\n return ok(request.id, {\n value: await cdp.evaluate<string>(target.id, \"location.href\", true),\n tab: shortId,\n });\n }\n if (request.attribute === \"title\" && !request.ref) {\n return ok(request.id, {\n value: await cdp.evaluate<string>(target.id, \"document.title\", true),\n tab: shortId,\n });\n }\n if (!request.ref) return fail(request.id, \"Missing ref parameter\");\n const value = await getAttributeValue(\n cdp,\n target.id,\n await parseRef(cdp, target.id, tab, request.ref),\n request.attribute,\n );\n return ok(request.id, { value, tab: shortId });\n }\n\n case \"press\": {\n if (!request.key) return fail(request.id, \"Missing key parameter\");\n const seq = tab.recordAction();\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"keyDown\", key: request.key,\n });\n if (request.key.length === 1) {\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"char\", text: request.key, key: request.key,\n });\n }\n await cdp.sessionCommand(target.id, \"Input.dispatchKeyEvent\", {\n type: \"keyUp\", key: request.key,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"scroll\": {\n const seq = tab.recordAction();\n const deltaY = request.direction === \"up\"\n ? -(request.pixels ?? 300)\n : (request.pixels ?? 300);\n await cdp.sessionCommand(target.id, \"Input.dispatchMouseEvent\", {\n type: \"mouseWheel\", x: 0, y: 0, deltaX: 0, deltaY,\n });\n return ok(request.id, { tab: shortId, seq });\n }\n\n case \"wait\": {\n await new Promise((resolve) => setTimeout(resolve, request.ms ?? 1000));\n return ok(request.id, { tab: shortId });\n }\n\n case \"eval\": {\n if (!request.script) return fail(request.id, \"Missing script parameter\");\n const seq = tab.recordAction();\n const result = await cdp.evaluate<unknown>(target.id, request.script, true);\n return ok(request.id, {\n result,\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Tab management\n // -----------------------------------------------------------------------\n case \"tab_list\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n const tabs = targets.map((t, index) => {\n const tState = cdp.tabManager.getTab(t.id);\n return {\n index,\n url: t.url,\n title: t.title,\n active: t.id === cdp.currentTargetId || (!cdp.currentTargetId && index === 0),\n tabId: t.id,\n tab: tState?.shortId ?? t.id.slice(-4).toLowerCase(),\n };\n });\n return ok(request.id, {\n tabs,\n activeIndex: tabs.findIndex((t) => t.active),\n });\n }\n\n // tab_new is handled before ensurePageTarget() above\n\n case \"tab_select\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n let selected: CdpTargetInfo | undefined;\n\n if (request.tabId !== undefined) {\n const tabIdStr = String(request.tabId);\n // Try short ID\n const resolvedId = cdp.tabManager.resolveShortId(tabIdStr);\n if (resolvedId) {\n selected = targets.find((t) => t.id === resolvedId);\n }\n // Try full target ID\n if (!selected) {\n selected = targets.find((t) => t.id === tabIdStr);\n }\n // Try numeric index\n if (!selected) {\n const num = Number(tabIdStr);\n if (!Number.isNaN(num)) {\n selected = targets[num];\n }\n }\n } else {\n selected = targets[request.index ?? 0];\n }\n\n if (!selected) return fail(request.id, \"Tab not found\");\n cdp.currentTargetId = selected.id;\n await cdp.attachAndEnable(selected.id);\n const selTab = cdp.tabManager.getTab(selected.id);\n return ok(request.id, {\n tabId: selected.id,\n url: selected.url,\n title: selected.title,\n tab: selTab?.shortId,\n });\n }\n\n case \"tab_close\": {\n const targets = (await cdp.getTargets()).filter((t) => t.type === \"page\");\n let selected: CdpTargetInfo | undefined;\n\n if (request.tabId !== undefined) {\n const tabIdStr = String(request.tabId);\n const resolvedId = cdp.tabManager.resolveShortId(tabIdStr);\n if (resolvedId) {\n selected = targets.find((t) => t.id === resolvedId);\n }\n if (!selected) {\n selected = targets.find((t) => t.id === tabIdStr);\n }\n if (!selected) {\n const num = Number(tabIdStr);\n if (!Number.isNaN(num)) {\n selected = targets[num];\n }\n }\n } else {\n selected = targets[request.index ?? 0];\n }\n\n if (!selected) return fail(request.id, \"Tab not found\");\n const closedTab = cdp.tabManager.getTab(selected.id);\n const closedShort = closedTab?.shortId;\n await cdp.browserCommand(\"Target.closeTarget\", { targetId: selected.id });\n if (cdp.currentTargetId === selected.id) {\n cdp.currentTargetId = undefined;\n }\n return ok(request.id, {\n tabId: selected.id,\n tab: closedShort,\n });\n }\n\n // -----------------------------------------------------------------------\n // Frame navigation\n // -----------------------------------------------------------------------\n case \"frame\": {\n if (!request.selector) return fail(request.id, \"Missing selector parameter\");\n const seq = tab.recordAction();\n const document = await cdp.pageCommand<{ root: { nodeId: number } }>(\n target.id,\n \"DOM.getDocument\",\n {},\n );\n const node = await cdp.pageCommand<{ nodeId: number }>(\n target.id,\n \"DOM.querySelector\",\n { nodeId: document.root.nodeId, selector: request.selector },\n );\n if (!node.nodeId) return fail(request.id, `iframe not found: ${request.selector}`);\n const described = await cdp.pageCommand<{\n node: { frameId?: string; nodeName?: string; attributes?: string[] };\n }>(target.id, \"DOM.describeNode\", { nodeId: node.nodeId });\n const frameId = described.node.frameId;\n const nodeName = String(described.node.nodeName ?? \"\").toLowerCase();\n if (!frameId) return fail(request.id, `Cannot get iframe frameId: ${request.selector}`);\n if (nodeName && nodeName !== \"iframe\" && nodeName !== \"frame\") {\n return fail(request.id, `Element is not an iframe: ${nodeName}`);\n }\n tab.activeFrameId = frameId;\n const attributes = described.node.attributes ?? [];\n const attrMap: Record<string, string> = {};\n for (let i = 0; i < attributes.length; i += 2) {\n attrMap[String(attributes[i])] = String(attributes[i + 1] ?? \"\");\n }\n return ok(request.id, {\n frameInfo: {\n selector: request.selector,\n name: attrMap.name ?? \"\",\n url: attrMap.src ?? \"\",\n frameId,\n },\n tab: shortId,\n seq,\n });\n }\n\n case \"frame_main\": {\n const seq = tab.recordAction();\n tab.activeFrameId = null;\n return ok(request.id, {\n frameInfo: { frameId: 0 },\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Dialog\n // -----------------------------------------------------------------------\n case \"dialog\": {\n const seq = tab.recordAction();\n tab.dialogHandler = {\n accept: request.dialogResponse !== \"dismiss\",\n ...(request.promptText !== undefined ? { promptText: request.promptText } : {}),\n };\n await cdp.sessionCommand(target.id, \"Page.enable\");\n return ok(request.id, {\n dialogInfo: {\n type: \"armed\",\n message: `Dialog handler armed: ${request.dialogResponse ?? \"accept\"}`,\n handled: false,\n },\n tab: shortId,\n seq,\n });\n }\n\n // -----------------------------------------------------------------------\n // Network observation\n // -----------------------------------------------------------------------\n case \"network\": {\n const subCommand = request.networkCommand ?? \"requests\";\n switch (subCommand) {\n case \"requests\": {\n const queryResult = tab.getNetworkRequests({\n since: request.since,\n filter: request.filter,\n method: request.method,\n status: request.status,\n limit: request.limit,\n });\n\n const items = queryResult.items;\n // Fetch response bodies if requested\n if (request.withBody) {\n await Promise.all(\n items.map(async (item) => {\n if (item.failed || item.responseBody !== undefined || item.bodyError !== undefined) return;\n try {\n const body = await cdp.sessionCommand<{ body: string; base64Encoded: boolean }>(\n target.id,\n \"Network.getResponseBody\",\n { requestId: item.requestId },\n );\n item.responseBody = body.body;\n item.responseBodyBase64 = body.base64Encoded;\n } catch (error) {\n item.bodyError = error instanceof Error ? error.message : String(error);\n }\n }),\n );\n }\n\n return ok(request.id, {\n networkRequests: items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"route\":\n return ok(request.id, { routeCount: 0, tab: shortId });\n case \"unroute\":\n return ok(request.id, { routeCount: 0, tab: shortId });\n case \"clear\":\n tab.clearNetwork();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown network subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // Console observation\n // -----------------------------------------------------------------------\n case \"console\": {\n const subCommand = request.consoleCommand ?? \"get\";\n switch (subCommand) {\n case \"get\": {\n const queryResult = tab.getConsoleMessages({\n since: request.since,\n filter: request.filter,\n limit: request.limit,\n });\n return ok(request.id, {\n consoleMessages: queryResult.items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"clear\":\n tab.clearConsole();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown console subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // JS Errors observation\n // -----------------------------------------------------------------------\n case \"errors\": {\n const subCommand = request.errorsCommand ?? \"get\";\n switch (subCommand) {\n case \"get\": {\n const queryResult = tab.getJSErrors({\n since: request.since,\n filter: request.filter,\n limit: request.limit,\n });\n return ok(request.id, {\n jsErrors: queryResult.items,\n tab: shortId,\n cursor: queryResult.cursor,\n });\n }\n case \"clear\":\n tab.clearErrors();\n return ok(request.id, { tab: shortId });\n default:\n return fail(request.id, `Unknown errors subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // Trace\n // -----------------------------------------------------------------------\n case \"trace\": {\n const subCommand = request.traceCommand ?? \"status\";\n switch (subCommand) {\n case \"start\":\n traceRecording = true;\n traceEvents.length = 0;\n return ok(request.id, {\n traceStatus: { recording: true, eventCount: 0 } satisfies TraceStatus,\n tab: shortId,\n });\n case \"stop\": {\n traceRecording = false;\n return ok(request.id, {\n traceEvents: [...traceEvents],\n traceStatus: { recording: false, eventCount: traceEvents.length } satisfies TraceStatus,\n tab: shortId,\n });\n }\n case \"status\":\n return ok(request.id, {\n traceStatus: { recording: traceRecording, eventCount: traceEvents.length } satisfies TraceStatus,\n tab: shortId,\n });\n default:\n return fail(request.id, `Unknown trace subcommand: ${subCommand}`);\n }\n }\n\n // -----------------------------------------------------------------------\n // History (not implemented in daemon yet)\n // -----------------------------------------------------------------------\n case \"history\": {\n return fail(request.id, \"History command is not supported in daemon mode\");\n }\n\n default:\n return fail(request.id, `Unknown action: ${request.action}`);\n }\n}\n","/**\n * CdpConnection — manages the browser-level WebSocket to Chrome DevTools\n * Protocol. Handles target discovery, auto-attach, session multiplexing,\n * and routes per-target session events to the TabStateManager.\n *\n * Merged from cli/cdp-client.ts (connection management) and\n * cli/cdp-monitor.ts (persistent connection + event listening).\n */\n\nimport { request as httpRequest } from \"node:http\";\nimport WebSocket from \"ws\";\nimport { TabStateManager } from \"./tab-state.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype JsonObject = Record<string, unknown>;\n\ninterface PendingCommand {\n resolve: (value: unknown) => void;\n reject: (reason?: unknown) => void;\n method: string;\n}\n\nexport interface CdpTargetInfo {\n id: string;\n type: string;\n title: string;\n url: string;\n}\n\n// ---------------------------------------------------------------------------\n// CDP helpers\n// ---------------------------------------------------------------------------\n\nfunction fetchJson(url: string): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const req = httpRequest(url, { method: \"GET\" }, (res) => {\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk: Buffer) => chunks.push(Buffer.from(chunk)));\n res.on(\"end\", () => {\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n if ((res.statusCode ?? 500) >= 400) {\n reject(new Error(`HTTP ${res.statusCode ?? 500}: ${raw}`));\n return;\n }\n try {\n resolve(JSON.parse(raw));\n } catch (error) {\n reject(error);\n }\n });\n });\n req.on(\"error\", reject);\n req.end();\n });\n}\n\nfunction connectWebSocket(url: string): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url);\n ws.once(\"open\", () => resolve(ws));\n ws.once(\"error\", reject);\n });\n}\n\nfunction normalizeHeaders(headers: unknown): Record<string, string> | undefined {\n if (!headers || typeof headers !== \"object\") return undefined;\n return Object.fromEntries(\n Object.entries(headers as Record<string, unknown>).map(([key, value]) => [key, String(value)]),\n );\n}\n\n// ---------------------------------------------------------------------------\n// CdpConnection\n// ---------------------------------------------------------------------------\n\nexport class CdpConnection {\n private socket: WebSocket | null = null;\n private pending = new Map<number, PendingCommand>();\n private nextId = 1;\n\n /** targetId -> sessionId (flat-mode) */\n private sessions = new Map<string, string>();\n /** sessionId -> targetId */\n private attachedTargets = new Map<string, string>();\n\n readonly host: string;\n readonly port: number;\n readonly tabManager: TabStateManager;\n\n /** Current (most recently selected) target ID. */\n currentTargetId: string | undefined;\n\n private connectionPromise: Promise<void> | null = null;\n private _connected = false;\n\n /** Last connection error (for diagnostics in 503 responses). */\n lastError: string | null = null;\n\n /** Resolvers for commands queued before CDP is ready. */\n private readyWaiters: Array<{ resolve: () => void; reject: (err: Error) => void }> = [];\n\n constructor(host: string, port: number, tabManager: TabStateManager) {\n this.host = host;\n this.port = port;\n this.tabManager = tabManager;\n }\n\n get connected(): boolean {\n return this._connected && this.socket !== null && this.socket.readyState === WebSocket.OPEN;\n }\n\n // ---------------------------------------------------------------------------\n // Connection lifecycle\n // ---------------------------------------------------------------------------\n\n /**\n * Connect to Chrome's browser-level WebSocket endpoint.\n * Idempotent — returns immediately if already connected.\n */\n async connect(): Promise<void> {\n if (this._connected) return;\n if (this.connectionPromise) return this.connectionPromise;\n\n this.connectionPromise = this.doConnect();\n try {\n await this.connectionPromise;\n this.lastError = null;\n } catch (err) {\n this.lastError = err instanceof Error ? err.message : String(err);\n const connErr = new Error(this.lastError);\n for (const waiter of this.readyWaiters) {\n waiter.reject(connErr);\n }\n this.readyWaiters = [];\n throw err;\n } finally {\n this.connectionPromise = null;\n }\n }\n\n private async doConnect(): Promise<void> {\n const versionData = (await fetchJson(\n `http://${this.host}:${this.port}/json/version`,\n )) as JsonObject;\n const wsUrl = versionData.webSocketDebuggerUrl;\n if (typeof wsUrl !== \"string\" || !wsUrl) {\n throw new Error(\"CDP endpoint missing webSocketDebuggerUrl\");\n }\n\n const ws = await connectWebSocket(wsUrl);\n this.socket = ws;\n this._connected = true;\n this.setupListeners(ws);\n\n // Discover + auto-attach existing page targets\n await this.browserCommand(\"Target.setDiscoverTargets\", { discover: true });\n const result = await this.browserCommand<{\n targetInfos: Array<{ targetId: string; type: string; title: string; url: string }>;\n }>(\"Target.getTargets\");\n\n const pages = (result.targetInfos || []).filter((t) => t.type === \"page\");\n for (const page of pages) {\n await this.attachAndEnable(page.targetId).catch(() => {});\n }\n\n // Notify any waiters that CDP is ready\n for (const waiter of this.readyWaiters) {\n waiter.resolve();\n }\n this.readyWaiters = [];\n }\n\n /** Wait until CDP connection is established (for two-phase startup). */\n waitUntilReady(): Promise<void> {\n if (this._connected) return Promise.resolve();\n if (this.lastError) return Promise.reject(new Error(this.lastError));\n return new Promise<void>((resolve, reject) => {\n this.readyWaiters.push({ resolve, reject });\n });\n }\n\n /** Gracefully close the CDP connection. */\n disconnect(): void {\n if (this.socket) {\n try {\n this.socket.close();\n } catch {}\n }\n this.socket = null;\n this._connected = false;\n\n for (const p of this.pending.values()) {\n p.reject(new Error(\"CDP connection closed\"));\n }\n this.pending.clear();\n\n // Reject any waiters\n for (const waiter of this.readyWaiters) {\n waiter.reject(new Error(\"CDP connection closed before ready\"));\n }\n this.readyWaiters = [];\n }\n\n // ---------------------------------------------------------------------------\n // WebSocket message handling\n // ---------------------------------------------------------------------------\n\n private setupListeners(ws: WebSocket): void {\n ws.on(\"message\", (raw) => {\n const message = JSON.parse(raw.toString()) as JsonObject;\n\n // Response to a browser-level command\n if (typeof message.id === \"number\") {\n const p = this.pending.get(message.id);\n if (!p) return;\n this.pending.delete(message.id);\n if (message.error) {\n p.reject(\n new Error(\n `${p.method}: ${(message.error as JsonObject).message ?? \"Unknown CDP error\"}`,\n ),\n );\n } else {\n p.resolve(message.result);\n }\n return;\n }\n\n // Flat-mode attach\n if (message.method === \"Target.attachedToTarget\") {\n const params = message.params as JsonObject;\n const sessionId = params.sessionId;\n const targetInfo = params.targetInfo as JsonObject;\n if (typeof sessionId === \"string\" && typeof targetInfo?.targetId === \"string\") {\n this.sessions.set(targetInfo.targetId, sessionId);\n this.attachedTargets.set(sessionId, targetInfo.targetId);\n }\n return;\n }\n\n if (message.method === \"Target.detachedFromTarget\") {\n const params = message.params as JsonObject;\n const sessionId = params.sessionId;\n if (typeof sessionId === \"string\") {\n const targetId = this.attachedTargets.get(sessionId);\n if (targetId) {\n this.sessions.delete(targetId);\n this.attachedTargets.delete(sessionId);\n this.tabManager.removeTab(targetId);\n if (this.currentTargetId === targetId) {\n this.currentTargetId = undefined;\n }\n }\n }\n return;\n }\n\n // New target auto-attach\n if (message.method === \"Target.targetCreated\") {\n const params = message.params as JsonObject;\n const targetInfo = params.targetInfo as JsonObject;\n if (targetInfo?.type === \"page\" && typeof targetInfo.targetId === \"string\") {\n this.attachAndEnable(targetInfo.targetId).catch(() => {});\n }\n return;\n }\n\n if (message.method === \"Target.targetDestroyed\") {\n const params = message.params as JsonObject;\n const targetId = params.targetId;\n if (typeof targetId === \"string\") {\n const sessionId = this.sessions.get(targetId);\n if (sessionId) {\n this.sessions.delete(targetId);\n this.attachedTargets.delete(sessionId);\n }\n this.tabManager.removeTab(targetId);\n if (this.currentTargetId === targetId) {\n this.currentTargetId = undefined;\n }\n }\n return;\n }\n\n // Flat protocol: session events carry sessionId directly\n if (typeof message.sessionId === \"string\" && typeof message.method === \"string\") {\n const targetId = this.attachedTargets.get(message.sessionId as string);\n if (targetId) {\n this.handleSessionEvent(targetId, message).catch(() => {});\n }\n }\n });\n\n ws.on(\"close\", () => {\n this._connected = false;\n this.socket = null;\n this.lastError = \"CDP WebSocket closed unexpectedly\";\n for (const p of this.pending.values()) {\n p.reject(new Error(\"CDP connection closed\"));\n }\n this.pending.clear();\n\n const closeErr = new Error(this.lastError);\n for (const waiter of this.readyWaiters) {\n waiter.reject(closeErr);\n }\n this.readyWaiters = [];\n });\n\n ws.on(\"error\", () => {});\n }\n\n // ---------------------------------------------------------------------------\n // Session event routing (network, console, errors, dialog)\n // ---------------------------------------------------------------------------\n\n private async handleSessionEvent(targetId: string, event: JsonObject): Promise<void> {\n const method = event.method;\n const params = (event.params ?? {}) as JsonObject;\n if (typeof method !== \"string\") return;\n\n const tab = this.tabManager.getTab(targetId);\n if (!tab) return;\n\n // Dialog handling\n if (method === \"Page.javascriptDialogOpening\") {\n if (tab.dialogHandler) {\n await this.sessionCommand(targetId, \"Page.handleJavaScriptDialog\", {\n accept: tab.dialogHandler.accept,\n ...(tab.dialogHandler.promptText !== undefined\n ? { promptText: tab.dialogHandler.promptText }\n : {}),\n });\n }\n return;\n }\n\n // Network events\n if (method === \"Network.requestWillBeSent\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n const request = params.request as JsonObject | undefined;\n if (!requestId || !request) return;\n tab.addNetworkRequest(requestId, {\n url: String(request.url ?? \"\"),\n method: String(request.method ?? \"GET\"),\n type: String(params.type ?? \"Other\"),\n timestamp: Math.round(Number(params.timestamp ?? Date.now()) * 1000),\n requestHeaders: normalizeHeaders(request.headers),\n requestBody: typeof request.postData === \"string\" ? request.postData : undefined,\n });\n return;\n }\n\n if (method === \"Network.responseReceived\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n const response = params.response as JsonObject | undefined;\n if (!requestId || !response) return;\n tab.updateNetworkResponse(requestId, {\n status: typeof response.status === \"number\" ? response.status : undefined,\n statusText: typeof response.statusText === \"string\" ? response.statusText : undefined,\n responseHeaders: normalizeHeaders(response.headers),\n mimeType: typeof response.mimeType === \"string\" ? response.mimeType : undefined,\n });\n return;\n }\n\n if (method === \"Network.loadingFailed\") {\n const requestId = typeof params.requestId === \"string\" ? params.requestId : undefined;\n if (!requestId) return;\n tab.updateNetworkFailure(\n requestId,\n typeof params.errorText === \"string\" ? params.errorText : \"Unknown error\",\n );\n return;\n }\n\n // Console events\n if (method === \"Runtime.consoleAPICalled\") {\n const type = String(params.type ?? \"log\");\n const args = Array.isArray(params.args) ? (params.args as JsonObject[]) : [];\n const text = args\n .map((arg) => {\n if (typeof arg.value === \"string\") return arg.value;\n if (arg.value !== undefined) return String(arg.value);\n if (typeof arg.description === \"string\") return arg.description;\n return \"\";\n })\n .filter(Boolean)\n .join(\" \");\n const stack = params.stackTrace as JsonObject | undefined;\n const firstCallFrame = Array.isArray(stack?.callFrames)\n ? (stack?.callFrames[0] as JsonObject | undefined)\n : undefined;\n // Chrome CDP sends \"warning\" for console.warn(); normalize it\n const consoleTypeMap: Record<string, string> = { warning: \"warn\" };\n const normalizedType = consoleTypeMap[type] || type;\n tab.addConsoleMessage({\n type: [\"log\", \"info\", \"warn\", \"error\", \"debug\"].includes(normalizedType)\n ? (normalizedType as \"log\" | \"info\" | \"warn\" | \"error\" | \"debug\")\n : \"log\",\n text,\n timestamp: Math.round(Number(params.timestamp ?? Date.now())),\n url:\n typeof firstCallFrame?.url === \"string\" ? firstCallFrame.url : undefined,\n lineNumber:\n typeof firstCallFrame?.lineNumber === \"number\"\n ? firstCallFrame.lineNumber\n : undefined,\n });\n return;\n }\n\n // JS Error events\n if (method === \"Runtime.exceptionThrown\") {\n const details = params.exceptionDetails as JsonObject | undefined;\n if (!details) return;\n const exception = details.exception as JsonObject | undefined;\n const stackTrace = details.stackTrace as JsonObject | undefined;\n const callFrames = Array.isArray(stackTrace?.callFrames)\n ? (stackTrace.callFrames as JsonObject[])\n : [];\n tab.addJSError({\n message:\n typeof exception?.description === \"string\"\n ? exception.description\n : String(details.text ?? \"JavaScript exception\"),\n url:\n typeof details.url === \"string\"\n ? details.url\n : typeof callFrames[0]?.url === \"string\"\n ? String(callFrames[0].url)\n : undefined,\n lineNumber:\n typeof details.lineNumber === \"number\" ? details.lineNumber : undefined,\n columnNumber:\n typeof details.columnNumber === \"number\" ? details.columnNumber : undefined,\n stackTrace:\n callFrames.length > 0\n ? callFrames\n .map(\n (frame) =>\n `${String(frame.functionName ?? \"<anonymous>\")} (${String(frame.url ?? \"\")}:${String(frame.lineNumber ?? 0)}:${String(frame.columnNumber ?? 0)})`,\n )\n .join(\"\\n\")\n : undefined,\n timestamp: Date.now(),\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // Target management\n // ---------------------------------------------------------------------------\n\n /** Attach to a target and enable required CDP domains. */\n async attachAndEnable(targetId: string): Promise<string> {\n if (this.sessions.has(targetId)) {\n // Already attached — register tab state if not present\n this.tabManager.addTab(targetId);\n return this.sessions.get(targetId)!;\n }\n\n const result = await this.browserCommand<{ sessionId: string }>(\n \"Target.attachToTarget\",\n { targetId, flatten: true },\n );\n this.sessions.set(targetId, result.sessionId);\n this.attachedTargets.set(result.sessionId, targetId);\n\n // Register in tab state manager\n this.tabManager.addTab(targetId);\n\n // Enable domains\n await this.sessionCommand(targetId, \"Page.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Runtime.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Network.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"DOM.enable\").catch(() => {});\n await this.sessionCommand(targetId, \"Accessibility.enable\").catch(() => {});\n\n return result.sessionId;\n }\n\n /** Get all targets via CDP Target.getTargets. */\n async getTargets(): Promise<CdpTargetInfo[]> {\n const result = await this.browserCommand<{\n targetInfos: Array<{\n targetId: string;\n type: string;\n title: string;\n url: string;\n }>;\n }>(\"Target.getTargets\");\n\n return (result.targetInfos || []).map((t) => ({\n id: t.targetId,\n type: t.type,\n title: t.title,\n url: t.url,\n }));\n }\n\n /**\n * Ensure we have a valid page target and return it. Supports resolution by:\n * - short ID string\n * - full target ID string\n * - numeric index\n * - undefined (use currentTargetId or first page)\n */\n async ensurePageTarget(tabRef?: string | number): Promise<CdpTargetInfo> {\n const targets = (await this.getTargets()).filter((t) => t.type === \"page\");\n if (targets.length === 0) throw new Error(\"No page target found\");\n\n let target: CdpTargetInfo | undefined;\n\n if (typeof tabRef === \"string\") {\n // Try short ID first\n const resolvedTargetId = this.tabManager.resolveShortId(tabRef);\n if (resolvedTargetId) {\n target = targets.find((t) => t.id === resolvedTargetId);\n }\n // Then try full target ID\n if (!target) {\n target = targets.find((t) => t.id === tabRef);\n }\n // Then try as numeric index\n if (!target) {\n const num = Number(tabRef);\n if (!Number.isNaN(num)) {\n target = targets[num];\n }\n }\n } else if (typeof tabRef === \"number\") {\n target = targets[tabRef];\n } else if (this.currentTargetId) {\n target = targets.find((t) => t.id === this.currentTargetId);\n }\n\n if (typeof tabRef === \"string\" && !target) {\n throw new Error(`Tab not found: ${tabRef}`);\n }\n\n target ??= targets[0];\n this.currentTargetId = target.id;\n await this.attachAndEnable(target.id);\n return target;\n }\n\n /** Check if a session exists for a given targetId. */\n hasSession(targetId: string): boolean {\n return this.sessions.has(targetId);\n }\n\n // ---------------------------------------------------------------------------\n // CDP command sending\n // ---------------------------------------------------------------------------\n\n /** Send a browser-level CDP command. */\n async browserCommand<T = unknown>(method: string, params: JsonObject = {}): Promise<T> {\n if (!this.socket) throw new Error(\"CDP not connected\");\n const id = this.nextId++;\n const payload = JSON.stringify({ id, method, params });\n return new Promise<T>((resolve, reject) => {\n this.pending.set(id, {\n resolve: resolve as (v: unknown) => void,\n reject,\n method,\n });\n this.socket!.send(payload);\n });\n }\n\n /** Send a session-level CDP command (flat protocol). */\n async sessionCommand<T = unknown>(\n targetId: string,\n method: string,\n params: JsonObject = {},\n ): Promise<T> {\n if (!this.socket) throw new Error(\"CDP not connected\");\n const sessionId =\n this.sessions.get(targetId) ?? (await this.attachAndEnable(targetId));\n const id = this.nextId++;\n const payload = JSON.stringify({ id, method, params, sessionId });\n return new Promise<T>((resolve, reject) => {\n const check = (raw: WebSocket.RawData) => {\n const msg = JSON.parse(raw.toString()) as JsonObject;\n if (msg.id === id && msg.sessionId === sessionId) {\n this.socket!.off(\"message\", check);\n if (msg.error) {\n reject(\n new Error(\n `${method}: ${(msg.error as JsonObject).message ?? \"Unknown CDP error\"}`,\n ),\n );\n } else {\n resolve(msg.result as T);\n }\n }\n };\n this.socket!.on(\"message\", check);\n this.socket!.send(payload);\n });\n }\n\n /**\n * Send a page-scoped command. If the tab has an active iframe,\n * the frameId is injected into the params.\n */\n async pageCommand<T = unknown>(\n targetId: string,\n method: string,\n params: JsonObject = {},\n ): Promise<T> {\n const tab = this.tabManager.getTab(targetId);\n const frameId = tab?.activeFrameId;\n return this.sessionCommand<T>(\n targetId,\n method,\n frameId ? { ...params, frameId } : params,\n );\n }\n\n /**\n * Evaluate JavaScript expression on a target.\n */\n async evaluate<T>(\n targetId: string,\n expression: string,\n returnByValue = true,\n ): Promise<T> {\n const result = await this.sessionCommand<{\n result: { type?: string; value?: T; objectId?: string };\n exceptionDetails?: { text?: string; exception?: { description?: string } };\n }>(targetId, \"Runtime.evaluate\", {\n expression,\n awaitPromise: true,\n returnByValue,\n });\n if (result.exceptionDetails) {\n throw new Error(\n result.exceptionDetails.exception?.description ||\n result.exceptionDetails.text ||\n \"Runtime.evaluate failed\",\n );\n }\n return (result.result.value ?? result.result) as T;\n }\n}\n","/**\n * RingBuffer — fixed-capacity circular buffer for bounded event storage.\n *\n * When the buffer is full, the oldest entries are silently discarded.\n * Supports iteration and filtering while keeping memory usage constant.\n */\nexport class RingBuffer<T> {\n private readonly items: (T | undefined)[];\n private head = 0; // next write position\n private count = 0;\n readonly capacity: number;\n\n constructor(capacity: number) {\n if (capacity < 1) throw new Error(\"RingBuffer capacity must be >= 1\");\n this.capacity = capacity;\n this.items = new Array<T | undefined>(capacity);\n }\n\n /** Number of elements currently stored. */\n get size(): number {\n return this.count;\n }\n\n /** Push a new element, evicting the oldest if at capacity. */\n push(item: T): void {\n this.items[this.head] = item;\n this.head = (this.head + 1) % this.capacity;\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /** Return all stored elements in insertion order (oldest first). */\n toArray(): T[] {\n if (this.count === 0) return [];\n const result: T[] = new Array(this.count);\n const start = this.count < this.capacity ? 0 : this.head;\n for (let i = 0; i < this.count; i++) {\n result[i] = this.items[(start + i) % this.capacity] as T;\n }\n return result;\n }\n\n /** Remove all elements. */\n clear(): void {\n this.items.fill(undefined);\n this.head = 0;\n this.count = 0;\n }\n}\n","/**\n * TabState — per-tab event state with global seq counter.\n *\n * Each tab maintains its own ring-buffered event collections:\n * - networkRequests (max 500)\n * - consoleMessages (max 200)\n * - jsErrors (max 100)\n *\n * A global monotonic `seq` counter is shared across all events and\n * operations. Each event or action increments seq so that callers can\n * use the `since` mechanism for incremental queries.\n */\n\nimport type {\n NetworkRequestInfo,\n ConsoleMessageInfo,\n JSErrorInfo,\n RefInfo,\n} from \"@bb-browser/shared\";\nimport { RingBuffer } from \"./ring-buffer.js\";\n\n// ---------------------------------------------------------------------------\n// Seq-tagged event wrappers\n// ---------------------------------------------------------------------------\n\nexport type SeqNetworkRequest = NetworkRequestInfo & { seq: number };\nexport type SeqConsoleMessage = ConsoleMessageInfo & { seq: number };\nexport type SeqJSError = JSErrorInfo & { seq: number };\n\n// ---------------------------------------------------------------------------\n// Per-tab state\n// ---------------------------------------------------------------------------\n\nconst NETWORK_CAPACITY = 500;\nconst CONSOLE_CAPACITY = 200;\nconst ERRORS_CAPACITY = 100;\n\nexport class TabState {\n readonly targetId: string;\n shortId: string;\n\n networkRequests = new RingBuffer<SeqNetworkRequest>(NETWORK_CAPACITY);\n consoleMessages = new RingBuffer<SeqConsoleMessage>(CONSOLE_CAPACITY);\n jsErrors = new RingBuffer<SeqJSError>(ERRORS_CAPACITY);\n\n /** Lookup in-flight network requests by requestId for response/failure updates. */\n private networkByRequestId = new Map<string, SeqNetworkRequest>();\n\n /** seq of the last user-initiated action on this tab. */\n lastActionSeq = 0;\n\n /** Element refs from the most recent snapshot. */\n refs: Record<string, RefInfo> = {};\n\n /** Active frame ID for iframe navigation, null = main frame. */\n activeFrameId: string | null = null;\n\n /** Dialog auto-handler config. */\n dialogHandler: { accept: boolean; promptText?: string } | null = null;\n\n constructor(\n targetId: string,\n shortId: string,\n private readonly nextSeq: () => number,\n ) {\n this.targetId = targetId;\n this.shortId = shortId;\n }\n\n // --------------- Action seq ---------------\n\n /** Increment global seq and record it as this tab's last action. */\n recordAction(): number {\n const seq = this.nextSeq();\n this.lastActionSeq = seq;\n return seq;\n }\n\n // --------------- Network events ---------------\n\n addNetworkRequest(requestId: string, info: Omit<NetworkRequestInfo, \"requestId\">): void {\n const seq = this.nextSeq();\n const entry: SeqNetworkRequest = { ...info, requestId, seq };\n this.networkRequests.push(entry);\n this.networkByRequestId.set(requestId, entry);\n }\n\n updateNetworkResponse(\n requestId: string,\n data: {\n status?: number;\n statusText?: string;\n responseHeaders?: Record<string, string>;\n mimeType?: string;\n },\n ): void {\n const existing = this.networkByRequestId.get(requestId);\n if (!existing) return;\n if (data.status !== undefined) existing.status = data.status;\n if (data.statusText !== undefined) existing.statusText = data.statusText;\n if (data.responseHeaders !== undefined) existing.responseHeaders = data.responseHeaders;\n if (data.mimeType !== undefined) existing.mimeType = data.mimeType;\n }\n\n updateNetworkFailure(requestId: string, reason: string): void {\n const existing = this.networkByRequestId.get(requestId);\n if (!existing) return;\n existing.failed = true;\n existing.failureReason = reason;\n }\n\n // --------------- Console events ---------------\n\n addConsoleMessage(info: Omit<ConsoleMessageInfo, never>): void {\n const seq = this.nextSeq();\n this.consoleMessages.push({ ...info, seq });\n }\n\n // --------------- JS Error events ---------------\n\n addJSError(info: Omit<JSErrorInfo, never>): void {\n const seq = this.nextSeq();\n this.jsErrors.push({ ...info, seq });\n }\n\n // --------------- Query helpers ---------------\n\n getNetworkRequests(options?: {\n since?: number | \"last_action\";\n filter?: string;\n method?: string;\n status?: string;\n limit?: number;\n }): { items: SeqNetworkRequest[]; cursor: number } {\n let items = this.networkRequests.toArray();\n\n // since\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n // filter (URL substring)\n if (options?.filter) {\n const f = options.filter;\n items = items.filter((item) => item.url.includes(f));\n }\n\n // method\n if (options?.method) {\n const m = options.method.toUpperCase();\n items = items.filter((item) => item.method === m);\n }\n\n // status\n if (options?.status) {\n const s = options.status;\n if (s === \"4xx\") {\n items = items.filter((item) => item.status !== undefined && item.status >= 400 && item.status < 500);\n } else if (s === \"5xx\") {\n items = items.filter((item) => item.status !== undefined && item.status >= 500 && item.status < 600);\n } else {\n const code = Number(s);\n if (!Number.isNaN(code)) {\n items = items.filter((item) => item.status === code);\n }\n }\n }\n\n // limit\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n getConsoleMessages(options?: {\n since?: number | \"last_action\";\n filter?: string;\n limit?: number;\n }): { items: SeqConsoleMessage[]; cursor: number } {\n let items = this.consoleMessages.toArray();\n\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n if (options?.filter) {\n const f = options.filter;\n items = items.filter((item) => item.text.includes(f));\n }\n\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n getJSErrors(options?: {\n since?: number | \"last_action\";\n filter?: string;\n limit?: number;\n }): { items: SeqJSError[]; cursor: number } {\n let items = this.jsErrors.toArray();\n\n if (options?.since !== undefined) {\n const threshold =\n options.since === \"last_action\" ? this.lastActionSeq : options.since;\n items = items.filter((item) => item.seq > threshold);\n }\n\n if (options?.filter) {\n const f = options.filter;\n items = items.filter(\n (item) => item.message.includes(f) || (item.url?.includes(f) ?? false),\n );\n }\n\n if (options?.limit !== undefined && options.limit > 0 && items.length > options.limit) {\n items = items.slice(-options.limit);\n }\n\n const sinceThreshold = options?.since !== undefined\n ? (options.since === \"last_action\" ? this.lastActionSeq : options.since)\n : 0;\n const cursor = items.length > 0 ? Math.max(...items.map((i) => i.seq)) : sinceThreshold;\n return { items, cursor };\n }\n\n // --------------- Clear helpers ---------------\n\n clearNetwork(): void {\n this.networkRequests.clear();\n this.networkByRequestId.clear();\n }\n\n clearConsole(): void {\n this.consoleMessages.clear();\n }\n\n clearErrors(): void {\n this.jsErrors.clear();\n }\n}\n\n// ---------------------------------------------------------------------------\n// TabStateManager — manages all tabs + global seq\n// ---------------------------------------------------------------------------\n\nexport class TabStateManager {\n private seq = 0;\n private tabs = new Map<string, TabState>(); // targetId -> TabState\n private shortToTarget = new Map<string, string>(); // shortId -> targetId\n private targetToShort = new Map<string, string>(); // targetId -> shortId\n\n /** Generate a globally unique short ID for a target. */\n private generateShortId(targetId: string): string {\n for (let len = 4; len <= targetId.length; len++) {\n const candidate = targetId.slice(-len).toLowerCase();\n if (!this.shortToTarget.has(candidate)) {\n return candidate;\n }\n }\n // Extremely unlikely fallback\n return targetId.toLowerCase();\n }\n\n /** Get next seq (globally monotonic). */\n nextSeq(): number {\n return ++this.seq;\n }\n\n /** Get current seq without incrementing. */\n currentSeq(): number {\n return this.seq;\n }\n\n /** Register a new tab. Returns the TabState. */\n addTab(targetId: string): TabState {\n const existing = this.tabs.get(targetId);\n if (existing) return existing;\n\n const shortId = this.generateShortId(targetId);\n const tab = new TabState(targetId, shortId, () => this.nextSeq());\n this.tabs.set(targetId, tab);\n this.shortToTarget.set(shortId, targetId);\n this.targetToShort.set(targetId, shortId);\n return tab;\n }\n\n /** Remove a tab (on targetDestroyed / detach). */\n removeTab(targetId: string): void {\n const tab = this.tabs.get(targetId);\n if (!tab) return;\n this.shortToTarget.delete(tab.shortId);\n this.targetToShort.delete(targetId);\n this.tabs.delete(targetId);\n }\n\n /** Get tab by targetId. */\n getTab(targetId: string): TabState | undefined {\n return this.tabs.get(targetId);\n }\n\n /** Resolve a short ID to a targetId. */\n resolveShortId(shortId: string): string | undefined {\n return this.shortToTarget.get(shortId);\n }\n\n /** Get the short ID for a targetId. */\n getShortId(targetId: string): string | undefined {\n return this.targetToShort.get(targetId);\n }\n\n /** Get all active tabs. */\n allTabs(): TabState[] {\n return Array.from(this.tabs.values());\n }\n\n /** Get tab count. */\n get tabCount(): number {\n return this.tabs.size;\n }\n}\n"],"mappings":"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","names":["readFileSync","path","call","path","readFileSync"]}
package/dist/mcp.js CHANGED
@@ -21171,7 +21171,7 @@ async function runSiteCli(args) {
21171
21171
  return parsed ?? result.stdout.trim();
21172
21172
  }
21173
21173
  var server = new McpServer(
21174
- { name: "bb-browser", version: "0.11.1" },
21174
+ { name: "bb-browser", version: "0.11.2" },
21175
21175
  { instructions: `bb-browser lets you control the user's real Chrome browser via CDP (Chrome DevTools Protocol).
21176
21176
 
21177
21177
  Your browser is the API. No headless browser, no cookie extraction, no anti-bot bypass.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bb-browser",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "Your browser is the API. CLI + MCP server for AI agents to control Chrome with your login state.",
5
5
  "type": "module",
6
6
  "bin": {