{"version":3,"sources":["../src/index.ts","../src/search/bing.ts","../src/search/duckduckgo.ts","../src/search/searxng.ts","../src/search/tavily.ts","../src/libs/browser/types.ts","../src/libs/browser/finder.ts","../src/libs/browser/base.ts","../src/libs/browser/local.ts","../src/libs/browser/remote.ts","../src/libs/browser-search/readability.ts","../src/libs/browser-search/search.ts","../src/libs/browser-search/utils.ts","../src/libs/browser-search/queue.ts","../src/libs/browser-search/engines/bing.ts","../src/libs/browser-search/engines/baidu.ts","../src/libs/browser-search/engines/sogou.ts","../src/libs/browser-search/engines/google.ts","../src/libs/browser-search/engines/get.ts","../src/search/local.ts","../src/tools.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport  { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { ISearchRequestOptions, ISearchResponse, SearchProvider } from './interface.js';\nimport { bingSearch, duckDuckGoSearch, searxngSearch, tavilySearch, localSearch } from './search/index.js';\nimport { SEARCH_TOOL, EXTRACT_TOOL, SCRAPE_TOOL, MAP_TOOL } from './tools.js';\nimport FirecrawlApp, { MapParams, ScrapeParams } from '@mendable/firecrawl-js';\nimport dotenvx from '@dotenvx/dotenvx';\nimport { SafeSearchType } from 'duck-duck-scrape';\n\ndotenvx.config();\n\n// search api\nconst SEARCH_API_URL = process.env.SEARCH_API_URL;\nconst SEARCH_API_KEY = process.env.SEARCH_API_KEY;\nconst SEARCH_PROVIDER: SearchProvider = process.env.SEARCH_PROVIDER as SearchProvider ?? 'local';\n\n// search query params\nconst SAFE_SEARCH = process.env.SAFE_SEARCH ?? 0;\nconst LIMIT = process.env.LIMIT ?? 10;\nconst CATEGORIES = process.env.CATEGORIES ?? 'general';\nconst ENGINES = process.env.ENGINES ?? 'all';\nconst FORMAT = process.env.FORMAT ?? 'json';\nconst LANGUAGE = process.env.LANGUAGE ?? 'auto';\nconst TIME_RANGE = process.env.TIME_RANGE ?? '';\nconst DEFAULT_TIMEOUT = process.env.TIMEOUT ?? 10000;\n\n// firecrawl api\nconst FIRECRAWL_API_KEY = process.env.FIRECRAWL_API_KEY;\nconst FIRECRAWL_API_URL = process.env.FIRECRAWL_API_URL;\n\n// firecrawl client\nconst firecrawl = new FirecrawlApp({\n  apiKey: FIRECRAWL_API_KEY ?? '',\n  ...(FIRECRAWL_API_URL ? { apiUrl: FIRECRAWL_API_URL } : {}),\n});\n\n// Server implementation\nconst server = new Server(\n  {\n    name: 'one-search-mcp',\n    version: '0.0.1',\n  },\n  {\n    capabilities: {\n      tools: {},\n      logging: {},\n    },\n  },\n);\n\nconst searchDefaultConfig = {\n  limit: Number(LIMIT),\n  categories: CATEGORIES,\n  format: FORMAT,\n  safesearch: SAFE_SEARCH,\n  language: LANGUAGE,\n  engines: ENGINES,\n  time_range: TIME_RANGE,\n  timeout: DEFAULT_TIMEOUT,\n};\n\n// Tool handlers\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n  tools: [\n    SEARCH_TOOL,\n    EXTRACT_TOOL,\n    SCRAPE_TOOL,\n    MAP_TOOL,\n  ],\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n  const startTime = Date.now();\n\n  try {\n    const { name, arguments: args } = request.params;\n\n    if (!args) {\n      throw new Error('No arguments provided');\n    }\n  \n    server.sendLoggingMessage({\n      level: 'info',\n      data: `[${new Date().toISOString()}] Received request for tool: [${name}]`,\n    });\n  \n    switch (name) {\n      case 'one_search': {\n        // check args.\n        if (!checkSearchArgs(args)) {\n          throw new Error(`Invalid arguments for tool: [${name}]`);\n        }\n        try {\n          const { results, success } = await processSearch({\n            ...args,\n            apiKey: SEARCH_API_KEY ?? '',\n            apiUrl: SEARCH_API_URL,\n          });\n          if (!success) {\n            throw new Error('Failed to search');\n          }\n          const resultsText = results.map((result) => (\n            `Title: ${result.title}\nURL: ${result.url}\nDescription: ${result.snippet}\n${result.markdown ? `Content: ${result.markdown}` : ''}`\n          ));\n          return {\n            content: [\n              {\n                type: 'text',\n                text: resultsText.join('\\n\\n'),\n              },\n            ],\n            results,\n            success,\n          };\n        } catch (error) {\n          server.sendLoggingMessage({\n            level: 'error',\n            data: `[${new Date().toISOString()}] Error searching: ${error}`,\n          });\n          const msg = error instanceof Error ? error.message : 'Unknown error';\n          return {\n            success: false,\n            content: [\n              {\n                type: 'text',\n                text: msg,\n              },\n            ],\n          };\n        }\n      }\n      case 'one_scrape': {\n        if (!checkScrapeArgs(args)) {\n          throw new Error(`Invalid arguments for tool: [${name}]`);\n        }\n        try {\n          const startTime = Date.now();\n          server.sendLoggingMessage({\n            level: 'info',\n            data: `[${new Date().toISOString()}] Scraping started for url: [${args.url}]`,\n          });\n\n          const { url, ...scrapeArgs } = args;\n          const { content, success, result } = await processScrape(url, scrapeArgs);\n\n          server.sendLoggingMessage({\n            level: 'info',\n            data: `[${new Date().toISOString()}] Scraping completed in ${Date.now() - startTime}ms`,\n          });\n\n          return {\n            content,\n            result,\n            success,\n          };\n        } catch (error) {\n          server.sendLoggingMessage({\n            level: 'error',\n            data: `[${new Date().toISOString()}] Error scraping: ${error}`,\n          });\n          const msg = error instanceof Error ? error.message : 'Unknown error';\n          return {\n            success: false,\n            content: [\n              {\n                type: 'text',\n                text: msg,\n              },\n            ],\n          };\n        }\n      }\n      case 'one_map': {\n        if (!checkMapArgs(args)) {\n          throw new Error(`Invalid arguments for tool: [${name}]`);\n        }\n        try {\n          const { content, success, result } = await processMapUrl(args.url, args);\n          return {\n            content,\n            result,\n            success,\n          };\n        } catch (error) {\n          server.sendLoggingMessage({\n            level: 'error',\n            data: `[${new Date().toISOString()}] Error mapping: ${error}`,\n          });\n          const msg = error instanceof Error ? error.message : String(error);\n          return {\n            success: false,\n            content: [\n              {\n                type: 'text',\n                text: msg,\n              },\n            ],\n          };\n        }\n      }\n      default: {\n        throw new Error(`Unknown tool: ${name}`);\n      }\n    }\n  } catch(error) {\n    const msg = error instanceof Error ? error.message : String(error);\n    server.sendLoggingMessage({\n      level: 'error',\n      data: {\n        message: `[${new Date().toISOString()}] Error processing request: ${msg}`,\n        tool: request.params.name,\n        arguments: request.params.arguments,\n        timestamp: new Date().toISOString(),\n        duration: Date.now() - startTime,\n      },\n    });\n    return {\n      success: false,\n      content: [\n        {\n          type: 'text',\n          text: msg,\n        },\n      ],\n    };\n  } finally {\n    server.sendLoggingMessage({\n      level: 'info',\n      data: `[${new Date().toISOString()}] Request completed in ${Date.now() - startTime}ms`,\n    });\n  }\n});\n\nasync function processSearch(args: ISearchRequestOptions): Promise<ISearchResponse> {\n  switch (SEARCH_PROVIDER) {\n    case 'searxng': {\n      // merge default config with args\n      const params = {\n        ...searchDefaultConfig,\n        ...args,\n        apiKey: SEARCH_API_KEY,\n      };\n\n      // but categories and language have higher priority (ENV > args).\n      const { categories, language } = searchDefaultConfig;\n\n      if (categories) {\n        params.categories = categories;\n      }\n      if (language) {\n        params.language = language;\n      }\n      return await searxngSearch(params);\n    }\n    case 'tavily': {\n      return await tavilySearch({\n        ...searchDefaultConfig,\n        ...args,\n        apiKey: SEARCH_API_KEY,\n      });\n    }\n    case 'bing': {\n      return await bingSearch({\n        ...searchDefaultConfig,\n        ...args,\n        apiKey: SEARCH_API_KEY,\n      });\n    }\n    case 'duckduckgo': {\n      const safeSearch = args.safeSearch ?? 0;\n      const safeSearchOptions = [SafeSearchType.STRICT, SafeSearchType.MODERATE, SafeSearchType.OFF];\n      return await duckDuckGoSearch({\n        ...searchDefaultConfig,\n        ...args,\n        apiKey: SEARCH_API_KEY,\n        safeSearch: safeSearchOptions[safeSearch],\n      });\n    }\n    case 'local': {\n      return await localSearch({\n        ...searchDefaultConfig,\n        ...args,\n      });\n    }\n    default:\n      throw new Error(`Unsupported search provider: ${SEARCH_PROVIDER}`);\n  }\n}\n\nasync function processScrape(url: string, args: ScrapeParams) {\n  const res = await firecrawl.scrapeUrl(url, {\n    ...args,\n  });\n\n  if (!res.success) {\n    throw new Error(`Failed to scrape: ${res.error}`);\n  }\n\n  const content: string[] = [];\n\n  if (res.markdown) {\n    content.push(res.markdown);\n  }\n\n  if (res.rawHtml) {\n    content.push(res.rawHtml);\n  }\n\n  if (res.links) {\n    content.push(res.links.join('\\n'));\n  }\n\n  if (res.screenshot) {\n    content.push(res.screenshot);\n  }\n\n  if (res.html) {\n    content.push(res.html);\n  }\n\n  if (res.extract) {\n    content.push(res.extract);\n  }\n\n  return {\n    content: [\n      {\n        type: 'text',\n        text: content.join('\\n\\n') || 'No content found',\n      },\n    ],\n    result: res,\n    success: true,\n  };\n}\n\nasync function processMapUrl(url: string, args: MapParams) {\n  const res = await firecrawl.mapUrl(url, {\n    ...args,\n  });\n\n  if ('error' in res) {\n    throw new Error(`Failed to map: ${res.error}`);\n  }\n\n  if (!res.links) {\n    throw new Error(`No links found from: ${url}`);\n  }\n\n  return {\n    content: [\n      {\n        type: 'text',\n        text: res.links.join('\\n').trim(),\n      },\n    ],\n    result: res.links,\n    success: true,\n  };\n}\n\nfunction checkSearchArgs(args: unknown): args is ISearchRequestOptions {\n  return (\n    typeof args === 'object' &&\n    args !== null &&\n    'query' in args &&\n    typeof args.query === 'string'\n  );\n}\n\nfunction checkScrapeArgs(args: unknown): args is ScrapeParams & { url: string } {\n  return (\n    typeof args === 'object' &&\n    args !== null &&\n    'url' in args &&\n    typeof args.url === 'string'\n  );\n}\n\nfunction checkMapArgs(args: unknown): args is MapParams & { url: string } {\n  return (\n    typeof args === 'object' &&\n    args !== null &&\n    'url' in args &&\n    typeof args.url === 'string'\n  );\n}\n\nasync function runServer() {\n  try {\n    process.stdout.write('Starting OneSearch MCP server...\\n');\n\n    const transport = new StdioServerTransport();\n    await server.connect(transport);\n\n    server.sendLoggingMessage({\n      level: 'info',\n      data: 'OneSearch MCP server started',\n    });\n\n  } catch (error) {\n    const msg = error instanceof Error ? error.message : String(error);\n    process.stderr.write(`Error starting server: ${msg}\\n`);\n    process.exit(1);\n  }\n}\n\n// run server\nrunServer().catch((error) => {\n  const msg = error instanceof Error ? error.message : String(error);\n  process.stderr.write(`Error running server: ${msg}\\n`);\n  process.exit(1);\n});\n\n// export types\nexport * from './interface.js';\n","/**\n * Bing Search API\n */\nimport { ISearchRequestOptions, ISearchResponse } from '../interface.js';\n\n\n/**\n * Options for performing a Bing search\n */\nexport interface BingSearchOptions {\n  /**\n   * Search query string\n   */\n  q: string;\n\n  /**\n   * Number of results to return\n   */\n  count?: number;\n\n  /**\n   * Result offset for pagination\n   */\n  offset?: number;\n\n  /**\n   * Market code (e.g., 'en-US')\n   */\n  mkt?: string;\n\n  /**\n   * Safe search filtering level\n   */\n  safeSearch?: 'Off' | 'Moderate' | 'Strict';\n\n  /**\n   * Bing API key\n   */\n  apiKey: string;\n\n  /**\n   * Bing Search API URL\n   */\n  apiUrl?: string;\n\n  /**\n   * Additional parameters supported by Bing Search API\n   */\n  [key: string]: any;\n}\n\n/**\n * Represents a web page result from Bing Search\n */\nexport interface BingSearchWebPage {\n  /**\n   * Title of the web page\n   */\n  name: string;\n\n  /**\n   * URL of the web page\n   */\n  url: string;\n\n  /**\n   * Text snippet from the web page\n   */\n  snippet: string;\n\n  /**\n   * Date the page was last crawled by Bing\n   */\n  dateLastCrawled?: string;\n\n  /**\n   * Display URL for the web page\n   */\n  displayUrl?: string;\n\n  /**\n   * Unique identifier for the result\n   */\n  id?: string;\n\n  /**\n   * Indicates if the content is family friendly\n   */\n  isFamilyFriendly?: boolean;\n\n  /**\n   * Indicates if the result is navigational\n   */\n  isNavigational?: boolean;\n\n  /**\n   * Language of the web page\n   */\n  language?: string;\n\n  /**\n   * Indicates if caching should be disabled\n   */\n  noCache?: boolean;\n\n  /**\n   * Name of the website\n   */\n  siteName?: string;\n\n  /**\n   * URL to a thumbnail image\n   */\n  thumbnailUrl?: string;\n}\n\n/**\n * Represents an image result from Bing Search\n */\nexport interface BingSearchImage {\n  contentSize: string;\n  contentUrl: string;\n  datePublished: string;\n  encodingFormat: string;\n  height: number;\n  width: number;\n  hostPageDisplayUrl: string;\n  hostPageUrl: string;\n  name: string;\n  thumbnail: {\n    height: number;\n    width: number;\n  };\n  thumbnailUrl: string;\n  webSearchUrl: string;\n}\n\n/**\n * Represents a video result from Bing Search\n */\nexport interface BingSearchVideo {\n  allowHttpsEmbed: boolean;\n  allowMobileEmbed: boolean;\n  contentUrl: string;\n  creator?: {\n    name: string;\n  };\n  datePublished: string;\n  description: string;\n  duration: string;\n  embedHtml: string;\n  encodingFormat: string;\n  height: number;\n  width: number;\n  hostPageDisplayUrl: string;\n  hostPageUrl: string;\n  name: string;\n  publisher?: {\n    name: string;\n  }[];\n  thumbnail: {\n    height: number;\n    width: number;\n  };\n  thumbnailUrl: string;\n  viewCount?: number;\n  webSearchUrl: string;\n}\n\nexport interface BingSearchResponse {\n  _type?: string;\n  queryContext?: {\n    originalQuery: string;\n  };\n  webPages?: {\n    value: BingSearchWebPage[];\n    totalEstimatedMatches?: number;\n    someResultsRemoved?: boolean;\n    webSearchUrl?: string;\n  };\n  images?: {\n    value: BingSearchImage[];\n    isFamilyFriendly?: boolean;\n    readLink?: string;\n    webSearchUrl?: string;\n    id?: string;\n  };\n  videos?: {\n    value: BingSearchVideo[];\n    isFamilyFriendly?: boolean;\n    readLink?: string;\n    webSearchUrl?: string;\n    id?: string;\n    scenario?: string;\n  };\n  rankingResponse?: {\n    mainline?: {\n      items: {\n        answerType: string;\n        resultIndex?: number;\n        value: {\n          id: string;\n        };\n      }[];\n    };\n  };\n  [key: string]: any; // Allow other response fields\n}\n\nexport async function bingSearch(options: ISearchRequestOptions): Promise<ISearchResponse> {\n  const { query, limit = 10, safeSearch = 0, page = 1, apiUrl = 'https://api.bing.microsoft.com/v7.0/search', apiKey, language } = options;\n\n  const bingSafeSearchOptions = ['Off', 'Moderate', 'Strict'];\n\n  if (!apiKey) {\n    throw new Error('Bing API key is required');\n  }\n\n  const searchOptions = {\n    q: query,\n    count: limit,\n    offset: (page - 1) * limit,\n    mkt: language,\n    safeSearch: bingSafeSearchOptions[safeSearch] as 'Off' | 'Moderate' | 'Strict',\n  };\n\n  try {\n    const queryParams = new URLSearchParams();\n    Object.entries(searchOptions).forEach(([key, value]) => {\n      if (value !== undefined) {\n        queryParams.set(key, value.toString());\n      }\n    });\n\n    const res = await fetch(`${apiUrl}?${queryParams}`, {\n      method: 'GET',\n      headers: {\n        'Content-Type': 'application/json',\n        'Ocp-Apim-Subscription-Key': apiKey,\n      },\n    });\n\n    if (!res.ok) {\n      throw new Error(`Bing search error: ${res.status} ${res.statusText}`);\n    }\n\n    const data = await res.json();\n    const serp = data.webPages?.value as Array<BingSearchWebPage>;\n    const results = serp?.map((item: BingSearchWebPage) => ({\n      title: item.name,\n      snippet: item.snippet,\n      url: item.url,\n      source: item.siteName,\n      thumbnailUrl: item.thumbnailUrl,\n      language: item.language,\n      image: null,\n      video: null,\n      engine: 'bing',\n    })) ?? [];\n\n    return {\n      results,\n      success: true,\n    };\n  } catch (err: unknown) {\n    const msg = err instanceof Error ? err.message : 'Bing search error.';\n    process.stdout.write(msg);\n    throw err;\n  }\n}","import * as DDG from 'duck-duck-scrape';\nimport asyncRetry from 'async-retry';\nimport type { SearchOptions } from 'duck-duck-scrape';\nimport { ISearchRequestOptions, ISearchResponse } from '../interface.js';\n\n\nexport async function duckDuckGoSearch(options: Omit<ISearchRequestOptions, 'safeSearch'> & SearchOptions): Promise<ISearchResponse> {\n  try {\n    const { query, timeout = 10000, safeSearch = DDG.SafeSearchType.OFF, retry = { retries: 3 }, ...searchOptions } = options;\n  \n    const res = await asyncRetry(\n      () => {\n        return DDG.search(query, {\n          ...searchOptions,\n          safeSearch,\n        }, {\n          // needle options\n          response_timeout: timeout,\n        });\n      },\n      retry,\n    );\n\n    const results = res ? {\n      noResults: res.noResults,\n      vqd: res.vqd,\n      results: res.results,\n    } : {\n      noResults: true,\n      vqd: '',\n      results: [],\n    };\n\n    return {\n      results: results.results.map((result) => ({\n        title: result.title,\n        snippet: result.description,\n        url: result.url,\n        source: result.hostname,\n        image: null,\n        video: null,\n        engine: 'duckduckgo',\n      })),\n      success: true,\n    };\n  } catch (error) {\n    const msg = error instanceof Error ? error.message : 'DuckDuckGo search error.';\n    process.stdout.write(msg);\n    throw error;\n  }\n}\n","import url from 'node:url';\nimport { ISearchRequestOptions, ISearchResponse, ISearchResponseResult } from '../interface.js';\n\n/**\n * SearxNG Search API\n * - https://docs.searxng.org/dev/search_api.html\n */\nexport async function searxngSearch(params: ISearchRequestOptions): Promise<ISearchResponse> {\n  try {\n    const {\n      query,\n      page = 1,\n      limit = 10,\n      categories = 'general',\n      engines = 'all',\n      safeSearch = 0,\n      format = 'json',\n      language = 'auto',\n      timeRange = '',\n      timeout = 10000,\n      apiKey,\n      apiUrl,\n    } = params;\n\n    if (!apiUrl) {\n      throw new Error('SearxNG API URL is required');\n    }\n\n    const controller = new AbortController();\n    const timeoutId = setTimeout(() => controller.abort(), Number(timeout));\n\n    const config = {\n      q: query,\n      pageno: page,\n      categories,\n      format,\n      safesearch: safeSearch,\n      language,\n      engines,\n      time_range: timeRange,\n    };\n\n    const endpoint = `${apiUrl}/search`;\n\n    const queryParams = url.format({ query: config });\n\n    const headers: HeadersInit = {\n      'Content-Type': 'application/json',\n    };\n\n    if (apiKey) {\n      headers['Authorization'] = `Bearer ${apiKey}`;\n    }\n\n    const res = await fetch(`${endpoint}${queryParams}`, {\n      method: 'POST',\n      headers,\n      signal: controller.signal,\n    });\n\n    clearTimeout(timeoutId);\n    const response = await res.json();\n    if (response.results) {\n      const list = (response.results as Array<Record<string, any>>).slice(0, limit);\n      const results: ISearchResponseResult[] = list.map((item: Record<string, any>) => {\n        const image = item.img_src ? {\n          thumbnail: item.thumbnail_src,\n          src: item.img_src,\n        } : null;\n        const video = item.iframe_src ? {\n          thumbnail: item.thumbnail_src,\n          src: item.iframe_src,\n        } : null;\n        return {\n          title: item.title,\n          snippet: item.content,\n          url: item.url,\n          source: item.source,\n          image,\n          video,\n          engine: item.engine,\n        };\n      });\n      return {\n        results,\n        success: true,\n      };\n    }\n    return {\n      results: [],\n      success: false,\n    };\n  } catch (err: unknown) {\n    const msg = err instanceof Error ? err.message : 'Searxng search error.';\n    process.stdout.write(msg);\n    throw err;\n  }\n}\n","import { tavily, TavilySearchOptions } from '@tavily/core';\nimport { ISearchRequestOptions, ISearchResponse } from '../interface.js';\n\n/**\n * Tavily Search API\n * - https://docs.tavily.com/documentation/quickstart\n */\nexport async function tavilySearch(options: ISearchRequestOptions): Promise<ISearchResponse> {\n  const {\n    query,\n    limit = 10,\n    categories = 'general',\n    timeRange,\n    apiKey,\n  } = options;\n\n  if (!apiKey) {\n    throw new Error('Tavily API key is required');\n  }\n\n  try {\n    const tvly = tavily({\n      apiKey,\n    });\n  \n    const params: TavilySearchOptions = {\n      topic: categories as TavilySearchOptions['topic'],\n      timeRange: timeRange as TavilySearchOptions['timeRange'],\n      maxResults: limit,\n    };\n  \n    const res = await tvly.search(query, params);\n    const results = res.results.map(item => ({\n      title: item.title,\n      url: item.url,\n      snippet: item.content,\n      engine: 'tavily',\n    }));\n  \n    return {\n      results,\n      success: true,\n    };\n  } catch (error) {\n    const msg = error instanceof Error ? error.message : 'Tavily search error.';\n    process.stdout.write(msg);\n    throw error;\n  }\n}","/**\n * The following code is based on\n * https://github.com/bytedance/UI-TARS-desktop/tree/main/packages/agent-infra/browser\n * \n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { Page, WaitForOptions } from 'puppeteer-core';\n\n/**\n * Options for launching a browser instance\n * @interface LaunchOptions\n */\nexport interface LaunchOptions {\n  /**\n   * Whether to run browser in headless mode\n   * @default false\n   */\n  headless?: boolean;\n\n  /**\n   * Maximum time in milliseconds to wait for the browser to start\n   * @default 0 (no timeout)\n   */\n  timeout?: number;\n\n  /**\n   * The viewport dimensions\n   * @property {number} width - Viewport width in pixels\n   * @property {number} height - Viewport height in pixels\n   */\n  defaultViewport?: {\n    width: number;\n    height: number;\n  };\n\n  /**\n   * Path to a browser executable to use instead of the automatically detected one\n   * If not provided, the system will attempt to find an installed browser\n   */\n  executablePath?: string;\n\n  /**\n   * Path to a specific browser profile to use\n   * Allows using existing browser profiles with cookies, extensions, etc.\n   */\n  profilePath?: string;\n\n  /**\n   * Proxy server URL, e.g. 'http://proxy.example.com:8080'\n   * Used to route browser traffic through a proxy server\n   */\n  proxy?: string;\n}\n\n/**\n * Options for evaluating JavaScript in a new page\n * @template T - Array of parameters to pass to the page function\n * @template R - Return type of the page function\n * @interface EvaluateOnNewPageOptions\n */\nexport interface EvaluateOnNewPageOptions<T extends any[], R> {\n  /**\n   * URL to navigate to before evaluating the function\n   * The page will load this URL before executing the pageFunction\n   */\n  url: string;\n\n  /**\n   * Options for waiting for the page to load\n   */\n  waitForOptions?: WaitForOptions;\n\n  /**\n   * Function to be evaluated in the page context\n   * This function runs in the context of the browser page, not Node.js\n   * @param {Window} window - The window object of the page\n   * @param {...T} args - Additional arguments passed to the function\n   * @returns {R} Result of the function execution\n   */\n  pageFunction: (window: Window, ...args: T) => R;\n\n  /**\n   * Parameters to pass to the page function\n   * These values will be serialized and passed to the pageFunction\n   */\n  pageFunctionParams: T;\n\n  /**\n   * Optional function to execute before page navigation\n   * Useful for setting up page configuration before loading the URL\n   * @param {Page} page - Puppeteer page instance\n   * @returns {void | Promise<void>}\n   */\n  beforePageLoad?: (page: Page) => void | Promise<void>;\n\n  /**\n   * Optional function to execute after page navigation\n   * Useful for setting up page configuration after loading the URL\n   * @param {Page} page - Puppeteer page instance\n   * @returns {void | Promise<void>}\n   */\n  afterPageLoad?: (page: Page) => void | Promise<void>;\n\n  /**\n   * Optional function to process the result before returning\n   * Can be used to transform or validate the result from page evaluation\n   * @param {Page} page - Puppeteer page instance\n   * @param {R} result - Result from page function evaluation\n   * @returns {R | Promise<R>} Processed result\n   */\n  beforeSendResult?: (page: Page, result: R) => R | Promise<R>;\n}\n\n/**\n * Core browser interface that all browser implementations must implement\n * Defines the standard API for browser automation\n * @interface BrowserInterface\n */\nexport interface BrowserInterface {\n  /**\n   * Launch a new browser instance\n   * @param {LaunchOptions} [options] - Launch configuration options\n   * @returns {Promise<void>} Promise resolving when browser is launched\n   */\n  launch(options?: LaunchOptions): Promise<void>;\n\n  /**\n   * Close the browser instance and all its pages\n   * @returns {Promise<void>} Promise resolving when browser is closed\n   */\n  close(): Promise<void>;\n\n  /**\n   * Create a new page in the browser\n   * @returns {Promise<Page>} Promise resolving to the new page instance\n   */\n  createPage(): Promise<Page>;\n\n  /**\n   * Evaluate a function in a new page context\n   * Creates a new page, navigates to URL, executes function, and returns result\n   * @template T - Array of parameters to pass to the page function\n   * @template R - Return type of the page function\n   * @param {EvaluateOnNewPageOptions<T, R>} options - Evaluation options\n   * @returns {Promise<R | null>} Promise resolving to the function result or null\n   */\n  evaluateOnNewPage<T extends any[], R>(\n    options: EvaluateOnNewPageOptions<T, R>,\n  ): Promise<R | null>;\n\n  /**\n   * Get the currently active page or create one if none exists\n   * @returns {Promise<Page>} Promise resolving to the active page instance\n   */\n  getActivePage(): Promise<Page>;\n}\n\nexport { Page };","/**\n * The following code is modified based on\n * https://github.com/egoist/local-web-search/blob/main/src/find-browser.ts\n * Copy from\n * https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/agent-infra/browser/src/browser-finder.ts\n * \n * MIT Licensed\n * Copyright (c) 2025 ChatWise (https://chatwise.app) <kevin@chatwise.app>\n * https://github.com/egoist/local-web-search/blob/main/LICENSE\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { Logger, defaultLogger } from '@agent-infra/logger';\n\n/**\n * Interface defining browser locations and configurations\n * Contains paths and settings for different operating systems\n * @interface Browser\n */\ninterface Browser {\n  /**\n   * Browser name identifier\n   */\n  name: string;\n\n  /**\n   * Executable paths by platform\n   * @property {string} win32 - Windows executable path\n   * @property {string} darwin - macOS executable path\n   * @property {string} linux - Linux executable path\n   */\n  executable: {\n    win32: string;\n    darwin: string;\n    linux: string;\n  };\n\n  /**\n   * User data directory paths by platform\n   * @property {string} win32 - Windows user data directory\n   * @property {string} darwin - macOS user data directory\n   * @property {string} linux - Linux user data directory\n   */\n  userDataDir: {\n    win32: string;\n    darwin: string;\n    linux: string;\n  };\n}\n\n/**\n * Class responsible for finding and managing browser installations\n * Detects installed browsers and their profiles across different platforms\n */\nexport class BrowserFinder {\n  /**\n   * Logger instance for diagnostic output\n   */\n  private logger: Logger;\n\n  /**\n   * Creates a new BrowserFinder instance\n   * @param {Logger} [logger] - Optional custom logger\n   */\n  constructor(logger?: Logger) {\n    this.logger = logger ?? defaultLogger;\n  }\n\n  /**\n   * Getter that returns the list of supported browsers with their platform-specific paths\n   * @returns {Browser[]} Array of browser configurations\n   * @private\n   */\n  private get browsers(): Browser[] {\n    // Get HOME_DIR inside the getter to ensure it's always current\n    const HOME_DIR = os.homedir();\n    const LOCAL_APP_DATA = process.env.LOCALAPPDATA;\n\n    return [\n      {\n        name: 'Chromium',\n        executable: {\n          win32: 'C:\\\\Program Files\\\\Chromium\\\\Application\\\\chrome.exe',\n          darwin: '/Applications/Chromium.app/Contents/MacOS/Chromium',\n          linux: '/usr/bin/chromium',\n        },\n        userDataDir: {\n          win32: `${LOCAL_APP_DATA}\\\\Chromium\\\\User Data`,\n          darwin: `${HOME_DIR}/Library/Application Support/Chromium`,\n          linux: `${HOME_DIR}/.config/chromium`,\n        },\n      },\n      {\n        name: 'Google Chrome',\n        executable: {\n          win32: 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n          darwin:\n            '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n          linux: '/usr/bin/google-chrome',\n        },\n        userDataDir: {\n          win32: `${LOCAL_APP_DATA}\\\\Google\\\\Chrome\\\\User Data`,\n          darwin: `${HOME_DIR}/Library/Application Support/Google/Chrome`,\n          linux: `${HOME_DIR}/.config/google-chrome`,\n        },\n      },\n      {\n        name: 'Google Chrome Canary',\n        executable: {\n          win32:\n            'C:\\\\Program Files\\\\Google\\\\Chrome Canary\\\\Application\\\\chrome.exe',\n          darwin:\n            '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n          linux: '/usr/bin/google-chrome-canary',\n        },\n        userDataDir: {\n          win32: `${LOCAL_APP_DATA}\\\\Google\\\\Chrome Canary\\\\User Data`,\n          darwin: `${HOME_DIR}/Library/Application Support/Google/Chrome Canary`,\n          linux: `${HOME_DIR}/.config/google-chrome-canary`,\n        },\n      },\n    ];\n  }\n\n  /**\n   * Find a specific browser or the first available browser\n   * @param {string} [name] - Optional browser name to find\n   * @returns {{ executable: string; userDataDir: string }} Browser executable and user data paths\n   * @throws {Error} If no supported browser is found or the platform is unsupported\n   */\n  findBrowser(name?: string): {\n    executable: string;\n    userDataDir: string;\n  } {\n    const platform = process.platform;\n    this.logger.info('Finding browser on platform:', platform);\n\n    if (platform !== 'darwin' && platform !== 'win32' && platform !== 'linux') {\n      const error = new Error(`Unsupported platform: ${platform}`);\n      this.logger.error(error.message);\n      throw error;\n    }\n\n    const browser = name\n      ? this.browsers.find(\n        (b) => b.name === name && fs.existsSync(b.executable[platform]),\n      )\n      : this.browsers.find((b) => fs.existsSync(b.executable[platform]));\n\n    this.logger.log('browser', browser);\n\n    if (!browser) {\n      const error = name\n        ? new Error(`Cannot find browser: ${name}`)\n        : new Error(\n          'Cannot find a supported browser on your system. Please install Chrome, Edge, or Brave.',\n        );\n      this.logger.error(error.message);\n      throw error;\n    }\n\n    const result = {\n      executable: browser.executable[platform],\n      userDataDir: browser.userDataDir[platform],\n    };\n\n    this.logger.success(`Found browser: ${browser.name}`);\n    this.logger.info('Browser details:', result);\n\n    return result;\n  }\n\n  /**\n   * Get browser profiles for a specific browser\n   * Reads the Local State file to extract profile information\n   * @param {string} [browserName] - Optional browser name to get profiles for\n   * @returns {Array<{ displayName: string; path: string }>} Array of profile objects with display names and paths\n   */\n  getBrowserProfiles(\n    browserName?: string,\n  ): Array<{ displayName: string; path: string }> {\n    const browser = this.findBrowser(browserName);\n\n    try {\n      const localState = JSON.parse(\n        fs.readFileSync(path.join(browser.userDataDir, 'Local State'), 'utf8'),\n      );\n      const profileInfo = localState.profile.info_cache;\n\n      return Object.entries(profileInfo).map(\n        ([profileName, info]: [string, any]) => ({\n          displayName: info.name,\n          path: path.join(browser.userDataDir, profileName),\n        }),\n      );\n    } catch (error) {\n      return [];\n    }\n  }\n\n  /**\n   * Legacy method for backwards compatibility\n   * Finds Chrome browser executable path\n   * @deprecated Use findBrowser instead\n   * @returns {string | null} Chrome executable path or null if not found\n   */\n  findChrome(): string | null {\n    try {\n      const { executable } = this.findBrowser('Google Chrome');\n      return executable;\n    } catch {\n      return null;\n    }\n  }\n}\n","/**\n * The following code is based on\n * https://github.com/bytedance/UI-TARS-desktop/tree/main/packages/agent-infra/browser\n * \n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport * as puppeteer from 'puppeteer-core';\nimport { Logger, defaultLogger } from '@agent-infra/logger';\nimport {\n  BrowserInterface,\n  EvaluateOnNewPageOptions,\n  LaunchOptions,\n  Page,\n} from './types.js';\n\n/**\n * Configuration options for the BaseBrowser class\n * @interface BaseBrowserOptions\n * @property {Logger} [logger] - Custom logger instance to use for browser logging\n */\nexport interface BaseBrowserOptions {\n  logger?: Logger;\n}\n\n/**\n * Abstract base class that implements common browser automation functionality\n * Provides a foundation for specific browser implementations with shared capabilities\n * @abstract\n * @implements {BrowserInterface}\n */\nexport abstract class BaseBrowser implements BrowserInterface {\n  /**\n   * The underlying Puppeteer browser instance\n   * @protected\n   */\n  protected browser: puppeteer.Browser | null = null;\n\n  /**\n   * Logger instance for browser-related logging\n   * @protected\n   */\n  protected logger: Logger;\n\n  /**\n   * Reference to the currently active browser page\n   * @protected\n   */\n  protected activePage: Page | null = null;\n\n  /**\n   * Creates an instance of BaseBrowser\n   * @param {BaseBrowserOptions} [options] - Configuration options\n   */\n  constructor(options?: BaseBrowserOptions) {\n    this.logger = options?.logger ?? defaultLogger;\n    this.logger.info('Browser Options:', options);\n  }\n\n  /**\n   * Get the underlying Puppeteer browser instance\n   * @throws Error if browser is not launched\n\n   * @returns {puppeteer.Browser} Puppeteer browser instance\n   */\n  getBrowser(): puppeteer.Browser {\n    if (!this.browser) {\n      throw new Error('Browser not launched');\n    }\n    return this.browser;\n  }\n\n  /**\n   * Sets up listeners for browser page events\n   * Tracks page creation and updates active page reference\n   * @protected\n   */\n  protected async setupPageListener() {\n    if (!this.browser) return;\n\n    this.browser.on('targetcreated', async (target) => {\n      const page = await target.page();\n      if (page) {\n        this.logger.info('New page created:', await page.url());\n        this.activePage = page;\n\n        page.once('close', () => {\n          if (this.activePage === page) {\n            this.activePage = null;\n          }\n        });\n\n        page.once('error', () => {\n          if (this.activePage === page) {\n            this.activePage = null;\n          }\n        });\n      }\n    });\n  }\n\n  /**\n   * Launches the browser with specified options\n   * @abstract\n   * @param {LaunchOptions} [options] - Browser launch configuration options\n   * @returns {Promise<void>} Promise that resolves when browser is launched\n   */\n  abstract launch(options?: LaunchOptions): Promise<void>;\n\n  /**\n   * Closes the browser instance and cleans up resources\n   * @returns {Promise<void>} Promise that resolves when browser is closed\n   * @throws {Error} If browser fails to close properly\n   */\n  async close(): Promise<void> {\n    this.logger.info('Closing browser');\n    try {\n      await this.browser?.close();\n      this.browser = null;\n      this.logger.success('Browser closed successfully');\n    } catch (error) {\n      this.logger.error('Failed to close browser:', error);\n      throw error;\n    }\n  }\n\n  /**\n   * Creates a new page, navigates to the specified URL, executes a function in the page context, and returns the result\n   * This method is inspired and modified from https://github.com/egoist/local-web-search/blob/04608ed09aa103e2fff6402c72ca12edfb692d19/src/browser.ts#L74\n   * @template T - Type of parameters passed to the page function\n   * @template R - Return type of the page function\n   * @param {EvaluateOnNewPageOptions<T, R>} options - Configuration options for the page evaluation\n   * @returns {Promise<R | null>} Promise resolving to the result of the page function or null\n   * @throws {Error} If page creation or evaluation fails\n   */\n  async evaluateOnNewPage<T extends any[], R>(\n    options: EvaluateOnNewPageOptions<T, R>,\n  ): Promise<R | null> {\n    const {\n      url,\n      pageFunction,\n      pageFunctionParams,\n      beforePageLoad,\n      afterPageLoad,\n      beforeSendResult,\n      waitForOptions,\n    } = options;\n    const page = await this.browser!.newPage();\n    try {\n      await beforePageLoad?.(page);\n      await page.goto(url, {\n        waitUntil: 'networkidle2',\n        ...waitForOptions,\n      });\n      await afterPageLoad?.(page);\n      const _window = await page.evaluateHandle(() => window);\n      const result = await page.evaluate(\n        pageFunction,\n        _window,\n        ...pageFunctionParams,\n      );\n      await beforeSendResult?.(page, result);\n      await _window.dispose();\n      await page.close();\n      return result;\n    } catch (error) {\n      await page.close();\n      throw error;\n    }\n  }\n\n  /**\n   * Creates a new browser page\n   * @returns {Promise<Page>} Promise resolving to the newly created page\n   * @throws {Error} If browser is not launched or page creation fails\n   */\n  async createPage(): Promise<Page> {\n    if (!this.browser) {\n      this.logger.error('No active browser');\n      throw new Error('Browser not launched');\n    }\n    const page = await this.browser.newPage();\n    return page;\n  }\n\n  /**\n   * Gets the currently active page or finds an active page if none is currently tracked\n   * If no active pages exist, creates a new page\n   * @returns {Promise<Page>} Promise resolving to the active page\n   * @throws {Error} If browser is not launched or no active page can be found/created\n   */\n  async getActivePage(): Promise<Page> {\n    if (!this.browser) {\n      throw new Error('Browser not launched');\n    }\n\n    // If activePage exists and is still available, return directly\n    if (this.activePage) {\n      try {\n        // Verify that the page is still available\n        await this.activePage.evaluate(() => document.readyState);\n        return this.activePage;\n      } catch (e) {\n        this.logger.warn('Active page no longer available:', e);\n        this.activePage = null;\n      }\n    }\n\n    // Get all pages and find the last active page\n    const pages = await this.browser.pages();\n\n    if (pages.length === 0) {\n      this.activePage = await this.createPage();\n      return this.activePage;\n    }\n\n    // Find the last responding page\n    for (let i = pages.length - 1; i >= 0; i--) {\n      const page = pages[i];\n      try {\n        await page.evaluate(() => document.readyState);\n        this.activePage = page;\n        return page;\n      } catch (e) {\n        continue;\n      }\n    }\n\n    throw new Error('No active page found');\n  }\n}","/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport * as puppeteer from 'puppeteer-core';\nimport { LaunchOptions } from './types.js';\nimport { BrowserFinder } from './finder.js';\nimport { BaseBrowser } from './base.js';\n\n/**\n * LocalBrowser class for controlling locally installed browsers\n * Extends the BaseBrowser with functionality specific to managing local browser instances\n * @extends BaseBrowser\n */\nexport class LocalBrowser extends BaseBrowser {\n  /**\n   * Browser finder instance to detect and locate installed browsers\n   * @private\n   */\n  private browserFinder = new BrowserFinder();\n\n  /**\n   * Launches a local browser instance with specified options\n   * Automatically detects installed browsers if no executable path is provided\n   * @param {LaunchOptions} options - Configuration options for launching the browser\n   * @returns {Promise<void>} Promise that resolves when the browser is successfully launched\n   * @throws {Error} If the browser cannot be launched\n   */\n  async launch(options: LaunchOptions = {}): Promise<void> {\n    this.logger.info('Launching browser with options:', options);\n\n    const executablePath =\n      options?.executablePath || this.browserFinder.findBrowser().executable;\n\n    this.logger.info('Using executable path:', executablePath);\n\n    const viewportWidth = options?.defaultViewport?.width ?? 1280;\n    const viewportHeight = options?.defaultViewport?.height ?? 800;\n\n    const puppeteerLaunchOptions: puppeteer.LaunchOptions = {\n      executablePath,\n      headless: options?.headless ?? false,\n      defaultViewport: {\n        width: viewportWidth,\n        height: viewportHeight,\n      },\n      args: [\n        '--no-sandbox',\n        '--mute-audio',\n        '--disable-gpu',\n        '--disable-http2',\n        '--disable-blink-features=AutomationControlled',\n        '--disable-infobars',\n        '--disable-background-timer-throttling',\n        '--disable-popup-blocking',\n        '--disable-backgrounding-occluded-windows',\n        '--disable-renderer-backgrounding',\n        '--disable-window-activation',\n        '--disable-focus-on-load',\n        '--no-default-browser-check', // disable default browser check\n        '--disable-web-security', // disable CORS\n        '--disable-features=IsolateOrigins,site-per-process',\n        '--disable-site-isolation-trials',\n        `--window-size=${viewportWidth},${viewportHeight + 90}`,\n        options?.proxy ? `--proxy-server=${options.proxy}` : '',\n        options?.profilePath\n          ? `--profile-directory=${options.profilePath}`\n          : '',\n      ].filter(Boolean),\n      ignoreDefaultArgs: ['--enable-automation'],\n      timeout: options.timeout ?? 0,\n      downloadBehavior: {\n        policy: 'deny',\n      },\n    };\n\n    this.logger.info('Launch options:', puppeteerLaunchOptions);\n\n    try {\n      this.browser = await puppeteer.launch(puppeteerLaunchOptions);\n      await this.setupPageListener();\n      this.logger.success('Browser launched successfully');\n    } catch (error) {\n      this.logger.error('Failed to launch browser:', error);\n      throw error;\n    }\n  }\n}","/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport * as puppeteer from 'puppeteer-core';\nimport { BaseBrowser, BaseBrowserOptions } from './base.js';\nimport { LaunchOptions } from './types.js';\n\n/**\n * Configuration options for RemoteBrowser\n * @extends BaseBrowserOptions\n * @interface RemoteBrowserOptions\n * @property {string} [wsEndpoint] - WebSocket endpoint URL for direct connection\n * @property {string} [host] - Remote host address (default: 'localhost')\n * @property {number} [port] - Remote debugging port (default: 9222)\n */\nexport interface RemoteBrowserOptions extends BaseBrowserOptions {\n  wsEndpoint?: string;\n  host?: string;\n  port?: number;\n}\n\n/**\n * RemoteBrowser class for connecting to remote browser instances\n *\n * Currently, this RemoteBrowser is not production ready,\n * mainly because it still relies on `puppeteer-core`,\n * which can only run on Node.js.\n *\n * At the same time, Chrome instances built with\n * `--remote-debugging-address` on Linux have security risks\n *\n * @see https://issues.chromium.org/issues/41487252\n * @see https://issues.chromium.org/issues/40261787\n * @see https://github.com/pyppeteer/pyppeteer/pull/379\n * @see https://stackoverflow.com/questions/72760355/chrome-remote-debugging-not-working-computer-to-computer\n *\n * @extends BaseBrowser\n */\nexport class RemoteBrowser extends BaseBrowser {\n  /**\n   * Creates a new RemoteBrowser instance\n   * @param {RemoteBrowserOptions} [options] - Configuration options for remote browser connection\n   */\n  constructor(private options?: RemoteBrowserOptions) {\n    super(options);\n  }\n\n  /**\n   * Connects to a remote browser instance using WebSocket\n   * If no WebSocket endpoint is provided, attempts to discover it using the DevTools Protocol\n   * @param {LaunchOptions} [options] - Launch configuration options\n   * @returns {Promise<void>} Promise that resolves when connected to the remote browser\n   * @throws {Error} If connection to the remote browser fails\n   */\n  async launch(options?: LaunchOptions): Promise<void> {\n    this.logger.info('Browser Launch options:', options);\n\n    let browserWSEndpoint = this.options?.wsEndpoint;\n\n    if (!browserWSEndpoint) {\n      const host = this.options?.host || 'localhost';\n      const port = this.options?.port || 9222;\n      const response = await fetch(`http://${host}:${port}/json/version`);\n      const { webSocketDebuggerUrl } = await response.json();\n      browserWSEndpoint = webSocketDebuggerUrl;\n    }\n\n    this.logger.info('Using WebSocket endpoint:', browserWSEndpoint);\n\n    const puppeteerConnectOptions: puppeteer.ConnectOptions = {\n      browserWSEndpoint,\n      defaultViewport: options?.defaultViewport ?? { width: 1280, height: 800 },\n    };\n\n    try {\n      this.browser = await puppeteer.connect(puppeteerConnectOptions);\n      await this.setupPageListener();\n      this.logger.success('Connected to remote browser successfully');\n    } catch (error) {\n      this.logger.error('Failed to connect to remote browser:', error);\n      throw error;\n    }\n  }\n}","/**\n * PLEASE DO NOT MODIFY IT as it is generated by the build script\n *\n * Build: scripts/build-readability.ts\n * Source: https://github.com/mozilla/readability/blob/main/Readability.js\n */\n\n/**\n * Copyright (c) 2010 Arc90 Inc\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const READABILITY_SCRIPT =\n  'function q(t,e){if(e&&e.documentElement)t=e,e=arguments[2];else if(!t||!t.documentElement)throw new Error(\"First argument to Readability constructor should be a document object.\");if(e=e||{},this._doc=t,this._docJSDOMParser=this._doc.firstChild.__JSDOMParser__,this._articleTitle=null,this._articleByline=null,this._articleDir=null,this._articleSiteName=null,this._attempts=[],this._debug=!!e.debug,this._maxElemsToParse=e.maxElemsToParse||this.DEFAULT_MAX_ELEMS_TO_PARSE,this._nbTopCandidates=e.nbTopCandidates||this.DEFAULT_N_TOP_CANDIDATES,this._charThreshold=e.charThreshold||this.DEFAULT_CHAR_THRESHOLD,this._classesToPreserve=this.CLASSES_TO_PRESERVE.concat(e.classesToPreserve||[]),this._keepClasses=!!e.keepClasses,this._serializer=e.serializer||function(i){return i.innerHTML},this._disableJSONLD=!!e.disableJSONLD,this._allowedVideoRegex=e.allowedVideoRegex||this.REGEXPS.videos,this._flags=this.FLAG_STRIP_UNLIKELYS|this.FLAG_WEIGHT_CLASSES|this.FLAG_CLEAN_CONDITIONALLY,this._debug){let i=function(r){if(r.nodeType==r.TEXT_NODE)return`${r.nodeName} (\"${r.textContent}\")`;let l=Array.from(r.attributes||[],function(a){return`${a.name}=\"${a.value}\"`}).join(\" \");return`<${r.localName} ${l}>`};this.log=function(){if(typeof console!=\"undefined\"){let l=Array.from(arguments,a=>a&&a.nodeType==this.ELEMENT_NODE?i(a):a);l.unshift(\"Reader: (Readability)\"),console.log.apply(console,l)}else if(typeof dump!=\"undefined\"){var r=Array.prototype.map.call(arguments,function(l){return l&&l.nodeName?i(l):l}).join(\" \");dump(\"Reader: (Readability) \"+r+`\\n`)}}}else this.log=function(){}}q.prototype={FLAG_STRIP_UNLIKELYS:1,FLAG_WEIGHT_CLASSES:2,FLAG_CLEAN_CONDITIONALLY:4,ELEMENT_NODE:1,TEXT_NODE:3,DEFAULT_MAX_ELEMS_TO_PARSE:0,DEFAULT_N_TOP_CANDIDATES:5,DEFAULT_TAGS_TO_SCORE:\"section,h2,h3,h4,h5,h6,p,td,pre\".toUpperCase().split(\",\"),DEFAULT_CHAR_THRESHOLD:500,REGEXPS:{unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i,positive:/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,negative:/-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,extraneous:/print|archive|comment|discuss|e[\\\\-]?mail|share|reply|all|login|sign|single|utility/i,byline:/byline|author|dateline|writtenby|p-author/i,replaceFonts:/<(\\\\/?)font[^>]*>/gi,normalize:/\\\\s{2,}/g,videos:/\\\\/\\\\/(www\\\\.)?((dailymotion|youtube|youtube-nocookie|player\\\\.vimeo|v\\\\.qq)\\\\.com|(archive|upload\\\\.wikimedia)\\\\.org|player\\\\.twitch\\\\.tv)/i,shareElements:/(\\\\b|_)(share|sharedaddy)(\\\\b|_)/i,nextLink:/(next|weiter|continue|>([^\\\\|]|$)|»([^\\\\|]|$))/i,prevLink:/(prev|earl|old|new|<|«)/i,tokenize:/\\\\W+/g,whitespace:/^\\\\s*$/,hasContent:/\\\\S$/,hashUrl:/^#.+/,srcsetUrl:/(\\\\S+)(\\\\s+[\\\\d.]+[xw])?(\\\\s*(?:,|$))/g,b64DataUrl:/^data:\\\\s*([^\\\\s;,]+)\\\\s*;\\\\s*base64\\\\s*,/i,commas:/\\\\u002C|\\\\u060C|\\\\uFE50|\\\\uFE10|\\\\uFE11|\\\\u2E41|\\\\u2E34|\\\\u2E32|\\\\uFF0C/g,jsonLdArticleTypes:/^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/},UNLIKELY_ROLES:[\"menu\",\"menubar\",\"complementary\",\"navigation\",\"alert\",\"alertdialog\",\"dialog\"],DIV_TO_P_ELEMS:new Set([\"BLOCKQUOTE\",\"DL\",\"DIV\",\"IMG\",\"OL\",\"P\",\"PRE\",\"TABLE\",\"UL\"]),ALTER_TO_DIV_EXCEPTIONS:[\"DIV\",\"ARTICLE\",\"SECTION\",\"P\"],PRESENTATIONAL_ATTRIBUTES:[\"align\",\"background\",\"bgcolor\",\"border\",\"cellpadding\",\"cellspacing\",\"frame\",\"hspace\",\"rules\",\"style\",\"valign\",\"vspace\"],DEPRECATED_SIZE_ATTRIBUTE_ELEMS:[\"TABLE\",\"TH\",\"TD\",\"HR\",\"PRE\"],PHRASING_ELEMS:[\"ABBR\",\"AUDIO\",\"B\",\"BDO\",\"BR\",\"BUTTON\",\"CITE\",\"CODE\",\"DATA\",\"DATALIST\",\"DFN\",\"EM\",\"EMBED\",\"I\",\"IMG\",\"INPUT\",\"KBD\",\"LABEL\",\"MARK\",\"MATH\",\"METER\",\"NOSCRIPT\",\"OBJECT\",\"OUTPUT\",\"PROGRESS\",\"Q\",\"RUBY\",\"SAMP\",\"SCRIPT\",\"SELECT\",\"SMALL\",\"SPAN\",\"STRONG\",\"SUB\",\"SUP\",\"TEXTAREA\",\"TIME\",\"VAR\",\"WBR\"],CLASSES_TO_PRESERVE:[\"page\"],HTML_ESCAPE_MAP:{lt:\"<\",gt:\">\",amp:\"&\",quot:\\'\"\\',apos:\"\\'\"},_postProcessContent:function(t){this._fixRelativeUris(t),this._simplifyNestedElements(t),this._keepClasses||this._cleanClasses(t)},_removeNodes:function(t,e){if(this._docJSDOMParser&&t._isLiveNodeList)throw new Error(\"Do not pass live node lists to _removeNodes\");for(var i=t.length-1;i>=0;i--){var r=t[i],l=r.parentNode;l&&(!e||e.call(this,r,i,t))&&l.removeChild(r)}},_replaceNodeTags:function(t,e){if(this._docJSDOMParser&&t._isLiveNodeList)throw new Error(\"Do not pass live node lists to _replaceNodeTags\");for(let i of t)this._setNodeTag(i,e)},_forEachNode:function(t,e){Array.prototype.forEach.call(t,e,this)},_findNode:function(t,e){return Array.prototype.find.call(t,e,this)},_someNode:function(t,e){return Array.prototype.some.call(t,e,this)},_everyNode:function(t,e){return Array.prototype.every.call(t,e,this)},_concatNodeLists:function(){var t=Array.prototype.slice,e=t.call(arguments),i=e.map(function(r){return t.call(r)});return Array.prototype.concat.apply([],i)},_getAllNodesWithTag:function(t,e){return t.querySelectorAll?t.querySelectorAll(e.join(\",\")):[].concat.apply([],e.map(function(i){var r=t.getElementsByTagName(i);return Array.isArray(r)?r:Array.from(r)}))},_cleanClasses:function(t){var e=this._classesToPreserve,i=(t.getAttribute(\"class\")||\"\").split(/\\\\s+/).filter(function(r){return e.indexOf(r)!=-1}).join(\" \");for(i?t.setAttribute(\"class\",i):t.removeAttribute(\"class\"),t=t.firstElementChild;t;t=t.nextElementSibling)this._cleanClasses(t)},_fixRelativeUris:function(t){var e=this._doc.baseURI,i=this._doc.documentURI;function r(s){if(e==i&&s.charAt(0)==\"#\")return s;try{return new URL(s,e).href}catch(h){}return s}var l=this._getAllNodesWithTag(t,[\"a\"]);this._forEachNode(l,function(s){var h=s.getAttribute(\"href\");if(h)if(h.indexOf(\"javascript:\")===0)if(s.childNodes.length===1&&s.childNodes[0].nodeType===this.TEXT_NODE){var c=this._doc.createTextNode(s.textContent);s.parentNode.replaceChild(c,s)}else{for(var n=this._doc.createElement(\"span\");s.firstChild;)n.appendChild(s.firstChild);s.parentNode.replaceChild(n,s)}else s.setAttribute(\"href\",r(h))});var a=this._getAllNodesWithTag(t,[\"img\",\"picture\",\"figure\",\"video\",\"audio\",\"source\"]);this._forEachNode(a,function(s){var h=s.getAttribute(\"src\"),c=s.getAttribute(\"poster\"),n=s.getAttribute(\"srcset\");if(h&&s.setAttribute(\"src\",r(h)),c&&s.setAttribute(\"poster\",r(c)),n){var u=n.replace(this.REGEXPS.srcsetUrl,function(m,b,N,v){return r(b)+(N||\"\")+v});s.setAttribute(\"srcset\",u)}})},_simplifyNestedElements:function(t){for(var e=t;e;){if(e.parentNode&&[\"DIV\",\"SECTION\"].includes(e.tagName)&&!(e.id&&e.id.startsWith(\"readability\"))){if(this._isElementWithoutContent(e)){e=this._removeAndGetNext(e);continue}else if(this._hasSingleTagInsideElement(e,\"DIV\")||this._hasSingleTagInsideElement(e,\"SECTION\")){for(var i=e.children[0],r=0;r<e.attributes.length;r++)i.setAttribute(e.attributes[r].name,e.attributes[r].value);e.parentNode.replaceChild(i,e),e=i;continue}}e=this._getNextNode(e)}},_getArticleTitle:function(){var t=this._doc,e=\"\",i=\"\";try{e=i=t.title.trim(),typeof e!=\"string\"&&(e=i=this._getInnerText(t.getElementsByTagName(\"title\")[0]))}catch(u){}var r=!1;function l(u){return u.split(/\\\\s+/).length}if(/ [\\\\|\\\\-\\\\\\\\\\\\/>»] /.test(e))r=/ [\\\\\\\\\\\\/>»] /.test(e),e=i.replace(/(.*)[\\\\|\\\\-\\\\\\\\\\\\/>»] .*/gi,\"$1\"),l(e)<3&&(e=i.replace(/[^\\\\|\\\\-\\\\\\\\\\\\/>»]*[\\\\|\\\\-\\\\\\\\\\\\/>»](.*)/gi,\"$1\"));else if(e.indexOf(\": \")!==-1){var a=this._concatNodeLists(t.getElementsByTagName(\"h1\"),t.getElementsByTagName(\"h2\")),s=e.trim(),h=this._someNode(a,function(u){return u.textContent.trim()===s});h||(e=i.substring(i.lastIndexOf(\":\")+1),l(e)<3?e=i.substring(i.indexOf(\":\")+1):l(i.substr(0,i.indexOf(\":\")))>5&&(e=i))}else if(e.length>150||e.length<15){var c=t.getElementsByTagName(\"h1\");c.length===1&&(e=this._getInnerText(c[0]))}e=e.trim().replace(this.REGEXPS.normalize,\" \");var n=l(e);return n<=4&&(!r||n!=l(i.replace(/[\\\\|\\\\-\\\\\\\\\\\\/>»]+/g,\"\"))-1)&&(e=i),e},_prepDocument:function(){var t=this._doc;this._removeNodes(this._getAllNodesWithTag(t,[\"style\"])),t.body&&this._replaceBrs(t.body),this._replaceNodeTags(this._getAllNodesWithTag(t,[\"font\"]),\"SPAN\")},_nextNode:function(t){for(var e=t;e&&e.nodeType!=this.ELEMENT_NODE&&this.REGEXPS.whitespace.test(e.textContent);)e=e.nextSibling;return e},_replaceBrs:function(t){this._forEachNode(this._getAllNodesWithTag(t,[\"br\"]),function(e){for(var i=e.nextSibling,r=!1;(i=this._nextNode(i))&&i.tagName==\"BR\";){r=!0;var l=i.nextSibling;i.parentNode.removeChild(i),i=l}if(r){var a=this._doc.createElement(\"p\");for(e.parentNode.replaceChild(a,e),i=a.nextSibling;i;){if(i.tagName==\"BR\"){var s=this._nextNode(i.nextSibling);if(s&&s.tagName==\"BR\")break}if(!this._isPhrasingContent(i))break;var h=i.nextSibling;a.appendChild(i),i=h}for(;a.lastChild&&this._isWhitespace(a.lastChild);)a.removeChild(a.lastChild);a.parentNode.tagName===\"P\"&&this._setNodeTag(a.parentNode,\"DIV\")}})},_setNodeTag:function(t,e){if(this.log(\"_setNodeTag\",t,e),this._docJSDOMParser)return t.localName=e.toLowerCase(),t.tagName=e.toUpperCase(),t;for(var i=t.ownerDocument.createElement(e);t.firstChild;)i.appendChild(t.firstChild);t.parentNode.replaceChild(i,t),t.readability&&(i.readability=t.readability);for(var r=0;r<t.attributes.length;r++)try{i.setAttribute(t.attributes[r].name,t.attributes[r].value)}catch(l){}return i},_prepArticle:function(t){this._cleanStyles(t),this._markDataTables(t),this._fixLazyImages(t),this._cleanConditionally(t,\"form\"),this._cleanConditionally(t,\"fieldset\"),this._clean(t,\"object\"),this._clean(t,\"embed\"),this._clean(t,\"footer\"),this._clean(t,\"link\"),this._clean(t,\"aside\");var e=this.DEFAULT_CHAR_THRESHOLD;this._forEachNode(t.children,function(i){this._cleanMatchedNodes(i,function(r,l){return this.REGEXPS.shareElements.test(l)&&r.textContent.length<e})}),this._clean(t,\"iframe\"),this._clean(t,\"input\"),this._clean(t,\"textarea\"),this._clean(t,\"select\"),this._clean(t,\"button\"),this._cleanHeaders(t),this._cleanConditionally(t,\"table\"),this._cleanConditionally(t,\"ul\"),this._cleanConditionally(t,\"div\"),this._replaceNodeTags(this._getAllNodesWithTag(t,[\"h1\"]),\"h2\"),this._removeNodes(this._getAllNodesWithTag(t,[\"p\"]),function(i){var r=i.getElementsByTagName(\"img\").length,l=i.getElementsByTagName(\"embed\").length,a=i.getElementsByTagName(\"object\").length,s=i.getElementsByTagName(\"iframe\").length,h=r+l+a+s;return h===0&&!this._getInnerText(i,!1)}),this._forEachNode(this._getAllNodesWithTag(t,[\"br\"]),function(i){var r=this._nextNode(i.nextSibling);r&&r.tagName==\"P\"&&i.parentNode.removeChild(i)}),this._forEachNode(this._getAllNodesWithTag(t,[\"table\"]),function(i){var r=this._hasSingleTagInsideElement(i,\"TBODY\")?i.firstElementChild:i;if(this._hasSingleTagInsideElement(r,\"TR\")){var l=r.firstElementChild;if(this._hasSingleTagInsideElement(l,\"TD\")){var a=l.firstElementChild;a=this._setNodeTag(a,this._everyNode(a.childNodes,this._isPhrasingContent)?\"P\":\"DIV\"),i.parentNode.replaceChild(a,i)}}})},_initializeNode:function(t){switch(t.readability={contentScore:0},t.tagName){case\"DIV\":t.readability.contentScore+=5;break;case\"PRE\":case\"TD\":case\"BLOCKQUOTE\":t.readability.contentScore+=3;break;case\"ADDRESS\":case\"OL\":case\"UL\":case\"DL\":case\"DD\":case\"DT\":case\"LI\":case\"FORM\":t.readability.contentScore-=3;break;case\"H1\":case\"H2\":case\"H3\":case\"H4\":case\"H5\":case\"H6\":case\"TH\":t.readability.contentScore-=5;break}t.readability.contentScore+=this._getClassWeight(t)},_removeAndGetNext:function(t){var e=this._getNextNode(t,!0);return t.parentNode.removeChild(t),e},_getNextNode:function(t,e){if(!e&&t.firstElementChild)return t.firstElementChild;if(t.nextElementSibling)return t.nextElementSibling;do t=t.parentNode;while(t&&!t.nextElementSibling);return t&&t.nextElementSibling},_textSimilarity:function(t,e){var i=t.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean),r=e.toLowerCase().split(this.REGEXPS.tokenize).filter(Boolean);if(!i.length||!r.length)return 0;var l=r.filter(s=>!i.includes(s)),a=l.join(\" \").length/r.join(\" \").length;return 1-a},_checkByline:function(t,e){if(this._articleByline)return!1;if(t.getAttribute!==void 0)var i=t.getAttribute(\"rel\"),r=t.getAttribute(\"itemprop\");return(i===\"author\"||r&&r.indexOf(\"author\")!==-1||this.REGEXPS.byline.test(e))&&this._isValidByline(t.textContent)?(this._articleByline=t.textContent.trim(),!0):!1},_getNodeAncestors:function(t,e){e=e||0;for(var i=0,r=[];t.parentNode&&(r.push(t.parentNode),!(e&&++i===e));)t=t.parentNode;return r},_grabArticle:function(t){this.log(\"**** grabArticle ****\");var e=this._doc,i=t!==null;if(t=t||this._doc.body,!t)return this.log(\"No body found in document. Abort.\"),null;for(var r=t.innerHTML;;){this.log(\"Starting grabArticle loop\");var l=this._flagIsActive(this.FLAG_STRIP_UNLIKELYS),a=[],s=this._doc.documentElement;let J=!0;for(;s;){s.tagName===\"HTML\"&&(this._articleLang=s.getAttribute(\"lang\"));var h=s.className+\" \"+s.id;if(!this._isProbablyVisible(s)){this.log(\"Removing hidden node - \"+h),s=this._removeAndGetNext(s);continue}if(s.getAttribute(\"aria-modal\")==\"true\"&&s.getAttribute(\"role\")==\"dialog\"){s=this._removeAndGetNext(s);continue}if(this._checkByline(s,h)){s=this._removeAndGetNext(s);continue}if(J&&this._headerDuplicatesTitle(s)){this.log(\"Removing header: \",s.textContent.trim(),this._articleTitle.trim()),J=!1,s=this._removeAndGetNext(s);continue}if(l){if(this.REGEXPS.unlikelyCandidates.test(h)&&!this.REGEXPS.okMaybeItsACandidate.test(h)&&!this._hasAncestorTag(s,\"table\")&&!this._hasAncestorTag(s,\"code\")&&s.tagName!==\"BODY\"&&s.tagName!==\"A\"){this.log(\"Removing unlikely candidate - \"+h),s=this._removeAndGetNext(s);continue}if(this.UNLIKELY_ROLES.includes(s.getAttribute(\"role\"))){this.log(\"Removing content with role \"+s.getAttribute(\"role\")+\" - \"+h),s=this._removeAndGetNext(s);continue}}if((s.tagName===\"DIV\"||s.tagName===\"SECTION\"||s.tagName===\"HEADER\"||s.tagName===\"H1\"||s.tagName===\"H2\"||s.tagName===\"H3\"||s.tagName===\"H4\"||s.tagName===\"H5\"||s.tagName===\"H6\")&&this._isElementWithoutContent(s)){s=this._removeAndGetNext(s);continue}if(this.DEFAULT_TAGS_TO_SCORE.indexOf(s.tagName)!==-1&&a.push(s),s.tagName===\"DIV\"){for(var c=null,n=s.firstChild;n;){var u=n.nextSibling;if(this._isPhrasingContent(n))c!==null?c.appendChild(n):this._isWhitespace(n)||(c=e.createElement(\"p\"),s.replaceChild(c,n),c.appendChild(n));else if(c!==null){for(;c.lastChild&&this._isWhitespace(c.lastChild);)c.removeChild(c.lastChild);c=null}n=u}if(this._hasSingleTagInsideElement(s,\"P\")&&this._getLinkDensity(s)<.25){var m=s.children[0];s.parentNode.replaceChild(m,s),s=m,a.push(s)}else this._hasChildBlockElement(s)||(s=this._setNodeTag(s,\"P\"),a.push(s))}s=this._getNextNode(s)}var b=[];this._forEachNode(a,function(A){if(!(!A.parentNode||typeof A.parentNode.tagName==\"undefined\")){var T=this._getInnerText(A);if(!(T.length<25)){var K=this._getNodeAncestors(A,5);if(K.length!==0){var C=0;C+=1,C+=T.split(this.REGEXPS.commas).length,C+=Math.min(Math.floor(T.length/100),3),this._forEachNode(K,function(S,F){if(!(!S.tagName||!S.parentNode||typeof S.parentNode.tagName==\"undefined\")){if(typeof S.readability==\"undefined\"&&(this._initializeNode(S),b.push(S)),F===0)var X=1;else F===1?X=2:X=F*3;S.readability.contentScore+=C/X}})}}}});for(var N=[],v=0,y=b.length;v<y;v+=1){var E=b[v],d=E.readability.contentScore*(1-this._getLinkDensity(E));E.readability.contentScore=d,this.log(\"Candidate:\",E,\"with score \"+d);for(var p=0;p<this._nbTopCandidates;p++){var x=N[p];if(!x||d>x.readability.contentScore){N.splice(p,0,E),N.length>this._nbTopCandidates&&N.pop();break}}}var o=N[0]||null,L=!1,g;if(o===null||o.tagName===\"BODY\"){for(o=e.createElement(\"DIV\"),L=!0;t.firstChild;)this.log(\"Moving child out:\",t.firstChild),o.appendChild(t.firstChild);t.appendChild(o),this._initializeNode(o)}else if(o){for(var I=[],P=1;P<N.length;P++)N[P].readability.contentScore/o.readability.contentScore>=.75&&I.push(this._getNodeAncestors(N[P]));var O=3;if(I.length>=O)for(g=o.parentNode;g.tagName!==\"BODY\";){for(var G=0,H=0;H<I.length&&G<O;H++)G+=Number(I[H].includes(g));if(G>=O){o=g;break}g=g.parentNode}o.readability||this._initializeNode(o),g=o.parentNode;for(var M=o.readability.contentScore,Q=M/3;g.tagName!==\"BODY\";){if(!g.readability){g=g.parentNode;continue}var V=g.readability.contentScore;if(V<Q)break;if(V>M){o=g;break}M=g.readability.contentScore,g=g.parentNode}for(g=o.parentNode;g.tagName!=\"BODY\"&&g.children.length==1;)o=g,g=o.parentNode;o.readability||this._initializeNode(o)}var _=e.createElement(\"DIV\");i&&(_.id=\"readability-content\");var Z=Math.max(10,o.readability.contentScore*.2);g=o.parentNode;for(var U=g.children,w=0,j=U.length;w<j;w++){var f=U[w],R=!1;if(this.log(\"Looking at sibling node:\",f,f.readability?\"with score \"+f.readability.contentScore:\"\"),this.log(\"Sibling has score\",f.readability?f.readability.contentScore:\"Unknown\"),f===o)R=!0;else{var $=0;if(f.className===o.className&&o.className!==\"\"&&($+=o.readability.contentScore*.2),f.readability&&f.readability.contentScore+$>=Z)R=!0;else if(f.nodeName===\"P\"){var Y=this._getLinkDensity(f),z=this._getInnerText(f),k=z.length;(k>80&&Y<.25||k<80&&k>0&&Y===0&&z.search(/\\\\.( |$)/)!==-1)&&(R=!0)}}R&&(this.log(\"Appending node:\",f),this.ALTER_TO_DIV_EXCEPTIONS.indexOf(f.nodeName)===-1&&(this.log(\"Altering sibling:\",f,\"to div.\"),f=this._setNodeTag(f,\"DIV\")),_.appendChild(f),U=g.children,w-=1,j-=1)}if(this._debug&&this.log(\"Article content pre-prep: \"+_.innerHTML),this._prepArticle(_),this._debug&&this.log(\"Article content post-prep: \"+_.innerHTML),L)o.id=\"readability-page-1\",o.className=\"page\";else{var B=e.createElement(\"DIV\");for(B.id=\"readability-page-1\",B.className=\"page\";_.firstChild;)B.appendChild(_.firstChild);_.appendChild(B)}this._debug&&this.log(\"Article content after paging: \"+_.innerHTML);var W=!0,D=this._getInnerText(_,!0).length;if(D<this._charThreshold)if(W=!1,t.innerHTML=r,this._flagIsActive(this.FLAG_STRIP_UNLIKELYS))this._removeFlag(this.FLAG_STRIP_UNLIKELYS),this._attempts.push({articleContent:_,textLength:D});else if(this._flagIsActive(this.FLAG_WEIGHT_CLASSES))this._removeFlag(this.FLAG_WEIGHT_CLASSES),this._attempts.push({articleContent:_,textLength:D});else if(this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY))this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY),this._attempts.push({articleContent:_,textLength:D});else{if(this._attempts.push({articleContent:_,textLength:D}),this._attempts.sort(function(A,T){return T.textLength-A.textLength}),!this._attempts[0].textLength)return null;_=this._attempts[0].articleContent,W=!0}if(W){var tt=[g,o].concat(this._getNodeAncestors(g));return this._someNode(tt,function(A){if(!A.tagName)return!1;var T=A.getAttribute(\"dir\");return T?(this._articleDir=T,!0):!1}),_}}},_isValidByline:function(t){return typeof t==\"string\"||t instanceof String?(t=t.trim(),t.length>0&&t.length<100):!1},_unescapeHtmlEntities:function(t){if(!t)return t;var e=this.HTML_ESCAPE_MAP;return t.replace(/&(quot|amp|apos|lt|gt);/g,function(i,r){return e[r]}).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi,function(i,r,l){var a=parseInt(r||l,r?16:10);return String.fromCharCode(a)})},_getJSONLD:function(t){var e=this._getAllNodesWithTag(t,[\"script\"]),i;return this._forEachNode(e,function(r){if(!i&&r.getAttribute(\"type\")===\"application/ld+json\")try{var l=r.textContent.replace(/^\\\\s*<!\\\\[CDATA\\\\[|\\\\]\\\\]>\\\\s*$/g,\"\"),a=JSON.parse(l);if(!a[\"@context\"]||!a[\"@context\"].match(/^https?\\\\:\\\\/\\\\/schema\\\\.org$/)||(!a[\"@type\"]&&Array.isArray(a[\"@graph\"])&&(a=a[\"@graph\"].find(function(n){return(n[\"@type\"]||\"\").match(this.REGEXPS.jsonLdArticleTypes)})),!a||!a[\"@type\"]||!a[\"@type\"].match(this.REGEXPS.jsonLdArticleTypes)))return;if(i={},typeof a.name==\"string\"&&typeof a.headline==\"string\"&&a.name!==a.headline){var s=this._getArticleTitle(),h=this._textSimilarity(a.name,s)>.75,c=this._textSimilarity(a.headline,s)>.75;c&&!h?i.title=a.headline:i.title=a.name}else typeof a.name==\"string\"?i.title=a.name.trim():typeof a.headline==\"string\"&&(i.title=a.headline.trim());a.author&&(typeof a.author.name==\"string\"?i.byline=a.author.name.trim():Array.isArray(a.author)&&a.author[0]&&typeof a.author[0].name==\"string\"&&(i.byline=a.author.filter(function(n){return n&&typeof n.name==\"string\"}).map(function(n){return n.name.trim()}).join(\", \"))),typeof a.description==\"string\"&&(i.excerpt=a.description.trim()),a.publisher&&typeof a.publisher.name==\"string\"&&(i.siteName=a.publisher.name.trim()),typeof a.datePublished==\"string\"&&(i.datePublished=a.datePublished.trim());return}catch(n){this.log(n.message)}}),i||{}},_getArticleMetadata:function(t){var e={},i={},r=this._doc.getElementsByTagName(\"meta\"),l=/\\\\s*(article|dc|dcterm|og|twitter)\\\\s*:\\\\s*(author|creator|description|published_time|title|site_name)\\\\s*/gi,a=/^\\\\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\\\\s*[\\\\.:]\\\\s*)?(author|creator|description|title|site_name)\\\\s*$/i;return this._forEachNode(r,function(s){var h=s.getAttribute(\"name\"),c=s.getAttribute(\"property\"),n=s.getAttribute(\"content\");if(n){var u=null,m=null;c&&(u=c.match(l),u&&(m=u[0].toLowerCase().replace(/\\\\s/g,\"\"),i[m]=n.trim())),!u&&h&&a.test(h)&&(m=h,n&&(m=m.toLowerCase().replace(/\\\\s/g,\"\").replace(/\\\\./g,\":\"),i[m]=n.trim()))}}),e.title=t.title||i[\"dc:title\"]||i[\"dcterm:title\"]||i[\"og:title\"]||i[\"weibo:article:title\"]||i[\"weibo:webpage:title\"]||i.title||i[\"twitter:title\"],e.title||(e.title=this._getArticleTitle()),e.byline=t.byline||i[\"dc:creator\"]||i[\"dcterm:creator\"]||i.author,e.excerpt=t.excerpt||i[\"dc:description\"]||i[\"dcterm:description\"]||i[\"og:description\"]||i[\"weibo:article:description\"]||i[\"weibo:webpage:description\"]||i.description||i[\"twitter:description\"],e.siteName=t.siteName||i[\"og:site_name\"],e.publishedTime=t.datePublished||i[\"article:published_time\"]||null,e.title=this._unescapeHtmlEntities(e.title),e.byline=this._unescapeHtmlEntities(e.byline),e.excerpt=this._unescapeHtmlEntities(e.excerpt),e.siteName=this._unescapeHtmlEntities(e.siteName),e.publishedTime=this._unescapeHtmlEntities(e.publishedTime),e},_isSingleImage:function(t){return t.tagName===\"IMG\"?!0:t.children.length!==1||t.textContent.trim()!==\"\"?!1:this._isSingleImage(t.children[0])},_unwrapNoscriptImages:function(t){var e=Array.from(t.getElementsByTagName(\"img\"));this._forEachNode(e,function(r){for(var l=0;l<r.attributes.length;l++){var a=r.attributes[l];switch(a.name){case\"src\":case\"srcset\":case\"data-src\":case\"data-srcset\":return}if(/\\\\.(jpg|jpeg|png|webp)/i.test(a.value))return}r.parentNode.removeChild(r)});var i=Array.from(t.getElementsByTagName(\"noscript\"));this._forEachNode(i,function(r){var l=t.createElement(\"div\");if(l.innerHTML=r.innerHTML,!!this._isSingleImage(l)){var a=r.previousElementSibling;if(a&&this._isSingleImage(a)){var s=a;s.tagName!==\"IMG\"&&(s=a.getElementsByTagName(\"img\")[0]);for(var h=l.getElementsByTagName(\"img\")[0],c=0;c<s.attributes.length;c++){var n=s.attributes[c];if(n.value!==\"\"&&(n.name===\"src\"||n.name===\"srcset\"||/\\\\.(jpg|jpeg|png|webp)/i.test(n.value))){if(h.getAttribute(n.name)===n.value)continue;var u=n.name;h.hasAttribute(u)&&(u=\"data-old-\"+u),h.setAttribute(u,n.value)}}r.parentNode.replaceChild(l.firstElementChild,a)}}})},_removeScripts:function(t){this._removeNodes(this._getAllNodesWithTag(t,[\"script\",\"noscript\"]))},_hasSingleTagInsideElement:function(t,e){return t.children.length!=1||t.children[0].tagName!==e?!1:!this._someNode(t.childNodes,function(i){return i.nodeType===this.TEXT_NODE&&this.REGEXPS.hasContent.test(i.textContent)})},_isElementWithoutContent:function(t){return t.nodeType===this.ELEMENT_NODE&&t.textContent.trim().length==0&&(t.children.length==0||t.children.length==t.getElementsByTagName(\"br\").length+t.getElementsByTagName(\"hr\").length)},_hasChildBlockElement:function(t){return this._someNode(t.childNodes,function(e){return this.DIV_TO_P_ELEMS.has(e.tagName)||this._hasChildBlockElement(e)})},_isPhrasingContent:function(t){return t.nodeType===this.TEXT_NODE||this.PHRASING_ELEMS.indexOf(t.tagName)!==-1||(t.tagName===\"A\"||t.tagName===\"DEL\"||t.tagName===\"INS\")&&this._everyNode(t.childNodes,this._isPhrasingContent)},_isWhitespace:function(t){return t.nodeType===this.TEXT_NODE&&t.textContent.trim().length===0||t.nodeType===this.ELEMENT_NODE&&t.tagName===\"BR\"},_getInnerText:function(t,e){e=typeof e==\"undefined\"?!0:e;var i=t.textContent.trim();return e?i.replace(this.REGEXPS.normalize,\" \"):i},_getCharCount:function(t,e){return e=e||\",\",this._getInnerText(t).split(e).length-1},_cleanStyles:function(t){if(!(!t||t.tagName.toLowerCase()===\"svg\")){for(var e=0;e<this.PRESENTATIONAL_ATTRIBUTES.length;e++)t.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[e]);this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(t.tagName)!==-1&&(t.removeAttribute(\"width\"),t.removeAttribute(\"height\"));for(var i=t.firstElementChild;i!==null;)this._cleanStyles(i),i=i.nextElementSibling}},_getLinkDensity:function(t){var e=this._getInnerText(t).length;if(e===0)return 0;var i=0;return this._forEachNode(t.getElementsByTagName(\"a\"),function(r){var l=r.getAttribute(\"href\"),a=l&&this.REGEXPS.hashUrl.test(l)?.3:1;i+=this._getInnerText(r).length*a}),i/e},_getClassWeight:function(t){if(!this._flagIsActive(this.FLAG_WEIGHT_CLASSES))return 0;var e=0;return typeof t.className==\"string\"&&t.className!==\"\"&&(this.REGEXPS.negative.test(t.className)&&(e-=25),this.REGEXPS.positive.test(t.className)&&(e+=25)),typeof t.id==\"string\"&&t.id!==\"\"&&(this.REGEXPS.negative.test(t.id)&&(e-=25),this.REGEXPS.positive.test(t.id)&&(e+=25)),e},_clean:function(t,e){var i=[\"object\",\"embed\",\"iframe\"].indexOf(e)!==-1;this._removeNodes(this._getAllNodesWithTag(t,[e]),function(r){if(i){for(var l=0;l<r.attributes.length;l++)if(this._allowedVideoRegex.test(r.attributes[l].value))return!1;if(r.tagName===\"object\"&&this._allowedVideoRegex.test(r.innerHTML))return!1}return!0})},_hasAncestorTag:function(t,e,i,r){i=i||3,e=e.toUpperCase();for(var l=0;t.parentNode;){if(i>0&&l>i)return!1;if(t.parentNode.tagName===e&&(!r||r(t.parentNode)))return!0;t=t.parentNode,l++}return!1},_getRowAndColumnCount:function(t){for(var e=0,i=0,r=t.getElementsByTagName(\"tr\"),l=0;l<r.length;l++){var a=r[l].getAttribute(\"rowspan\")||0;a&&(a=parseInt(a,10)),e+=a||1;for(var s=0,h=r[l].getElementsByTagName(\"td\"),c=0;c<h.length;c++){var n=h[c].getAttribute(\"colspan\")||0;n&&(n=parseInt(n,10)),s+=n||1}i=Math.max(i,s)}return{rows:e,columns:i}},_markDataTables:function(t){for(var e=t.getElementsByTagName(\"table\"),i=0;i<e.length;i++){var r=e[i],l=r.getAttribute(\"role\");if(l==\"presentation\"){r._readabilityDataTable=!1;continue}var a=r.getAttribute(\"datatable\");if(a==\"0\"){r._readabilityDataTable=!1;continue}var s=r.getAttribute(\"summary\");if(s){r._readabilityDataTable=!0;continue}var h=r.getElementsByTagName(\"caption\")[0];if(h&&h.childNodes.length>0){r._readabilityDataTable=!0;continue}var c=[\"col\",\"colgroup\",\"tfoot\",\"thead\",\"th\"],n=function(m){return!!r.getElementsByTagName(m)[0]};if(c.some(n)){this.log(\"Data table because found data-y descendant\"),r._readabilityDataTable=!0;continue}if(r.getElementsByTagName(\"table\")[0]){r._readabilityDataTable=!1;continue}var u=this._getRowAndColumnCount(r);if(u.rows>=10||u.columns>4){r._readabilityDataTable=!0;continue}r._readabilityDataTable=u.rows*u.columns>10}},_fixLazyImages:function(t){this._forEachNode(this._getAllNodesWithTag(t,[\"img\",\"picture\",\"figure\"]),function(e){if(e.src&&this.REGEXPS.b64DataUrl.test(e.src)){var i=this.REGEXPS.b64DataUrl.exec(e.src);if(i[1]===\"image/svg+xml\")return;for(var r=!1,l=0;l<e.attributes.length;l++){var a=e.attributes[l];if(a.name!==\"src\"&&/\\\\.(jpg|jpeg|png|webp)/i.test(a.value)){r=!0;break}}if(r){var s=e.src.search(/base64\\\\s*/i)+7,h=e.src.length-s;h<133&&e.removeAttribute(\"src\")}}if(!((e.src||e.srcset&&e.srcset!=\"null\")&&e.className.toLowerCase().indexOf(\"lazy\")===-1)){for(var c=0;c<e.attributes.length;c++)if(a=e.attributes[c],!(a.name===\"src\"||a.name===\"srcset\"||a.name===\"alt\")){var n=null;if(/\\\\.(jpg|jpeg|png|webp)\\\\s+\\\\d/.test(a.value)?n=\"srcset\":/^\\\\s*\\\\S+\\\\.(jpg|jpeg|png|webp)\\\\S*\\\\s*$/.test(a.value)&&(n=\"src\"),n){if(e.tagName===\"IMG\"||e.tagName===\"PICTURE\")e.setAttribute(n,a.value);else if(e.tagName===\"FIGURE\"&&!this._getAllNodesWithTag(e,[\"img\",\"picture\"]).length){var u=this._doc.createElement(\"img\");u.setAttribute(n,a.value),e.appendChild(u)}}}}})},_getTextDensity:function(t,e){var i=this._getInnerText(t,!0).length;if(i===0)return 0;var r=0,l=this._getAllNodesWithTag(t,e);return this._forEachNode(l,a=>r+=this._getInnerText(a,!0).length),r/i},_cleanConditionally:function(t,e){this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)&&this._removeNodes(this._getAllNodesWithTag(t,[e]),function(i){var r=function(g){return g._readabilityDataTable},l=e===\"ul\"||e===\"ol\";if(!l){var a=0,s=this._getAllNodesWithTag(i,[\"ul\",\"ol\"]);this._forEachNode(s,g=>a+=this._getInnerText(g).length),l=a/this._getInnerText(i).length>.9}if(e===\"table\"&&r(i)||this._hasAncestorTag(i,\"table\",-1,r)||this._hasAncestorTag(i,\"code\"))return!1;var h=this._getClassWeight(i);this.log(\"Cleaning Conditionally\",i);var c=0;if(h+c<0)return!0;if(this._getCharCount(i,\",\")<10){for(var n=i.getElementsByTagName(\"p\").length,u=i.getElementsByTagName(\"img\").length,m=i.getElementsByTagName(\"li\").length-100,b=i.getElementsByTagName(\"input\").length,N=this._getTextDensity(i,[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]),v=0,y=this._getAllNodesWithTag(i,[\"object\",\"embed\",\"iframe\"]),E=0;E<y.length;E++){for(var d=0;d<y[E].attributes.length;d++)if(this._allowedVideoRegex.test(y[E].attributes[d].value))return!1;if(y[E].tagName===\"object\"&&this._allowedVideoRegex.test(y[E].innerHTML))return!1;v++}var p=this._getLinkDensity(i),x=this._getInnerText(i).length,o=u>1&&n/u<.5&&!this._hasAncestorTag(i,\"figure\")||!l&&m>n||b>Math.floor(n/3)||!l&&N<.9&&x<25&&(u===0||u>2)&&!this._hasAncestorTag(i,\"figure\")||!l&&h<25&&p>.2||h>=25&&p>.5||v===1&&x<75||v>1;if(l&&o){for(var L=0;L<i.children.length;L++)if(i.children[L].children.length>1)return o;let g=i.getElementsByTagName(\"li\").length;if(u==g)return!1}return o}return!1})},_cleanMatchedNodes:function(t,e){for(var i=this._getNextNode(t,!0),r=this._getNextNode(t);r&&r!=i;)e.call(this,r,r.className+\" \"+r.id)?r=this._removeAndGetNext(r):r=this._getNextNode(r)},_cleanHeaders:function(t){let e=this._getAllNodesWithTag(t,[\"h1\",\"h2\"]);this._removeNodes(e,function(i){let r=this._getClassWeight(i)<0;return r&&this.log(\"Removing header with low class weight:\",i),r})},_headerDuplicatesTitle:function(t){if(t.tagName!=\"H1\"&&t.tagName!=\"H2\")return!1;var e=this._getInnerText(t,!1);return this.log(\"Evaluating similarity of header:\",e,this._articleTitle),this._textSimilarity(this._articleTitle,e)>.75},_flagIsActive:function(t){return(this._flags&t)>0},_removeFlag:function(t){this._flags=this._flags&~t},_isProbablyVisible:function(t){return(!t.style||t.style.display!=\"none\")&&(!t.style||t.style.visibility!=\"hidden\")&&!t.hasAttribute(\"hidden\")&&(!t.hasAttribute(\"aria-hidden\")||t.getAttribute(\"aria-hidden\")!=\"true\"||t.className&&t.className.indexOf&&t.className.indexOf(\"fallback-image\")!==-1)},parse:function(){if(this._maxElemsToParse>0){var t=this._doc.getElementsByTagName(\"*\").length;if(t>this._maxElemsToParse)throw new Error(\"Aborting parsing document; \"+t+\" elements found\")}this._unwrapNoscriptImages(this._doc);var e=this._disableJSONLD?{}:this._getJSONLD(this._doc);this._removeScripts(this._doc),this._prepDocument();var i=this._getArticleMetadata(e);this._articleTitle=i.title;var r=this._grabArticle();if(!r)return null;if(this.log(\"Grabbed: \"+r.innerHTML),this._postProcessContent(r),!i.excerpt){var l=r.getElementsByTagName(\"p\");l.length>0&&(i.excerpt=l[0].textContent.trim())}var a=r.textContent;return{title:this._articleTitle,byline:i.byline||this._articleByline,dir:this._articleDir,lang:this._articleLang,content:this._serializer(r),textContent:a,length:a.length,excerpt:i.excerpt,siteName:i.siteName||this._articleSiteName,publishedTime:i.publishedTime}}};typeof module==\"object\"&&(module.exports=q);\\n';","/**\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { LocalBrowser, type BrowserInterface } from '../browser/index.js';\nimport { READABILITY_SCRIPT } from './readability.js';\nimport { Logger, defaultLogger } from '@agent-infra/logger';\nimport {\n  extractPageInformation,\n  toMarkdown,\n} from './utils.js';\nimport { PromiseQueue } from './queue.js';\nimport { shouldSkipDomain, interceptRequest } from './utils.js';\nimport { getSearchEngine } from './engines/index.js';\nimport type {\n  SearchResult,\n  BrowserSearchOptions,\n  BrowserSearchConfig,\n  LocalBrowserSearchEngine,\n} from './types.js';\n\n/**\n * Service class for performing web searches and content extraction\n */\nexport class BrowserSearch {\n  private logger: Logger;\n  private browser: BrowserInterface;\n  private isBrowserOpen = false;\n  private defaultEngine: LocalBrowserSearchEngine;\n\n  constructor(private config: BrowserSearchConfig = {}) {\n    this.logger = config?.logger ?? defaultLogger;\n    this.browser = config.browser ?? new LocalBrowser({ logger: this.logger });\n    this.defaultEngine = config.defaultEngine ?? 'bing';\n  }\n\n  /**\n   * Search web and extract content from result pages\n   */\n  async perform(options: BrowserSearchOptions) {\n    this.logger.info('Starting search with options:', options);\n\n    const queries = Array.isArray(options.query)\n      ? options.query\n      : [options.query];\n    const excludeDomains = options.excludeDomains || [];\n    const count =\n      options.count && Math.max(3, Math.floor(options.count / queries.length));\n    const engine = options.engine || this.defaultEngine;\n\n    try {\n      if (!this.isBrowserOpen) {\n        this.logger.info('Launching browser');\n        await this.browser.launch(this.config.browserOptions);\n        this.isBrowserOpen = true;\n      } else {\n        this.logger.info('Using existing browser instance');\n      }\n\n      const queue = new PromiseQueue(options.concurrency || 15);\n      const visitedUrls = new Set<string>();\n      const results = await Promise.all(\n        queries.map((query) =>\n          this.search(this.browser, {\n            query,\n            count,\n            queue,\n            visitedUrls,\n            excludeDomains,\n            truncate: options.truncate,\n            needVisitedUrls: options.needVisitedUrls,\n            engine,\n          }),\n        ),\n      );\n\n      this.logger.success('Search completed successfully');\n      return results.flat();\n    } catch (error) {\n      this.logger.error('Search failed:', error);\n      return [];\n    } finally {\n      if (!options.keepBrowserOpen && this.isBrowserOpen) {\n        await this.closeBrowser();\n      }\n    }\n  }\n\n  /**\n   * Explicitly close the browser instance\n   */\n  async closeBrowser(): Promise<void> {\n    if (this.isBrowserOpen) {\n      this.logger.info('Closing browser');\n      await this.browser.close();\n      this.isBrowserOpen = false;\n    }\n  }\n\n  private async search(\n    browser: BrowserInterface,\n    options: {\n      query: string;\n      count?: number;\n      needVisitedUrls?: boolean;\n      excludeDomains: string[];\n      queue: PromiseQueue;\n      visitedUrls: Set<string>;\n      truncate?: number;\n      engine: LocalBrowserSearchEngine;\n    },\n  ) {\n    const searchEngine = getSearchEngine(options.engine);\n    const url = searchEngine.getSearchUrl(options.query, {\n      count: options.count,\n      excludeDomains: options.excludeDomains,\n    });\n\n    this.logger.info(`Searching with ${options.engine} engine: ${url}`);\n\n    let links = await browser.evaluateOnNewPage({\n      url,\n      waitForOptions: {\n        waitUntil: 'networkidle2',\n      },\n      pageFunction: searchEngine.extractSearchResults,\n      pageFunctionParams: [],\n      beforePageLoad: async (page) => {\n        await interceptRequest(page);\n      },\n      afterPageLoad: async (page) => {\n        if (searchEngine.waitForSearchResults)\n          await searchEngine.waitForSearchResults(page, 10000);\n      },\n    });\n\n    this.logger.info(`Fetched ${links?.length ?? 0} links`);\n\n    // Filter links\n    links =\n      links?.filter((link) => {\n        if (options.visitedUrls.has(link.url)) return false;\n        options.visitedUrls.add(link.url);\n        return !shouldSkipDomain(link.url);\n      }) || [];\n\n    if (!links.length) {\n      this.logger.info('No valid links found');\n      return [];\n    }\n\n    // Visit each link and extract content\n    const results = await Promise.allSettled(\n      options.needVisitedUrls\n        ? links.map((item) =>\n          options.queue.add(() => this.visitLink(this.browser, item)),\n        )\n        : links,\n    );\n\n    return results\n      .map((result) => {\n        if (result.status === 'rejected' || !result.value) return null;\n\n        return {\n          ...result.value,\n          content: options.truncate\n            ? result.value.content.slice(0, options.truncate)\n            : result.value.content,\n        };\n      }).filter((v): v is SearchResult => v !== null);\n  }\n\n  private async visitLink(\n    browser: BrowserInterface,\n    item: SearchResult,\n  ): Promise<SearchResult | undefined> {\n    try {\n      this.logger.info('Visiting link:', item.url);\n\n      const result = await browser.evaluateOnNewPage({\n        url: item.url,\n        pageFunction: extractPageInformation,\n        pageFunctionParams: [READABILITY_SCRIPT],\n        beforePageLoad: async (page) => {\n          await interceptRequest(page);\n        },\n      });\n\n      if (result) {\n        const content = toMarkdown(result.content);\n        return { ...result, url: item.url, content, snippet: item.snippet };\n      }\n    } catch (e) {\n      this.logger.error('Failed to visit link:', e);\n    }\n  }\n}\n\ndeclare global {\n  interface Window {\n    Readability: any;\n  }\n}\n","/**\n * The following code is based on\n * https://github.com/bytedance/UI-TARS-desktop/tree/main/packages/agent-infra/search/browser-search\n * \n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport Turndown from 'turndown';\nimport { gfm } from 'turndown-plugin-gfm';\nimport { defaultLogger as logger } from '@agent-infra/logger';\nimport { Page } from '../browser/index.js';\nimport UserAgent from 'user-agents';\n\n/**\n * Safely parses a URL string into a URL object\n * @param url - The URL string to parse\n * @returns URL object or null if invalid\n */\nconst parseUrl = (url: string) => {\n  try {\n    return new URL(url);\n  } catch {\n    return null;\n  }\n};\n\n/**\n * Determines if a domain should be skipped based on a blocklist\n * @param url - The URL to check\n * @returns True if the domain should be skipped, false otherwise\n */\nexport const shouldSkipDomain = (url: string) => {\n  const parsed = parseUrl(url);\n  if (!parsed) return true;\n\n  const { hostname } = parsed;\n  return [\n    'reddit.com',\n    'www.reddit.com',\n    'x.com',\n    'twitter.com',\n    'www.twitter.com',\n    'youtube.com',\n    'www.youtube.com',\n  ].includes(hostname);\n};\n\n/**\n * Applies various stealth techniques to make the browser appear more like a regular user browser\n * @param page - Puppeteer page object\n */\nexport async function applyStealthScripts(page: Page) {\n  const userAgent = new UserAgent({\n    deviceCategory: 'desktop',\n  }).toString();\n  await page.setBypassCSP(true);\n  await page.setUserAgent(userAgent);\n\n  /**\n   * https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html\n   */\n  await page.evaluate(() => {\n    /**\n     * Override the navigator.webdriver property\n     * The webdriver read-only property of the navigator interface indicates whether the user agent is controlled by automation.\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver\n     */\n    Object.defineProperty(navigator, 'webdriver', {\n      get: () => undefined,\n    });\n\n    // Mock languages and plugins to mimic a real browser\n    Object.defineProperty(navigator, 'languages', {\n      get: () => ['en-US', 'en'],\n    });\n\n    Object.defineProperty(navigator, 'plugins', {\n      get: () => [{}, {}, {}, {}, {}],\n    });\n\n    // Redefine the headless property\n    Object.defineProperty(navigator, 'headless', {\n      get: () => false,\n    });\n\n    // Override the permissions API\n    const originalQuery = window.navigator.permissions.query;\n    window.navigator.permissions.query = (parameters) =>\n      parameters.name === 'notifications'\n        ? Promise.resolve({\n          state: Notification.permission,\n        } as PermissionStatus)\n        : originalQuery(parameters);\n  });\n}\n\n/**\n * Sets up request interception to block unnecessary resources and apply stealth techniques\n * @param page - Puppeteer page object\n */\nexport async function interceptRequest(page: Page) {\n  await applyStealthScripts(page);\n  await page.setRequestInterception(true);\n\n  page.on('request', (request) => {\n    const resourceType = request.resourceType();\n\n    if (resourceType !== 'document') {\n      return request.abort();\n    }\n\n    if (request.isNavigationRequest()) {\n      return request.continue();\n    }\n\n    return request.abort();\n  });\n}\n\n/**\n * Interface representing extracted page information\n */\ninterface PageInfo {\n  /** Page title */\n  title: string;\n  /** Page content in HTML format */\n  content: string;\n}\n\n/**\n * !NOTE: This function runs in the context of the browser page, not Node.js\n * \n * Extracts readable content from a web page using Readability\n * @param window Browser window object\n * @param readabilityScript Readability library script as string\n * @returns Extracted page information (title and content)\n */\nexport function extractPageInformation(\n  window: Window,\n  readabilityScript: string,\n): PageInfo {\n  const Readability = new Function(\n    'module',\n    `${readabilityScript}\\nreturn module.exports`,\n  )({});\n\n  const document = window.document;\n\n  // Remove non-content elements to improve extraction quality\n  document\n    .querySelectorAll(\n      'script,noscript,style,link,svg,img,video,iframe,canvas,.reflist',\n    )\n    .forEach((el) => el.remove());\n\n  // Parse the document using Readability\n  const article = new Readability(document).parse();\n  const content = article?.content || '';\n  const title = document.title;\n\n  return {\n    content,\n    title: article?.title || title,\n  };\n}\n\nexport interface ToMarkdownOptions extends Turndown.Options {\n  gfmExtension?: boolean;\n}\n\n/**\n * Convert HTML content to Markdown format\n * @param html HTML string\n * @param options Conversion options\n * @returns Markdown string\n */\nexport function toMarkdown(\n  html: string,\n  options: ToMarkdownOptions = {},\n): string {\n  if (!html) return '';\n\n  try {\n    const {\n      codeBlockStyle = 'fenced',\n      headingStyle = 'atx',\n      emDelimiter = '*',\n      strongDelimiter = '**',\n      gfmExtension = true,\n    } = options;\n\n    const turndown = new Turndown({\n      codeBlockStyle,\n      headingStyle,\n      emDelimiter,\n      strongDelimiter,\n    });\n\n    if (gfmExtension) {\n      turndown.use(gfm);\n    }\n\n    return turndown.turndown(html);\n  } catch (error) {\n    logger.error('Error converting HTML to Markdown:', error);\n    return html;\n  }\n}\n","/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport interface Task<T> {\n  (): Promise<T>;\n}\n\nexport class PromiseQueue {\n  private queue: Task<any>[] = [];\n\n  private concurrency: number;\n\n  private running = 0;\n\n  private results: any[] = [];\n\n  constructor(concurrency = 1) {\n    this.concurrency = concurrency;\n  }\n\n  add<T>(task: Task<T>): Promise<T> {\n    return new Promise((resolve, reject) => {\n      this.queue.push(async () => {\n        try {\n          const result = await task();\n          resolve(result);\n          return result;\n        } catch (error) {\n          reject(error);\n          throw error;\n        }\n      });\n      this.run();\n    });\n  }\n\n  private async run() {\n    if (this.running >= this.concurrency || this.queue.length === 0) {\n      return;\n    }\n\n    this.running++;\n    const task = this.queue.shift()!;\n\n    try {\n      const result = await task();\n      this.results.push(result);\n    } catch (error) {\n      // Handle error if needed\n    } finally {\n      this.running--;\n      this.run();\n    }\n  }\n\n  async waitAll(): Promise<any[]> {\n    while (this.running > 0 || this.queue.length > 0) {\n      await new Promise((resolve) => setTimeout(resolve, 100));\n    }\n    return this.results;\n  }\n}","/**\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Page } from 'puppeteer-core';\nimport type { SearchEngineAdapter, SearchResult } from '../types.js';\n\n/**\n * Bing search engine adapter implementation.\n * Provides functionality to generate Bing search URLs and extract search results from Bing search pages.\n */\nexport class BingSearchEngine implements SearchEngineAdapter {\n  /**\n   * Generates a Bing search URL based on the provided query and options.\n   *\n   * @param query - The search query string\n   * @param options - Search configuration options\n   * @param options.count - Number of search results to request (default: 10)\n   * @param options.excludeDomains - Array of domain names to exclude from search results\n   * @returns Formatted Bing search URL as a string\n   */\n  getSearchUrl(\n    query: string,\n    options: {\n      count?: number;\n      excludeDomains?: string[];\n    },\n  ): string {\n    const searchParams = new URLSearchParams({\n      q: `${\n        options.excludeDomains && options.excludeDomains.length > 0\n          ? `${options.excludeDomains.map((domain) => `-site:${domain}`).join(' ')} `\n          : ''\n      }${query}`,\n      count: `${options.count || 10}`,\n    });\n\n    return `https://www.bing.com/search?${searchParams.toString()}`;\n  }\n\n  /**\n   * Extracts search results from a Bing search page.\n   *\n   * @param window - The browser window object containing the loaded Bing search page\n   * @returns Array of search results extracted from the page\n   */\n  extractSearchResults(window: Window): SearchResult[] {\n    const links: SearchResult[] = [];\n    const document = window.document;\n\n    /**\n     * Validates if a string is a properly formatted URL.\n     *\n     * @param url - The URL string to validate\n     * @returns Boolean indicating if the URL is valid\n     */\n    const isValidUrl = (url: string) => {\n      try {\n        new URL(url);\n        return true;\n      } catch (error) {\n        return false;\n      }\n    };\n\n    /**\n    * Extracts the snippet text from a search result element\n    * @param element - The search result element\n    * @returns The extracted snippet text\n    */\n    const extractSnippet = (element: Element): string => {\n    // Clone the element to avoid modifying the original DOM\n      const clone = element.cloneNode(true) as Element;\n \n      // Remove title elements (typically h2 tags in Bing)\n      const titleElements = clone.querySelectorAll('h2');\n      titleElements.forEach((el) => el.remove());\n\n      // Remove any cite/URL elements\n      const citeElements = clone.querySelectorAll('.b_attribution');\n      citeElements.forEach((el) => el.remove());\n\n      // Remove script and style elements\n      const scriptElements = clone.querySelectorAll('script, style');\n      scriptElements.forEach((el) => el.remove());\n\n      // Get text content and remove duplicates\n      const text = Array.from(clone.querySelectorAll('*'))\n        .filter((node) => node.textContent?.trim())\n        .map((node) => node.textContent?.trim())\n        .filter(Boolean)\n        .reduce((acc: string[], curr) => {\n          // Only add text if it's not already included in accumulated text\n          if (\n            !acc.some(\n              (text) =>\n                text.includes(curr as string) ||\n            (curr as string).includes(text),\n            )\n          ) {\n            acc.push(curr as string);\n          }\n          return acc;\n        }, [])\n        .join(' ')\n        .trim()\n        .replace(/\\s+/g, ' ');\n\n      return text;\n    };\n\n    try {\n      // Bing search results are in elements with class 'b_algo'\n      const elements = document.querySelectorAll('.b_algo');\n      elements.forEach((element) => {\n        const titleEl = element.querySelector('h2');\n        const urlEl = element.querySelector('h2 a');\n        const url = urlEl?.getAttribute('href');\n        const snippet = extractSnippet(element);\n\n        if (!url || !isValidUrl(url)) return;\n\n        const item: SearchResult = {\n          title: titleEl?.textContent || '',\n          snippet,\n          url,\n          content: '',\n        };\n\n        if (!item.title || !item.url) return;\n\n        links.push(item);\n      });\n    } catch (error) {\n      console.error('Error extracting search results from Bing:', error);\n      throw error;\n    }\n\n    return links;\n  }\n\n  /**\n  * Waits for Bing search results to load completely.\n  *\n  * @param page - The Puppeteer page object\n  * @returns Promise that resolves when search results are loaded\n  */\n  async waitForSearchResults(page: Page, timeout?: number): Promise<void> {\n    await page.waitForSelector('#b_results', {\n      timeout: timeout ?? 10000,\n    });\n  }\n}","/**\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { Page } from '../../browser/index.js';\nimport type { SearchEngineAdapter, SearchResult } from '../types.js';\n\n/**\n * Baidu search engine adapter implementation.\n * Provides functionality to generate Baidu search URLs and extract search results from Baidu search pages.\n */\nexport class BaiduSearchEngine implements SearchEngineAdapter {\n  /**\n   * Generates a Baidu search URL based on the provided query and options.\n   *\n   * @param query - The search query string\n   * @param options - Search configuration options\n   * @param options.count - Number of search results to request (default: 10)\n   * @param options.excludeDomains - Array of domain names to exclude from search results\n   * @returns Formatted Baidu search URL as a string\n   */\n  getSearchUrl(\n    query: string,\n    options: {\n      count?: number;\n      excludeDomains?: string[];\n    },\n  ): string {\n    // Baidu doesn't support excluding domains in the same way as Google\n    // But we can add '-site:domain' to the query\n    const excludeDomainsQuery =\n      options.excludeDomains && options.excludeDomains.length > 0\n        ? options.excludeDomains.map((domain) => `-site:${domain}`).join(' ')\n        : '';\n\n    const searchParams = new URLSearchParams({\n      wd: excludeDomainsQuery ? `${excludeDomainsQuery} ${query}` : query,\n      rn: `${options.count || 10}`, // rn is the parameter for result count\n    });\n\n    return `https://www.baidu.com/s?${searchParams.toString()}`;\n  }\n\n  /**\n   * Extracts search results from a Baidu search page.\n   *\n   * @param window - The browser window object containing the loaded Baidu search page\n   * @returns Array of search results extracted from the page\n   */\n  extractSearchResults(window: Window): SearchResult[] {\n    const links: SearchResult[] = [];\n    const document = window.document;\n\n    try {\n      // Baidu search results are in elements with class 'result'\n      const elements = document.querySelectorAll('.result');\n      elements.forEach((element) => {\n        const titleEl = element.querySelector('.t a');\n        const url = titleEl?.getAttribute('href');\n        const snippetEl = element.querySelector('.c-span-last .content-right_2s-H4');\n\n        if (!url) return;\n\n        const item: SearchResult = {\n          title: titleEl?.textContent || '',\n          url, // Note: Baidu uses redirects, we'll need to follow them\n          snippet: snippetEl?.textContent || '',\n          content: '',\n        };\n\n        if (!item.title || !item.url) return;\n\n        links.push(item);\n      });\n    } catch (error) {\n      console.error('Error extracting search results from Baidu:', error);\n    }\n\n    return links;\n  }\n\n  /**\n  * Waits for Bing search results to load completely.\n  *\n  * @param page - The Puppeteer page object\n  * @returns Promise that resolves when search results are loaded\n  */\n  async waitForSearchResults(page: Page, timeout?: number): Promise<void> {\n    await page.waitForSelector('#page', {\n      timeout: timeout ?? 10000,\n    });\n  }\n}","import { Page } from '../../browser/index.js';\nimport type { SearchEngineAdapter, SearchResult } from '../types.js';\n\nexport class SogouSearchEngine implements SearchEngineAdapter {\n  /**\n   * Generates a Sogou search URL based on the provided query and options.\n   *\n   * @param query - The search query string\n   * @param options - Search configuration options\n   * @param options.count - Number of search results to request (default: 10)\n   * @param options.excludeDomains - Array of domain names to exclude from search results\n   * @returns Formatted Sogou search URL as a string\n   */\n  getSearchUrl(\n    query: string,\n    options: {\n      count?: number;\n      excludeDomains?: string[];\n    },\n  ): string {\n    const { count = 10, excludeDomains = [] } = options;\n\n    const excludeDomainsQuery =\n      excludeDomains && excludeDomains.length > 0\n        ? excludeDomains.map((domain) => `-site:${domain}`).join(' ')\n        : '';\n\n    const searchParams = new URLSearchParams({\n      query: `${excludeDomainsQuery ? `${excludeDomainsQuery} ` : ''}${query}`,\n      num: `${count}`,\n    });\n\n    return `https://www.sogou.com/web?${searchParams.toString()}`;\n  }\n\n  /**\n   * !NOTE: This function runs in the context of the browser page, not Node.js\n   * \n   * Extract search results from Sogou\n   * @param window - The window object\n   * @returns Search results\n   */\n  extractSearchResults(window: Window): SearchResult[] {\n    const links: SearchResult[] = [];\n    const document = window.document;\n\n    const isValidUrl = (url: string) => {\n      try {\n        new URL(url);\n        return true;\n      } catch (error) {\n        return false;\n      }\n    };\n\n    const EndPoints = 'https://www.sogou.com';\n    \n    const SELECTOR = {\n      results: '.results .vrwrap',\n      resultTitle: '.vr-title',\n      resultLink: '.vr-title > a',\n      resultSnippet: ['.star-wiki', '.fz-mid', '.attribute-centent'],\n      resultSnippetExcluded: ['.text-lightgray', '.zan-box', '.tag-website'],\n      related: '#main .vrwrap.middle-better-hintBox .hint-mid',\n    };\n\n    try {\n      const elements = document.querySelectorAll(SELECTOR.results);\n      elements.forEach((element) => {\n        const titleEl = element.querySelector(SELECTOR.resultTitle);\n        let url = element.querySelector(SELECTOR.resultLink)?.getAttribute('href');\n\n        const snippets = SELECTOR.resultSnippet.map((selector) => {\n          const cloneElement = element.cloneNode(true) as HTMLElement;\n          // remove excluded elements\n          SELECTOR.resultSnippetExcluded.forEach((excludedSelector) => {\n            const el = cloneElement.querySelector(excludedSelector);\n            el?.remove();\n          });\n          // get the text content of the element\n          const el = cloneElement.querySelector(selector);\n          return el?.textContent?.trim() || '';\n        });\n\n        const snippet = snippets\n          .filter(Boolean)\n          .join(' ')\n          .replace(/\\s+/g, ' ')\n          .trim();\n\n        if (!url?.includes('http')) url = `${EndPoints}${url}`;\n\n        if (!url?.trim() || !isValidUrl(url)) return;\n\n        const item: SearchResult = {\n          title: titleEl?.textContent?.trim() || '',\n          url,\n          snippet,\n          content: '',\n        };\n\n        if (!item.title || !item.url) return;\n\n        links.push(item);\n      });\n    } catch (error) {\n      const msg = error instanceof Error ? error.message : String(error);\n      console.error('Error extracting search results from Sogou:', msg);\n      throw error;\n    }\n\n    return links;\n  }\n\n  /**\n  * Waits for Sogou search results to load completely.\n  *\n  * @param page - The Puppeteer page object\n  * @returns Promise that resolves when search results are loaded\n  */\n  async waitForSearchResults(page: Page, timeout?: number): Promise<void> {\n    await page.waitForSelector('#pagebar_container', {\n      timeout: timeout ?? 10000,\n    });\n  }\n}\n","/**\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Page } from '../../browser/types.js';\nimport type { SearchEngineAdapter, SearchResult } from '../types.js';\n\n/**\n * Google search engine adapter implementation.\n * Provides functionality to generate Google search URLs and extract search results from Google search pages.\n */\nexport class GoogleSearchEngine implements SearchEngineAdapter {\n  /**\n   * Generates a Google search URL based on the provided query and options.\n   *\n   * @param query - The search query string\n   * @param options - Search configuration options\n   * @param options.count - Number of search results to request (default: 10)\n   * @param options.excludeDomains - Array of domain names to exclude from search results\n   * @returns Formatted Google search URL as a string\n   */\n  getSearchUrl(\n    query: string,\n    options: {\n      count?: number;\n      excludeDomains?: string[];\n    },\n  ): string {\n    const searchParams = new URLSearchParams({\n      q: `${\n        options.excludeDomains && options.excludeDomains.length > 0\n          ? `${options.excludeDomains.map((domain) => `-site:${domain}`).join(' ')} `\n          : ''\n      }${query}`,\n      num: `${options.count || 10}`,\n    });\n\n    searchParams.set('udm', '14');\n    return `https://www.google.com/search?${searchParams.toString()}`;\n  }\n\n  /**\n   * Extracts search results from a Google search page.\n   *\n   * @param window - The browser window object containing the loaded Google search page\n   * @returns Array of search results extracted from the page\n   */\n  extractSearchResults(window: Window): SearchResult[] {\n    const links: SearchResult[] = [];\n    const document = window.document;\n\n    /**\n     * Validates if a string is a properly formatted URL.\n     *\n     * @param url - The URL string to validate\n     * @returns Boolean indicating if the URL is valid\n     */\n    const isValidUrl = (url: string) => {\n      try {\n        new URL(url);\n        return true;\n      } catch (error) {\n        return false;\n      }\n    };\n\n    /**\n     * Extracts the snippet text from an element by cloning it and removing title elements\n     *\n     * @param element - The search result element\n     * @returns The extracted snippet text\n     */\n    const extractSnippet = (element: Element): string => {\n      // Clone the element to avoid modifying the original DOM\n      const clone = element.cloneNode(true) as Element;\n\n      // Remove title elements (typically h3 tags in Google)\n      const titleElements = clone.querySelectorAll('h3');\n      titleElements.forEach((el) => el.remove());\n\n      // Remove any cite elements (showing the URL)\n      const citeElements = clone.querySelectorAll('cite');\n      citeElements.forEach((el) => el.remove());\n\n      // Remove script and style elements\n      const scriptElements = clone.querySelectorAll('script, style');\n      scriptElements.forEach((el) => el.remove());\n\n      // Get text content and remove duplicates\n      const text = Array.from(clone.querySelectorAll('*'))\n        .filter((node) => node.textContent?.trim())\n        .map((node) => node.textContent?.trim())\n        .filter(Boolean)\n        .reduce((acc: string[], curr) => {\n          // Only add text if it's not already included in accumulated text\n          if (\n            !acc.some(\n              (text) =>\n                text.includes(curr as string) ||\n                (curr as string).includes(text),\n            )\n          ) {\n            acc.push(curr as string);\n          }\n          return acc;\n        }, [])\n        .join(' ')\n        .trim()\n        .replace(/\\s+/g, ' ');\n\n      return text;\n    };\n\n    try {\n      // Google search results are contained in elements with class 'tF2Cxc'\n      // It may change at any time\n      const elements = document.querySelectorAll('.tF2Cxc');\n      elements.forEach((element) => {\n        const titleEl = element.querySelector('h3');\n        const urlEl = element.querySelector('a');\n        const url = urlEl?.getAttribute('href');\n\n        // Extract snippet using the generic method\n        const snippet = extractSnippet(element.parentElement || element);\n\n        if (!url || !isValidUrl(url)) return;\n\n        const item: SearchResult = {\n          title: titleEl?.textContent || '',\n          url,\n          snippet,\n          content: '',\n        };\n\n        if (!item.title || !item.url) return;\n\n        links.push(item);\n      });\n    } catch (error) {\n      console.error(error);\n    }\n\n    return links;\n  }\n\n  /**\n   * Waits for Google search results to load completely.\n   *\n   * @param page - The Puppeteer page object\n   * @returns Promise that resolves when search results are loaded\n   */\n  async waitForSearchResults(page: Page, timeout?: number): Promise<void> {\n    await page.waitForSelector('#search', {\n      timeout: timeout ?? 10000,\n    });\n  }\n}","import { BingSearchEngine } from './bing.js';\nimport { BaiduSearchEngine } from './baidu.js';\nimport type { LocalBrowserSearchEngine, SearchEngineAdapter } from '../types.js';\nimport { SogouSearchEngine } from './sogou.js';\nimport { GoogleSearchEngine } from './google.js';\n\n/**\n * Factory function to get the appropriate search engine adapter instance.\n *\n * @param engine - The search engine identifier ('sogou', 'bing', or 'baidu')\n * @returns An instance of the requested search engine adapter\n */\nexport function getSearchEngine(engine: LocalBrowserSearchEngine): SearchEngineAdapter {\n  switch (engine) {\n    case 'bing':\n      return new BingSearchEngine();\n    case 'baidu':\n      return new BaiduSearchEngine();\n    case 'sogou':\n      return new SogouSearchEngine();\n    case 'google':\n      return new GoogleSearchEngine();\n    default:\n      return new BingSearchEngine();\n  }\n}","import { ISearchRequestOptions, ISearchResponse, ISearchResponseResult } from '../interface.js';\nimport { BrowserSearch, LocalBrowserSearchEngine } from '../libs/browser-search/index.js';\nimport { ConsoleLogger } from '@agent-infra/logger';\n\nconst logger = new ConsoleLogger('[LocalSearch]');\n\nexport async function localSearch(options: ISearchRequestOptions): Promise<ISearchResponse> {\n  const { query, limit = 10 } = options;\n  let { engines = 'all' } = options;\n  const browserSearch = new BrowserSearch({\n    logger,\n    browserOptions: {\n      headless: true,\n    },\n  });\n\n  if (engines === 'all') {\n    engines = 'bing,google,baidu,sogou';\n  }\n\n  try {\n    const engineList = engines.split(',');\n\n    if (engineList.length === 0) {\n      throw new Error('engines is required');\n    }\n\n    const results: ISearchResponseResult[] = [];\n\n    for (const engine of engineList) {\n      const res = await browserSearch.perform({\n        query,\n        count: limit,\n        engine: engine as LocalBrowserSearchEngine,\n        needVisitedUrls: false,\n      });\n\n      if (res.length > 0) {\n        results.push(...res);\n        break;\n      }\n    }\n\n    logger.info(`Found ${results.length} results for ${query}`, results);\n\n    return {\n      results,\n      success: true,\n    };\n  } catch (err: unknown) {\n    const msg = err instanceof Error ? err.message : 'Local search error.';\n    process.stdout.write(msg);\n    throw err;\n  } finally {\n    await browserSearch.closeBrowser();\n  }\n}","/**\n * The following tools are based on the Firecrawl MCP Server\n * https://github.com/mendableai/firecrawl-mcp-server\n */\n\nimport { Tool } from '@modelcontextprotocol/sdk/types.js';\n\n// tools definition\nexport const SEARCH_TOOL: Tool = {\n  name: 'one_search',\n  description:\n    'Search and retrieve content from web pages. ' +\n    'Returns SERP results by default (url, title, description).',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      query: {\n        type: 'string',\n        description: 'Search query string',\n      },\n      limit: {\n        type: 'number',\n        description: 'Maximum number of results to return (default: 10)',\n      },\n      language: {\n        type: 'string',\n        description: 'Language code for search results (default: auto)',\n      },\n      categories: {\n        type: 'string',\n        enum: [\n          'general',\n          'news',\n          'images',\n          'videos',\n          'it',\n          'science',\n          'map',\n          'music',\n          'files',\n          'social_media',\n        ],\n        description: 'Categories to search for (default: general)',\n      },\n      timeRange: {\n        type: 'string',\n        description: 'Time range for search results (default: all)',\n        enum: [\n          'all',\n          'day',\n          'week',\n          'month',\n          'year',\n        ],\n      },\n    },\n    required: ['query'],\n  },\n};\n\nexport const MAP_TOOL: Tool = {\n  name: 'one_map',\n  description:\n    'Discover URLs from a starting point. Can use both sitemap.xml and HTML link discovery.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      url: {\n        type: 'string',\n        description: 'Starting URL for URL discovery',\n      },\n      search: {\n        type: 'string',\n        description: 'Optional search term to filter URLs',\n      },\n      ignoreSitemap: {\n        type: 'boolean',\n        description: 'Skip sitemap.xml discovery and only use HTML links',\n      },\n      sitemapOnly: {\n        type: 'boolean',\n        description: 'Only use sitemap.xml for discovery, ignore HTML links',\n      },\n      includeSubdomains: {\n        type: 'boolean',\n        description: 'Include URLs from subdomains in results',\n      },\n      limit: {\n        type: 'number',\n        description: 'Maximum number of URLs to return',\n      },\n    },\n    required: ['url'],\n  },\n};\n\nexport const SCRAPE_TOOL: Tool = {\n  name: 'one_scrape',\n  description:\n    'Scrape a single webpage with advanced options for content extraction. ' +\n    'Supports various formats including markdown, HTML, and screenshots. ' +\n    'Can execute custom actions like clicking or scrolling before scraping.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      url: {\n        type: 'string',\n        description: 'The URL to scrape',\n      },\n      formats: {\n        type: 'array',\n        items: {\n          type: 'string',\n          enum: [\n            'markdown',\n            'html',\n            'rawHtml',\n            'screenshot',\n            'links',\n            'screenshot@fullPage',\n            'extract',\n          ],\n        },\n        description: \"Content formats to extract (default: ['markdown'])\",\n      },\n      onlyMainContent: {\n        type: 'boolean',\n        description:\n          'Extract only the main content, filtering out navigation, footers, etc.',\n      },\n      includeTags: {\n        type: 'array',\n        items: { type: 'string' },\n        description: 'HTML tags to specifically include in extraction',\n      },\n      excludeTags: {\n        type: 'array',\n        items: { type: 'string' },\n        description: 'HTML tags to exclude from extraction',\n      },\n      waitFor: {\n        type: 'number',\n        description: 'Time in milliseconds to wait for dynamic content to load',\n      },\n      timeout: {\n        type: 'number',\n        description:\n          'Maximum time in milliseconds to wait for the page to load',\n      },\n      actions: {\n        type: 'array',\n        items: {\n          type: 'object',\n          properties: {\n            type: {\n              type: 'string',\n              enum: [\n                'wait',\n                'click',\n                'screenshot',\n                'write',\n                'press',\n                'scroll',\n                'scrape',\n                'executeJavascript',\n              ],\n              description: 'Type of action to perform',\n            },\n            selector: {\n              type: 'string',\n              description: 'CSS selector for the target element',\n            },\n            milliseconds: {\n              type: 'number',\n              description: 'Time to wait in milliseconds (for wait action)',\n            },\n            text: {\n              type: 'string',\n              description: 'Text to write (for write action)',\n            },\n            key: {\n              type: 'string',\n              description: 'Key to press (for press action)',\n            },\n            direction: {\n              type: 'string',\n              enum: ['up', 'down'],\n              description: 'Scroll direction',\n            },\n            script: {\n              type: 'string',\n              description: 'JavaScript code to execute',\n            },\n            fullPage: {\n              type: 'boolean',\n              description: 'Take full page screenshot',\n            },\n          },\n          required: ['type'],\n        },\n        description: 'List of actions to perform before scraping',\n      },\n      extract: {\n        type: 'object',\n        properties: {\n          schema: {\n            type: 'object',\n            description: 'Schema for structured data extraction',\n          },\n          systemPrompt: {\n            type: 'string',\n            description: 'System prompt for LLM extraction',\n          },\n          prompt: {\n            type: 'string',\n            description: 'User prompt for LLM extraction',\n          },\n        },\n        description: 'Configuration for structured data extraction',\n      },\n      mobile: {\n        type: 'boolean',\n        description: 'Use mobile viewport',\n      },\n      skipTlsVerification: {\n        type: 'boolean',\n        description: 'Skip TLS certificate verification',\n      },\n      removeBase64Images: {\n        type: 'boolean',\n        description: 'Remove base64 encoded images from output',\n      },\n      location: {\n        type: 'object',\n        properties: {\n          country: {\n            type: 'string',\n            description: 'Country code for geolocation',\n          },\n          languages: {\n            type: 'array',\n            items: { type: 'string' },\n            description: 'Language codes for content',\n          },\n        },\n        description: 'Location settings for scraping',\n      },\n    },\n    required: ['url'],\n  },\n};\n\n\n\nexport const EXTRACT_TOOL: Tool = {\n  name: 'one_extract',\n  description:\n    'Extract structured information from web pages using LLM. ' +\n    'Supports both cloud AI and self-hosted LLM extraction.',\n  inputSchema: {\n    type: 'object',\n    properties: {\n      urls: {\n        type: 'array',\n        items: { type: 'string' },\n        description: 'List of URLs to extract information from',\n      },\n      prompt: {\n        type: 'string',\n        description: 'Prompt for the LLM extraction',\n      },\n      systemPrompt: {\n        type: 'string',\n        description: 'System prompt for LLM extraction',\n      },\n      schema: {\n        type: 'object',\n        description: 'JSON schema for structured data extraction',\n      },\n      allowExternalLinks: {\n        type: 'boolean',\n        description: 'Allow extraction from external links',\n      },\n      enableWebSearch: {\n        type: 'boolean',\n        description: 'Enable web search for additional context',\n      },\n      includeSubdomains: {\n        type: 'boolean',\n        description: 'Include subdomains in extraction',\n      },\n    },\n    required: ['urls'],\n  },\n};\n"],"mappings":"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mBACf,EACA,QAAS,CACP,KAAM,QACN,MAAO,CACL,KAAM,SACN,KAAM,CACJ,WACA,OACA,UACA,aACA,QACA,sBACA,SACF,CACF,EACA,YAAa,oDACf,EACA,gBAAiB,CACf,KAAM,UACN,YACE,wEACJ,EACA,YAAa,CACX,KAAM,QACN,MAAO,CAAE,KAAM,QAAS,EACxB,YAAa,iDACf,EACA,YAAa,CACX,KAAM,QACN,MAAO,CAAE,KAAM,QAAS,EACxB,YAAa,sCACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,0DACf,EACA,QAAS,CACP,KAAM,SACN,YACE,2DACJ,EACA,QAAS,CACP,KAAM,QACN,MAAO,CACL,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,KAAM,CACJ,OACA,QACA,aACA,QACA,QACA,SACA,SACA,mBACF,EACA,YAAa,2BACf,EACA,SAAU,CACR,KAAM,SACN,YAAa,qCACf,EACA,aAAc,CACZ,KAAM,SACN,YAAa,gDACf,EACA,KAAM,CACJ,KAAM,SACN,YAAa,kCACf,EACA,IAAK,CACH,KAAM,SACN,YAAa,iCACf,EACA,UAAW,CACT,KAAM,SACN,KAAM,CAAC,KAAM,MAAM,EACnB,YAAa,kBACf,EACA,OAAQ,CACN,KAAM,SACN,YAAa,4BACf,EACA,SAAU,CACR,KAAM,UACN,YAAa,2BACf,CACF,EACA,SAAU,CAAC,MAAM,CACnB,EACA,YAAa,4CACf,EACA,QAAS,CACP,KAAM,SACN,WAAY,CACV,OAAQ,CACN,KAAM,SACN,YAAa,uCACf,EACA,aAAc,CACZ,KAAM,SACN,YAAa,kCACf,EACA,OAAQ,CACN,KAAM,SACN,YAAa,gCACf,CACF,EACA,YAAa,8CACf,EACA,OAAQ,CACN,KAAM,UACN,YAAa,qBACf,EACA,oBAAqB,CACnB,KAAM,UACN,YAAa,mCACf,EACA,mBAAoB,CAClB,KAAM,UACN,YAAa,0CACf,EACA,SAAU,CACR,KAAM,SACN,WAAY,CACV,QAAS,CACP,KAAM,SACN,YAAa,8BACf,EACA,UAAW,CACT,KAAM,QACN,MAAO,CAAE,KAAM,QA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","names":["index_exports","__toCommonJS","import_server","import_types","import_stdio","bingSearch","options","query","limit","safeSearch","page","apiUrl","apiKey","language","bingSafeSearchOptions","searchOptions","queryParams","key","value","res","item","err","msg","DDG","import_async_retry","duckDuckGoSearch","options","query","timeout","safeSearch","retry","searchOptions","res","asyncRetry","result","error","msg","import_node_url","searxngSearch","params","query","page","limit","categories","engines","safeSearch","format","language","timeRange","timeout","apiKey","apiUrl","controller","timeoutId","config","endpoint","queryParams","url","headers","res","response","item","image","video","err","msg","import_core","tavilySearch","options","query","limit","categories","timeRange","apiKey","tvly","params","item","error","msg","import_puppeteer_core","fs","path","os","import_logger","BrowserFinder","logger","HOME_DIR","LOCAL_APP_DATA","name","platform","error","browser","b","result","browserName","profileInfo","profileName","info","executable","import_logger","BaseBrowser","options","target","page","error","url","pageFunction","pageFunctionParams","beforePageLoad","afterPageLoad","beforeSendResult","waitForOptions","_window","result","pages","i","puppeteer","LocalBrowser","BaseBrowser","BrowserFinder","options","executablePath","viewportWidth","viewportHeight","puppeteerLaunchOptions","error","puppeteer","READABILITY_SCRIPT","import_logger","import_turndown","import_turndown_plugin_gfm","import_logger","import_user_agents","parseUrl","url","shouldSkipDomain","parsed","hostname","applyStealthScripts","page","userAgent","UserAgent","originalQuery","parameters","interceptRequest","request","extractPageInformation","window","readabilityScript","Readability","document","el","article","content","title","toMarkdown","html","options","codeBlockStyle","headingStyle","emDelimiter","strongDelimiter","gfmExtension","turndown","Turndown","error","logger","PromiseQueue","concurrency","task","resolve","reject","result","error","BingSearchEngine","query","options","domain","window","links","document","isValidUrl","url","extractSnippet","element","clone","el","node","acc","curr","text","titleEl","snippet","item","error","page","timeout","BaiduSearchEngine","query","options","excludeDomainsQuery","domain","window","links","document","element","titleEl","url","snippetEl","item","error","page","timeout","SogouSearchEngine","query","options","count","excludeDomains","excludeDomainsQuery","domain","window","links","document","isValidUrl","url","EndPoints","SELECTOR","element","titleEl","snippet","selector","cloneElement","excludedSelector","item","error","msg","page","timeout","GoogleSearchEngine","query","options","searchParams","domain","window","links","document","isValidUrl","url","extractSnippet","element","clone","el","node","acc","curr","text","titleEl","snippet","item","error","page","timeout","getSearchEngine","engine","BingSearchEngine","BaiduSearchEngine","SogouSearchEngine","GoogleSearchEngine","BrowserSearch","config","LocalBrowser","options","queries","excludeDomains","count","engine","queue","PromiseQueue","visitedUrls","results","query","error","browser","searchEngine","getSearchEngine","url","links","page","interceptRequest","link","shouldSkipDomain","item","result","v","extractPageInformation","READABILITY_SCRIPT","content","toMarkdown","e","import_logger","logger","localSearch","options","query","limit","engines","browserSearch","BrowserSearch","engineList","results","engine","res","err","msg","SEARCH_TOOL","MAP_TOOL","SCRAPE_TOOL","EXTRACT_TOOL","import_firecrawl_js","import_dotenvx","import_duck_duck_scrape","dotenvx","SEARCH_API_URL","SEARCH_API_KEY","SEARCH_PROVIDER","SAFE_SEARCH","LIMIT","CATEGORIES","ENGINES","FORMAT","LANGUAGE","TIME_RANGE","DEFAULT_TIMEOUT","FIRECRAWL_API_KEY","FIRECRAWL_API_URL","firecrawl","FirecrawlApp","server","searchDefaultConfig","SEARCH_TOOL","EXTRACT_TOOL","SCRAPE_TOOL","MAP_TOOL","request","startTime","name","args","checkSearchArgs","results","success","processSearch","result","error","checkScrapeArgs","url","scrapeArgs","content","processScrape","checkMapArgs","processMapUrl","msg","params","categories","language","searxngSearch","tavilySearch","bingSearch","safeSearch","safeSearchOptions","duckDuckGoSearch","localSearch","res","runServer","transport"]}