{"version":3,"file":"index.cjs","names":["turndown","TurndownService","Readability","Text","Type"],"sources":["../utils.ts","../search.ts","../extract.ts","../index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst EXTENSION_DIR = dirname(fileURLToPath(import.meta.url));\nconst CONFIG_PATH = join(EXTENSION_DIR, \"web-search.json\");\n\nexport interface WebSearchConfig {\n  exaApiKey?: string;\n  braveApiKey?: string;\n  provider?: SearchProvider;\n}\n\nexport type SearchProvider = \"auto\" | \"exa\" | \"brave\";\nexport type ResolvedSearchProvider = \"exa\" | \"brave\";\n\nexport interface SearchResult {\n  title: string;\n  url: string;\n  snippet: string;\n}\n\nexport interface SearchResponse {\n  answer: string;\n  results: SearchResult[];\n  inlineContent?: ExtractedContent[];\n}\n\nexport interface AttributedSearchResponse extends SearchResponse {\n  provider: ResolvedSearchProvider;\n}\n\nexport interface SearchOptions {\n  numResults?: number;\n  includeContent?: boolean;\n  recencyFilter?: \"day\" | \"week\" | \"month\" | \"year\";\n  domainFilter?: string[];\n  signal?: AbortSignal;\n}\n\nexport interface ExtractedContent {\n  url: string;\n  title: string;\n  content: string;\n  error: string | null;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nexport const loadConfig = (): WebSearchConfig => {\n  if (cachedConfig) return cachedConfig;\n\n  if (!existsSync(CONFIG_PATH)) {\n    cachedConfig = {};\n    return cachedConfig;\n  }\n\n  try {\n    const raw = readFileSync(CONFIG_PATH, \"utf-8\");\n    const parsed = JSON.parse(raw) as Record<string, unknown>;\n    cachedConfig = {\n      exaApiKey: normalizeKey(parsed.exaApiKey),\n      braveApiKey: normalizeKey(parsed.braveApiKey),\n      provider: normalizeProvider(parsed.provider ?? parsed.searchProvider ?? \"auto\"),\n    };\n    return cachedConfig;\n  } catch (err) {\n    const message = err instanceof Error ? err.message : String(err);\n    throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`, { cause: err });\n  }\n};\n\nexport const saveConfig = (updates: Partial<WebSearchConfig>): void => {\n  let config: Record<string, unknown> = {};\n  if (existsSync(CONFIG_PATH)) {\n    try {\n      config = JSON.parse(readFileSync(CONFIG_PATH, \"utf-8\")) as Record<string, unknown>;\n    } catch {\n      // ignore parse errors, start fresh\n    }\n  }\n\n  Object.assign(config, updates);\n  if (!existsSync(EXTENSION_DIR)) mkdirSync(EXTENSION_DIR, { recursive: true });\n  writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + \"\\n\");\n  cachedConfig = null;\n};\n\nconst normalizeKey = (value: unknown): string | undefined => {\n  if (typeof value !== \"string\") return undefined;\n  const trimmed = value.trim();\n  return trimmed.length > 0 ? trimmed : undefined;\n};\n\nexport const normalizeProvider = (value: unknown): SearchProvider => {\n  if (typeof value !== \"string\") return \"auto\";\n  const normalized = value.trim().toLowerCase();\n  if (normalized === \"exa\") return \"exa\";\n  if (normalized === \"brave\") return \"brave\";\n  return \"auto\";\n};\n\nexport const errorMessage = (err: unknown): string => {\n  return err instanceof Error ? err.message : String(err);\n};\n\nexport const isAbortError = (err: unknown): boolean => {\n  return errorMessage(err).toLowerCase().includes(\"abort\");\n};\n\nexport const freshnessFromRecency = (filter: string | undefined): string | undefined => {\n  if (!filter) return undefined;\n  const map: Record<string, string> = {\n    day: \"pd\",\n    week: \"pw\",\n    month: \"pm\",\n    year: \"py\",\n  };\n  return map[filter];\n};\n\nexport const getApiKey = (keyName: \"exaApiKey\" | \"braveApiKey\"): string | undefined => {\n  const envVar = keyName === \"exaApiKey\" ? \"EXA_API_KEY\" : \"BRAVE_API_KEY\";\n  return process.env[envVar] ?? loadConfig()[keyName];\n};\n\nexport const getExaApiKey = (): string | undefined => {\n  return getApiKey(\"exaApiKey\");\n};\n\nexport const getBraveApiKey = (): string | undefined => {\n  return getApiKey(\"braveApiKey\");\n};\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n  type AttributedSearchResponse,\n  type ResolvedSearchProvider,\n  type SearchOptions,\n  type SearchResponse,\n  type SearchResult,\n  errorMessage,\n  freshnessFromRecency,\n  getExaApiKey,\n  getBraveApiKey,\n  loadConfig,\n  type ExtractedContent,\n} from \"./utils\";\n\n// ── Exa constants ────────────────────────────────────────────────────────────\n\nconst EXA_ANSWER_URL = \"https://api.exa.ai/answer\";\nconst EXA_SEARCH_URL = \"https://api.exa.ai/search\";\nconst EXA_MCP_URL = \"https://mcp.exa.ai/mcp\";\nconst EXA_USAGE_PATH = join(homedir(), \".pi\", \"exa-usage.json\");\nconst MONTHLY_LIMIT = 1000;\nconst MCP_TIMEOUT_MS = 60000;\n\n// ── Brave constants ──────────────────────────────────────────────────────────\n\nconst BRAVE_SEARCH_URL = \"https://api.search.brave.com/res/v1/web/search\";\n\n// ── Exa: budget tracking (only applies to direct API usage) ──────────────────\n\ninterface ExaUsage {\n  month: string;\n  count: number;\n}\n\nconst getCurrentMonth = (): string => {\n  return new Date().toISOString().slice(0, 7);\n};\n\nconst readExaUsage = (): ExaUsage => {\n  if (!existsSync(EXA_USAGE_PATH)) return { month: getCurrentMonth(), count: 0 };\n  try {\n    const raw = JSON.parse(readFileSync(EXA_USAGE_PATH, \"utf-8\")) as {\n      month?: unknown;\n      count?: unknown;\n    };\n    const month = typeof raw.month === \"string\" ? raw.month : getCurrentMonth();\n    const count =\n      typeof raw.count === \"number\" && Number.isFinite(raw.count)\n        ? Math.max(0, Math.floor(raw.count))\n        : 0;\n    if (month !== getCurrentMonth()) return { month: getCurrentMonth(), count: 0 };\n    return { month, count };\n  } catch {\n    return { month: getCurrentMonth(), count: 0 };\n  }\n};\n\nconst writeExaUsage = (usage: ExaUsage): void => {\n  const dir = join(homedir(), \".pi\");\n  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n  writeFileSync(EXA_USAGE_PATH, JSON.stringify(usage, null, 2) + \"\\n\");\n};\n\nconst reserveExaBudget = (): { exhausted: true } | null => {\n  const usage = readExaUsage();\n  if (usage.count >= MONTHLY_LIMIT) return { exhausted: true };\n  writeExaUsage({ month: usage.month, count: usage.count + 1 });\n  return null;\n};\n\n// ── Exa MCP client (zero-config) ─────────────────────────────────────────────\n\ninterface ExaMcpRpcResponse {\n  result?: {\n    content?: Array<{ type?: string; text?: string }>;\n    isError?: boolean;\n  };\n  error?: {\n    code?: number;\n    message?: string;\n  };\n}\n\nconst callExaMcp = async (\n  toolName: string,\n  args: Record<string, unknown>,\n  signal?: AbortSignal,\n): Promise<string> => {\n  const timeout = AbortSignal.timeout(MCP_TIMEOUT_MS);\n  const combinedSignal = signal ? AbortSignal.any([signal, timeout]) : timeout;\n\n  const response = await fetch(EXA_MCP_URL, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      Accept: \"application/json, text/event-stream\",\n    },\n    body: JSON.stringify({\n      jsonrpc: \"2.0\",\n      id: 1,\n      method: \"tools/call\",\n      params: { name: toolName, arguments: args },\n    }),\n    signal: combinedSignal,\n  });\n\n  if (!response.ok) {\n    const errorText = await response.text();\n    throw new Error(`Exa MCP error ${response.status}: ${errorText.slice(0, 300)}`);\n  }\n\n  const body = await response.text();\n  const dataLines = body.split(\"\\n\").filter((line) => line.startsWith(\"data:\"));\n\n  let parsed: ExaMcpRpcResponse | null = null;\n  for (const line of dataLines) {\n    const payload = line.slice(5).trim();\n    if (!payload) continue;\n    try {\n      const candidate = JSON.parse(payload) as ExaMcpRpcResponse;\n      if (candidate?.result || candidate?.error) {\n        parsed = candidate;\n        break;\n      }\n    } catch {\n      // skip invalid JSON lines\n    }\n  }\n\n  if (!parsed) {\n    try {\n      const candidate = JSON.parse(body) as ExaMcpRpcResponse;\n      if (candidate?.result || candidate?.error) parsed = candidate;\n    } catch {\n      // fallback parse failed\n    }\n  }\n\n  if (!parsed) throw new Error(\"Exa MCP returned an empty response\");\n\n  if (parsed.error) {\n    const code = typeof parsed.error.code === \"number\" ? ` ${parsed.error.code}` : \"\";\n    throw new Error(`Exa MCP error${code}: ${parsed.error.message ?? \"Unknown error\"}`);\n  }\n\n  if (parsed.result?.isError) {\n    const message = parsed.result.content\n      ?.find((item) => item.type === \"text\" && typeof item.text === \"string\")\n      ?.text?.trim();\n    throw new Error(message || \"Exa MCP returned an error\");\n  }\n\n  const text = parsed.result?.content?.find(\n    (item) => item.type === \"text\" && typeof item.text === \"string\" && item.text.trim().length > 0,\n  )?.text;\n\n  if (!text) throw new Error(\"Exa MCP returned empty content\");\n  return text;\n};\n\nconst parseExaMcpResults = (\n  text: string,\n): Array<{ title: string; url: string; content: string }> | null => {\n  const blocks = text.split(/(?=^Title: )/m).filter((block) => block.trim().length > 0);\n  const parsed = blocks\n    .map((block) => {\n      const title = block.match(/^Title: (.+)/m)?.[1]?.trim() ?? \"\";\n      const url = block.match(/^URL: (.+)/m)?.[1]?.trim() ?? \"\";\n      let content = \"\";\n      const textStart = block.indexOf(\"\\nText: \");\n      if (textStart >= 0) {\n        content = block.slice(textStart + 7).trim();\n      } else {\n        const hlMatch = block.match(/\\nHighlights:\\s*\\n/);\n        if (hlMatch?.index != null) {\n          content = block.slice(hlMatch.index + hlMatch[0].length).trim();\n        }\n      }\n      content = content.replace(/\\n---\\s*$/, \"\").trim();\n      return { title, url, content };\n    })\n    .filter((r) => r.url.length > 0);\n  return parsed.length > 0 ? parsed : null;\n};\n\nconst buildAnswerFromMcpResults = (\n  results: Array<{ title: string; url: string; content: string }>,\n): string => {\n  if (results.length === 0) return \"\";\n  return results\n    .map((r, i) => {\n      const snippet = r.content.replace(/\\s+/g, \" \").trim().slice(0, 500);\n      if (!snippet) return null;\n      return `${snippet}\\nSource: ${r.title || `Source ${i + 1}`} (${r.url})`;\n    })\n    .filter(Boolean)\n    .join(\"\\n\\n\");\n};\n\nconst mapMcpInlineContent = (\n  results: Array<{ title: string; url: string; content: string }>,\n): ExtractedContent[] => {\n  return results\n    .filter((r) => r.content.length > 0)\n    .map((r) => ({ url: r.url, title: r.title, content: r.content, error: null }));\n};\n\nconst buildExaMcpQuery = (query: string, options: SearchOptions): string => {\n  const parts = [query];\n  if (options.domainFilter?.length) {\n    for (const d of options.domainFilter) {\n      parts.push(d.startsWith(\"-\") ? `-site:${d.slice(1)}` : `site:${d}`);\n    }\n  }\n  if (options.recencyFilter) {\n    const now = new Date();\n    switch (options.recencyFilter) {\n      case \"day\":\n        parts.push(\"past 24 hours\");\n        break;\n      case \"week\":\n        parts.push(\"past week\");\n        break;\n      case \"month\":\n        parts.push(`${now.toLocaleString(\"en\", { month: \"long\" })} ${now.getFullYear()}`);\n        break;\n      case \"year\":\n        parts.push(String(now.getFullYear()));\n        break;\n    }\n  }\n  return parts.join(\" \");\n};\n\nconst searchWithExaMcp = async (\n  query: string,\n  options: SearchOptions = {},\n): Promise<SearchResponse | null> => {\n  const enrichedQuery = buildExaMcpQuery(query, options);\n  const text = await callExaMcp(\n    \"web_search_exa\",\n    {\n      query: enrichedQuery,\n      numResults: options.numResults ?? 5,\n      livecrawl: \"fallback\",\n      type: \"auto\",\n      contextMaxCharacters: options.includeContent ? 50000 : 3000,\n    },\n    options.signal,\n  );\n\n  const parsedResults = parseExaMcpResults(text);\n  if (!parsedResults) return null;\n\n  const response: SearchResponse = {\n    answer: buildAnswerFromMcpResults(parsedResults),\n    results: parsedResults.map((r, i) => ({\n      title: r.title || `Source ${i + 1}`,\n      url: r.url,\n      snippet: \"\",\n    })),\n  };\n\n  if (options.includeContent) {\n    const inlineContent = mapMcpInlineContent(parsedResults);\n    if (inlineContent.length > 0) response.inlineContent = inlineContent;\n  }\n\n  return response;\n};\n\n// ── Exa direct API client ────────────────────────────────────────────────────\n\ninterface ExaAnswerResponse {\n  answer?: string;\n  citations?: Array<{ url?: string; title?: string; text?: string; publishedDate?: string }>;\n}\n\ninterface ExaSearchResponse {\n  results?: Array<{\n    title?: string;\n    url?: string;\n    publishedDate?: string;\n    author?: string;\n    text?: string;\n    highlights?: unknown;\n    highlightScores?: number[];\n  }>;\n}\n\nconst mapExaResults = (\n  results: ExaSearchResponse[\"results\"] | ExaAnswerResponse[\"citations\"],\n): SearchResult[] => {\n  if (!Array.isArray(results)) return [];\n  const mapped: SearchResult[] = [];\n  for (const item of results) {\n    if (!item?.url) continue;\n    mapped.push({\n      title: item.title || `Source ${mapped.length + 1}`,\n      url: item.url,\n      snippet: \"\",\n    });\n  }\n  return mapped;\n};\n\nconst buildExaAnswerFromSearchResults = (results: ExaSearchResponse[\"results\"]): string => {\n  if (!results?.length) return \"\";\n  return results\n    .map((item, i) => {\n      if (!item?.url) return null;\n      const highlights = Array.isArray(item.highlights)\n        ? item.highlights.filter((h): h is string => typeof h === \"string\" && h.trim().length > 0)\n        : [];\n      const content =\n        highlights.length > 0\n          ? highlights.join(\" \")\n          : typeof item.text === \"string\"\n            ? item.text.trim().slice(0, 1000)\n            : \"\";\n      if (!content) return null;\n      return `${content}\\nSource: ${item.title || `Source ${i + 1}`} (${item.url})`;\n    })\n    .filter(Boolean)\n    .join(\"\\n\\n\");\n};\n\nconst mapExaInlineContent = (results: ExaSearchResponse[\"results\"]): ExtractedContent[] => {\n  if (!results?.length) return [];\n  return results\n    .filter(\n      (r): r is NonNullable<ExaSearchResponse[\"results\"]>[number] & { url: string; text: string } =>\n        !!r?.url && typeof r.text === \"string\" && r.text.length > 0,\n    )\n    .map((r) => ({ url: r.url, title: r.title || \"\", content: r.text, error: null }));\n};\n\nconst searchWithExaDirect = async (\n  query: string,\n  options: SearchOptions = {},\n): Promise<SearchResponse> => {\n  const budget = reserveExaBudget();\n  if (budget) {\n    throw new Error(\n      \"Exa monthly free tier exhausted (1,000 requests). Resets next month.\\n\" +\n        \"  Switch to Brave with provider: 'brave', or upgrade at exa.ai/pricing\",\n    );\n  }\n\n  const apiKey = getExaApiKey()!;\n  const useSearch =\n    options.includeContent ||\n    !!options.recencyFilter ||\n    !!options.domainFilter?.length ||\n    !!(options.numResults && options.numResults !== 5);\n\n  if (!useSearch) {\n    const response = await fetch(EXA_ANSWER_URL, {\n      method: \"POST\",\n      headers: { \"x-api-key\": apiKey, \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ query, text: true }),\n      signal: AbortSignal.any([\n        AbortSignal.timeout(30000),\n        ...(options.signal ? [options.signal] : []),\n      ]),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      throw new Error(`Exa API error ${response.status}: ${errorText.slice(0, 300)}`);\n    }\n\n    const data = (await response.json()) as ExaAnswerResponse;\n    return {\n      answer: data.answer || \"\",\n      results: mapExaResults(data.citations),\n    };\n  }\n\n  const startDate = options.recencyFilter\n    ? new Date(\n        Date.now() - { day: 1, week: 7, month: 30, year: 365 }[options.recencyFilter] * 86400000,\n      ).toISOString()\n    : null;\n\n  const includeDomains = options.domainFilter\n    ?.filter((d) => !d.startsWith(\"-\") && d.trim().length > 0)\n    .map((d) => d.trim());\n  const excludeDomains = options.domainFilter\n    ?.filter((d) => d.startsWith(\"-\"))\n    .map((d) => d.slice(1).trim())\n    .filter(Boolean);\n\n  const response = await fetch(EXA_SEARCH_URL, {\n    method: \"POST\",\n    headers: { \"x-api-key\": apiKey, \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({\n      query,\n      type: \"auto\",\n      numResults: options.numResults ?? 5,\n      ...(includeDomains?.length ? { includeDomains } : {}),\n      ...(excludeDomains?.length ? { excludeDomains } : {}),\n      ...(startDate ? { startPublishedDate: startDate } : {}),\n      contents: {\n        text: options.includeContent ? true : { maxCharacters: 3000 },\n        highlights: true,\n      },\n    }),\n    signal: AbortSignal.any([\n      AbortSignal.timeout(30000),\n      ...(options.signal ? [options.signal] : []),\n    ]),\n  });\n\n  if (!response.ok) {\n    const errorText = await response.text();\n    throw new Error(`Exa API error ${response.status}: ${errorText.slice(0, 300)}`);\n  }\n\n  const data = (await response.json()) as ExaSearchResponse;\n\n  const mapped: SearchResponse = {\n    answer: buildExaAnswerFromSearchResults(data.results),\n    results: mapExaResults(data.results),\n  };\n\n  if (options.includeContent) {\n    const inlineContent = mapExaInlineContent(data.results);\n    if (inlineContent.length > 0) mapped.inlineContent = inlineContent;\n  }\n\n  return mapped;\n};\n\n// ── Exa public entry ─────────────────────────────────────────────────────────\n\nexport const isExaAvailable = (): boolean => {\n  const key = getExaApiKey();\n  if (key) {\n    const usage = readExaUsage();\n    return usage.count < MONTHLY_LIMIT;\n  }\n  return true; // MCP always available\n};\n\nexport const hasExaApiKey = (): boolean => {\n  return !!getExaApiKey();\n};\n\nconst searchWithExa = async (\n  query: string,\n  options: SearchOptions = {},\n): Promise<SearchResponse> => {\n  const apiKey = getExaApiKey();\n  if (!apiKey) {\n    const result = await searchWithExaMcp(query, options);\n    if (!result) throw new Error(\"Exa MCP returned no results\");\n    return result;\n  }\n  return searchWithExaDirect(query, options);\n};\n\n// ── Brave Search client ──────────────────────────────────────────────────────\n\ninterface BraveWebResult {\n  title?: string;\n  url?: string;\n  description?: string;\n  extra_snippets?: string[];\n}\n\ninterface BraveApiResponse {\n  query?: { original?: string };\n  web?: {\n    results?: BraveWebResult[];\n  };\n}\n\nconst buildBraveAnswer = (results: BraveWebResult[]): string => {\n  if (results.length === 0) return \"\";\n  return results\n    .map((r, i) => {\n      const snippets = [r.description, ...(r.extra_snippets ?? [])].filter(Boolean);\n      const combined = snippets.join(\" \");\n      if (!combined) return null;\n      return `${combined}\\nSource: ${r.title || `Source ${i + 1}`} (${r.url})`;\n    })\n    .filter(Boolean)\n    .join(\"\\n\\n\");\n};\n\nconst searchWithBrave = async (\n  query: string,\n  options: SearchOptions = {},\n): Promise<SearchResponse> => {\n  const apiKey = getBraveApiKey();\n  if (!apiKey) {\n    throw new Error(\n      \"Brave Search API key not found.\\n\" +\n        \"  1. Get a free key at https://api.search.brave.com/app/dashboard\\n\" +\n        \"  2. Add 'braveApiKey' to extensions/web-access/web-search.json\\n\" +\n        \"  3. Or set BRAVE_API_KEY environment variable\",\n    );\n  }\n\n  const url = new URL(BRAVE_SEARCH_URL);\n  url.searchParams.set(\"q\", query);\n  url.searchParams.set(\"count\", String(Math.min(options.numResults ?? 5, 20)));\n  url.searchParams.set(\"extra_snippets\", \"true\");\n  url.searchParams.set(\"safesearch\", \"moderate\");\n\n  const freshness = freshnessFromRecency(options.recencyFilter);\n  if (freshness) url.searchParams.set(\"freshness\", freshness);\n\n  const response = await fetch(url.toString(), {\n    headers: {\n      Accept: \"application/json\",\n      \"Accept-Encoding\": \"gzip\",\n      \"X-Subscription-Token\": apiKey,\n    },\n    signal: AbortSignal.any([\n      AbortSignal.timeout(15000),\n      ...(options.signal ? [options.signal] : []),\n    ]),\n  });\n\n  if (!response.ok) {\n    if (response.status === 401 || response.status === 403) {\n      throw new Error(\n        \"Brave Search API returned unauthorized. Check your braveApiKey in extensions/web-access/web-search.json\",\n      );\n    }\n    const errorText = await response.text();\n    throw new Error(`Brave API error ${response.status}: ${errorText.slice(0, 300)}`);\n  }\n\n  const data = (await response.json()) as BraveApiResponse;\n  const results = data.web?.results ?? [];\n\n  return {\n    answer: buildBraveAnswer(results),\n    results: results\n      .filter((r): r is BraveWebResult & { url: string } => !!r.url)\n      .map((r) => ({\n        title: r.title || \"Untitled\",\n        url: r.url,\n        snippet: r.description || \"\",\n      })),\n  };\n};\n\n// ── Provider availability ────────────────────────────────────────────────────\n\nexport const isBraveAvailable = (): boolean => {\n  return !!getBraveApiKey();\n};\n\nconst resolveProvider = (requested: unknown): ResolvedSearchProvider => {\n  const config = loadConfig();\n  const provider = (typeof requested === \"string\" ? requested : config.provider) ?? \"auto\";\n\n  if (provider === \"auto\") {\n    if (isExaAvailable()) return \"exa\";\n    if (isBraveAvailable()) return \"brave\";\n    return \"exa\";\n  }\n\n  if (provider === \"exa\") return \"exa\";\n  if (provider === \"brave\") return \"brave\";\n  return \"exa\";\n};\n\n// ── Search router ────────────────────────────────────────────────────────────\n\nexport const search = async (\n  query: string,\n  options: SearchOptions & { provider?: string } = {},\n): Promise<AttributedSearchResponse> => {\n  const resolvedProvider = resolveProvider(options.provider);\n\n  if (resolvedProvider === \"exa\") {\n    try {\n      const result = await searchWithExa(query, options);\n      return { ...result, provider: \"exa\" };\n    } catch (err) {\n      const message = errorMessage(err);\n      if (message.toLowerCase().includes(\"abort\")) throw err;\n      if (isBraveAvailable()) {\n        try {\n          const result = await searchWithBrave(query, options);\n          return { ...result, provider: \"brave\" };\n        } catch {\n          // both failed\n        }\n      }\n      throw err;\n    }\n  }\n\n  if (resolvedProvider === \"brave\") {\n    return { ...(await searchWithBrave(query, options)), provider: \"brave\" };\n  }\n\n  throw new Error(`Unknown provider: ${resolvedProvider}`);\n};\n","import { Readability } from \"@mozilla/readability\";\nimport { parseHTML } from \"linkedom\";\nimport TurndownService from \"turndown\";\nimport type { ExtractedContent } from \"./utils\";\nimport { errorMessage } from \"./utils\";\n\nconst DEFAULT_TIMEOUT_MS = 30000;\nconst MAX_RESPONSE_SIZE = 5 * 1024 * 1024; // 5MB\nconst JINA_READER_BASE = \"https://r.jina.ai/\";\nconst JINA_TIMEOUT_MS = 30000;\nconst MIN_USEFUL_CONTENT = 500;\n\nconst turndown = new TurndownService({\n  headingStyle: \"atx\",\n  codeBlockStyle: \"fenced\",\n});\n\nconst REJECTED_TYPES = [\n  \"application/octet-stream\",\n  \"image/\",\n  \"audio/\",\n  \"video/\",\n  \"application/zip\",\n  \"application/gzip\",\n  \"application/x-tar\",\n  \"application/x-rar-compressed\",\n];\n\nconst isRejectedContentType = (contentType: string): boolean => {\n  const lower = contentType.toLowerCase();\n  return REJECTED_TYPES.some((t) => lower.includes(t));\n};\n\nconst isLikelyJSRendered = (html: string): boolean => {\n  const bodyMatch = html.match(/<body[^>]*>([\\s\\S]*?)<\\/body>/i);\n  if (!bodyMatch) return false;\n\n  const textContent = bodyMatch[1]\n    .replace(/<script[\\s\\S]*?<\\/script>/gi, \"\")\n    .replace(/<style[\\s\\S]*?<\\/style>/gi, \"\")\n    .replace(/<[^>]+>/g, \"\")\n    .replace(/\\s+/g, \" \")\n    .trim();\n\n  const scriptCount = (html.match(/<script/gi) || []).length;\n  return textContent.length < 500 && scriptCount > 3;\n};\n\nconst extractHeadingTitle = (text: string): string | null => {\n  const match = text.match(/^#{1,2}\\s+(.+)/m);\n  if (!match) return null;\n  const cleaned = match[1].replace(/\\*+/g, \"\").trim();\n  return cleaned || null;\n};\n\n// ── Jina Reader fallback ─────────────────────────────────────────────────────\n\nconst extractWithJinaReader = async (\n  url: string,\n  signal?: AbortSignal,\n): Promise<ExtractedContent | null> => {\n  const jinaUrl = JINA_READER_BASE + url;\n\n  try {\n    const res = await fetch(jinaUrl, {\n      headers: {\n        Accept: \"text/markdown\",\n        \"X-No-Cache\": \"true\",\n      },\n      signal: AbortSignal.any([AbortSignal.timeout(JINA_TIMEOUT_MS), ...(signal ? [signal] : [])]),\n    });\n\n    if (!res.ok) return null;\n\n    const content = await res.text();\n    const contentStart = content.indexOf(\"Markdown Content:\");\n    if (contentStart < 0) return null;\n\n    const markdownPart = content.slice(contentStart + 17).trim();\n\n    if (\n      markdownPart.length < 100 ||\n      markdownPart.startsWith(\"Loading...\") ||\n      markdownPart.startsWith(\"Please enable JavaScript\")\n    ) {\n      return null;\n    }\n\n    const title =\n      extractHeadingTitle(markdownPart) ?? (new URL(url).pathname.split(\"/\").pop() || url);\n    return { url, title, content: markdownPart, error: null };\n  } catch {\n    return null;\n  }\n};\n\n// ── HTTP extraction ──────────────────────────────────────────────────────────\n\nconst extractViaHttp = async (url: string, signal?: AbortSignal): Promise<ExtractedContent> => {\n  const controller = new AbortController();\n  const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);\n\n  const onAbort = () => controller.abort();\n  signal?.addEventListener(\"abort\", onAbort);\n\n  try {\n    const response = await fetch(url, {\n      signal: controller.signal,\n      headers: {\n        \"User-Agent\":\n          \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36\",\n        Accept:\n          \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8\",\n        \"Accept-Language\": \"en-US,en;q=0.9\",\n        \"Cache-Control\": \"no-cache\",\n      },\n    });\n\n    if (!response.ok) {\n      return {\n        url,\n        title: \"\",\n        content: \"\",\n        error: `HTTP ${response.status}: ${response.statusText}`,\n      };\n    }\n\n    const contentType = response.headers.get(\"content-type\") || \"\";\n    const contentLength = response.headers.get(\"content-length\");\n\n    if (contentLength) {\n      const length = parseInt(contentLength, 10);\n      if (length > MAX_RESPONSE_SIZE) {\n        return {\n          url,\n          title: \"\",\n          content: \"\",\n          error: `Response too large (${Math.round(length / 1024 / 1024)}MB)`,\n        };\n      }\n    }\n\n    if (isRejectedContentType(contentType)) {\n      return {\n        url,\n        title: \"\",\n        content: \"\",\n        error: `Unsupported content type: ${contentType.split(\";\")[0]}`,\n      };\n    }\n\n    const text = await response.text();\n    const isHTML =\n      contentType.includes(\"text/html\") || contentType.includes(\"application/xhtml+xml\");\n\n    if (!isHTML) {\n      const title = extractHeadingTitle(text) ?? (new URL(url).pathname.split(\"/\").pop() || url);\n      return { url, title, content: text, error: null };\n    }\n\n    const { document } = parseHTML(text);\n    const reader = new Readability(document as unknown as Document);\n    const article = reader.parse();\n\n    if (!article) {\n      const jsRendered = isLikelyJSRendered(text);\n      return {\n        url,\n        title: \"\",\n        content: \"\",\n        error: jsRendered\n          ? \"Page appears to be JavaScript-rendered (content loads dynamically)\"\n          : \"Could not extract readable content from HTML structure\",\n      };\n    }\n\n    const markdown = turndown.turndown(article.content);\n\n    if (markdown.length < MIN_USEFUL_CONTENT) {\n      return {\n        url,\n        title: article.title || \"\",\n        content: markdown,\n        error: isLikelyJSRendered(text)\n          ? \"Page appears to be JavaScript-rendered (content loads dynamically)\"\n          : \"Extracted content appears incomplete\",\n      };\n    }\n\n    return { url, title: article.title || \"\", content: markdown, error: null };\n  } catch (err) {\n    const message = errorMessage(err);\n    if (message.toLowerCase().includes(\"abort\")) {\n      return { url, title: \"\", content: \"\", error: \"Aborted\" };\n    }\n    return { url, title: \"\", content: \"\", error: message };\n  } finally {\n    clearTimeout(timeoutId);\n    signal?.removeEventListener(\"abort\", onAbort);\n  }\n};\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\nexport const extractContent = async (\n  url: string,\n  signal?: AbortSignal,\n): Promise<ExtractedContent> => {\n  if (signal?.aborted) {\n    return { url, title: \"\", content: \"\", error: \"Aborted\" };\n  }\n\n  let parsedUrl: URL;\n  try {\n    parsedUrl = new URL(url);\n  } catch {\n    return { url, title: \"\", content: \"\", error: \"Invalid URL\" };\n  }\n\n  if (parsedUrl.protocol !== \"http:\" && parsedUrl.protocol !== \"https:\") {\n    return { url, title: \"\", content: \"\", error: \"Only http:// and https:// URLs are supported\" };\n  }\n\n  if (signal?.aborted) return { url, title: \"\", content: \"\", error: \"Aborted\" };\n\n  const httpResult = await extractViaHttp(url, signal);\n\n  if (signal?.aborted) return { url, title: \"\", content: \"\", error: \"Aborted\" };\n  if (!httpResult.error) return httpResult;\n\n  // If Readability failed (likely JS-rendered), try Jina Reader\n  const jinaResult = await extractWithJinaReader(url, signal);\n  if (jinaResult) return jinaResult;\n\n  if (signal?.aborted) return { url, title: \"\", content: \"\", error: \"Aborted\" };\n\n  // Both failed — enhance error message with guidance\n  const guidance = [\n    httpResult.error,\n    \"\",\n    \"The page could not be extracted. Try:\",\n    \"  • Use web_search to find information about this topic\",\n    \"  • The page may require login or blocks automated access\",\n  ].join(\"\\n\");\n\n  return { ...httpResult, error: guidance };\n};\n","import type { ExtensionAPI, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { Type } from \"typebox\";\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport pLimit from \"p-limit\";\nimport { search } from \"./search\";\nimport { extractContent } from \"./extract\";\nimport {\n  loadConfig,\n  getExaApiKey,\n  getBraveApiKey,\n  errorMessage,\n  type ExtractedContent,\n} from \"./utils\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\ninterface ProviderStatus {\n  exa: \"mcp\" | \"api\" | \"unavailable\";\n  brave: \"key-set\" | \"missing\";\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\ntype WebThemeColor = \"accent\" | \"success\" | \"error\" | \"warning\" | \"muted\" | \"toolTitle\";\ntype WebRenderTheme = {\n  fg: (color: WebThemeColor, text: string) => string;\n  bold: (text: string) => string;\n};\n\nconst computeProviderStatus = (): ProviderStatus => {\n  const exaKey = getExaApiKey();\n  return {\n    exa: exaKey ? \"api\" : \"mcp\",\n    brave: getBraveApiKey() ? \"key-set\" : \"missing\",\n  };\n};\n\nconst formatStatus = (pi: ExtensionAPI, ctx: ExtensionContext): string => {\n  const status = computeProviderStatus();\n  const theme = ctx.ui.theme;\n  const lines: string[] = [];\n\n  lines.push(theme.fg(\"accent\", \"── Web Search Status ──\"));\n\n  const exaLabel =\n    status.exa === \"api\"\n      ? theme.fg(\"success\", \"✓ API key set\")\n      : status.exa === \"mcp\"\n        ? theme.fg(\"success\", \"✓ MCP (zero-config)\")\n        : theme.fg(\"error\", \"✗ unavailable\");\n  lines.push(`  Exa:   ${exaLabel}`);\n\n  const braveLabel =\n    status.brave === \"key-set\"\n      ? theme.fg(\"success\", \"✓ API key set\")\n      : theme.fg(\"warning\", \"✗ missing\");\n  lines.push(`  Brave: ${braveLabel}`);\n\n  const config = loadConfig();\n  lines.push(`  Provider: ${config.provider ?? \"auto\"}`);\n\n  return lines.join(\"\\n\");\n};\n\nconst normalizeQueryList = (raw: unknown[]): string[] => {\n  return raw\n    .filter((q): q is string => typeof q === \"string\")\n    .map((q) => q.trim())\n    .filter((q) => q.length > 0);\n};\n\nconst normalizeNumResults = (value: unknown): number => {\n  if (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n  return Math.min(20, Math.max(1, Math.floor(value)));\n};\n\nconst fetchIncludedContent = async (\n  urls: string[],\n  signal: AbortSignal | undefined,\n  onUpdate:\n    | ((update: {\n        content: Array<{ type: \"text\"; text: string }>;\n        details: Record<string, unknown> | undefined;\n      }) => void)\n    | undefined,\n): Promise<ExtractedContent[]> => {\n  const limit = pLimit(3);\n  const uniqueUrls = [...new Set(urls)].slice(0, 10);\n\n  const tasks = uniqueUrls.map((url, index) =>\n    limit(async () => {\n      onUpdate?.({\n        content: [\n          {\n            type: \"text\" as const,\n            text: `Fetching content ${index + 1}/${uniqueUrls.length}: ${url}`,\n          },\n        ],\n        details: {\n          phase: \"fetching_content\",\n          progress: index / uniqueUrls.length,\n          currentQuery: url,\n        },\n      });\n\n      try {\n        return await extractContent(url, signal);\n      } catch (err) {\n        return { url, title: \"\", content: \"\", error: errorMessage(err) };\n      }\n    }),\n  );\n\n  return Promise.all(tasks);\n};\n\n// ── Static render helpers (no ctx dependency) ────────────────────────────────\n\nconst renderSearchCall = (\n  args: { query?: string; queries?: string[] },\n  theme: WebRenderTheme,\n): Text => {\n  const raw: unknown[] = Array.isArray(args.queries)\n    ? args.queries\n    : args.query !== undefined\n      ? [args.query]\n      : [];\n  const list = normalizeQueryList(raw);\n\n  if (list.length === 0) {\n    return new Text(\n      theme.fg(\"toolTitle\", theme.bold(\"search \")) + theme.fg(\"error\", \"(no query)\"),\n      0,\n      0,\n    );\n  }\n\n  if (list.length === 1) {\n    const q = list[0];\n    const display = q.length > 60 ? q.slice(0, 57) + \"...\" : q;\n    return new Text(\n      theme.fg(\"toolTitle\", theme.bold(\"search \")) + theme.fg(\"accent\", `\"${display}\"`),\n      0,\n      0,\n    );\n  }\n\n  const lines = [\n    theme.fg(\"toolTitle\", theme.bold(\"search \")) + theme.fg(\"accent\", `${list.length} queries`),\n  ];\n  for (const q of list.slice(0, 5)) {\n    const display = q.length > 50 ? q.slice(0, 47) + \"...\" : q;\n    lines.push(theme.fg(\"muted\", `  \"${display}\"`));\n  }\n  if (list.length > 5) {\n    lines.push(theme.fg(\"muted\", `  ... and ${list.length - 5} more`));\n  }\n  return new Text(lines.join(\"\\n\"), 0, 0);\n};\n\nconst renderSearchResult = (\n  result: { content?: Array<{ type: string; text?: string }>; details?: Record<string, unknown> },\n  options: { expanded: boolean; isPartial: boolean },\n  theme: WebRenderTheme,\n): Text => {\n  const details = result.details as\n    | {\n        queryCount?: number;\n        successfulQueries?: number;\n        totalResults?: number;\n        error?: string;\n        phase?: string;\n        progress?: number;\n        currentQuery?: string;\n        provider?: string;\n      }\n    | undefined;\n\n  if (options.isPartial) {\n    if (details?.phase === \"searching\") {\n      const progress = details.progress ?? 0;\n      const bar =\n        \"\\u2588\".repeat(Math.floor(progress * 10)) +\n        \"\\u2591\".repeat(10 - Math.floor(progress * 10));\n      const query = details.currentQuery ?? \"\";\n      const display = query.length > 40 ? query.slice(0, 37) + \"...\" : query;\n      return new Text(theme.fg(\"accent\", `[${bar}] ${display}`), 0, 0);\n    }\n    return new Text(theme.fg(\"accent\", \"searching...\"), 0, 0);\n  }\n\n  if (details?.error) {\n    return new Text(theme.fg(\"error\", `Error: ${details.error}`), 0, 0);\n  }\n\n  const queryInfo =\n    details?.queryCount === 1\n      ? \"\"\n      : `${details?.successfulQueries}/${details?.queryCount} queries, `;\n  const providerInfo = details?.provider ? ` via ${details.provider}` : \"\";\n  return new Text(\n    theme.fg(\"success\", `${queryInfo}${details?.totalResults ?? 0} sources${providerInfo}`),\n    0,\n    0,\n  );\n};\n\n// ── Config for request scoped progress updates ───────────────────────────────\n\n// ── Extension entrypoint ─────────────────────────────────────────────────────\n\nconst webAccessExtension = (pi: ExtensionAPI): void => {\n  // ── Session lifecycle ──────────────────────────────────────────────────────\n\n  pi.on(\"session_start\", () => {\n    // Clean slate on session start\n  });\n\n  pi.on(\"session_shutdown\", () => {\n    // Cleanup if needed\n  });\n\n  // ── Tool: web_search ───────────────────────────────────────────────────────\n\n  pi.registerTool({\n    name: \"web_search\",\n    label: \"Web Search\",\n    description:\n      \"Search the web when the user asks for current/external information but does not provide a specific URL to fetch. \" +\n      \"Use this for topics, names, domains, documentation lookup, comparisons, recent information, or broad research. \" +\n      \"Do not use this when the user provides a direct http/https URL and asks to read/fetch/summarize that page; use fetch_content instead. \" +\n      \"Search uses Exa (MCP zero-config, or API with key) or Brave Search (needs API key), and returns a synthesized answer with source citations. \" +\n      \"For comprehensive research, prefer queries (plural) with 2-4 varied angles. \" +\n      \"Provider auto-selects: Exa first (MCP if no key, API if key set), then Brave (needs key).\",\n    promptSnippet:\n      \"Routing: use web_search when no direct URL is provided and the user needs web/current/external info. If a URL is present and the request is to read/fetch/summarize that page, use fetch_content. Prefer {queries:[...]} with 2-4 varied angles for research.\",\n    parameters: Type.Object({\n      query: Type.Optional(\n        Type.String({\n          description: \"Single search query. For research, prefer 'queries' with multiple angles.\",\n        }),\n      ),\n      queries: Type.Optional(\n        Type.Array(Type.String(), {\n          description:\n            \"Multiple queries searched in sequence. Vary phrasing and scope across 2-4 queries for best coverage.\",\n        }),\n      ),\n      numResults: Type.Optional(\n        Type.Number({ description: \"Results per query (default: 5, max: 20)\" }),\n      ),\n      includeContent: Type.Optional(\n        Type.Boolean({ description: \"Also fetch full page content for sources\" }),\n      ),\n      recencyFilter: Type.Optional(\n        StringEnum([\"day\", \"week\", \"month\", \"year\"], { description: \"Filter by recency\" }),\n      ),\n      domainFilter: Type.Optional(\n        Type.Array(Type.String(), { description: \"Limit to domains (prefix with - to exclude)\" }),\n      ),\n      provider: Type.Optional(\n        StringEnum([\"auto\", \"exa\", \"brave\"], { description: \"Search provider (default: auto)\" }),\n      ),\n    }),\n\n    execute: async (\n      _toolCallId: string,\n      params: {\n        query?: string;\n        queries?: string[];\n        numResults?: number;\n        includeContent?: boolean;\n        recencyFilter?: \"day\" | \"week\" | \"month\" | \"year\";\n        domainFilter?: string[];\n        provider?: string;\n      },\n      signal: AbortSignal | undefined,\n      onUpdate:\n        | ((update: {\n            content: Array<{ type: \"text\"; text: string }>;\n            details: Record<string, unknown> | undefined;\n          }) => void)\n        | undefined,\n      _ctx: ExtensionContext,\n    ) => {\n      const rawQueryList: unknown[] = Array.isArray(params.queries)\n        ? params.queries\n        : params.query !== undefined\n          ? [params.query]\n          : [];\n      const queryList = normalizeQueryList(rawQueryList);\n\n      if (queryList.length === 0) {\n        return {\n          content: [\n            {\n              type: \"text\" as const,\n              text: \"Error: No query provided. Use 'query' or 'queries' parameter.\",\n            },\n          ],\n          details: { error: \"No query provided\" },\n        };\n      }\n\n      const results: Array<{\n        query: string;\n        answer: string;\n        results: Array<{ title: string; url: string; snippet: string }>;\n        includedContent?: ExtractedContent[];\n        error: string | null;\n        provider?: string;\n      }> = [];\n      const allUrls: string[] = [];\n      let lastProvider: string | undefined;\n\n      for (let i = 0; i < queryList.length; i++) {\n        const query = queryList[i];\n\n        onUpdate?.({\n          content: [\n            {\n              type: \"text\" as const,\n              text: `Searching ${i + 1}/${queryList.length}: \"${query}\"...`,\n            },\n          ],\n          details: { phase: \"searching\", progress: i / queryList.length, currentQuery: query },\n        });\n\n        try {\n          const response = await search(query, {\n            numResults: normalizeNumResults(params.numResults),\n            includeContent: params.includeContent,\n            recencyFilter: params.recencyFilter,\n            domainFilter: params.domainFilter,\n            signal,\n            provider: params.provider,\n          });\n\n          results.push({\n            query,\n            answer: response.answer,\n            results: response.results,\n            includedContent: response.inlineContent,\n            error: null,\n            provider: response.provider,\n          });\n          lastProvider = response.provider;\n\n          for (const r of response.results) {\n            if (!allUrls.includes(r.url)) allUrls.push(r.url);\n          }\n        } catch (err) {\n          const message = errorMessage(err);\n          if (message.toLowerCase().includes(\"abort\")) throw err;\n          results.push({ query, answer: \"\", results: [], error: message, provider: undefined });\n        }\n\n        if (signal?.aborted) break;\n      }\n\n      const successfulCount = results.filter((r) => !r.error).length;\n      const totalResults = results.reduce((sum, r) => sum + r.results.length, 0);\n\n      let fetchedContent: ExtractedContent[] = [];\n      if (params.includeContent && allUrls.length > 0 && !signal?.aborted) {\n        const inlineContent = results.flatMap((r) => r.includedContent ?? []);\n        const inlineUrls = new Set(inlineContent.map((item) => item.url));\n        const urlsToFetch = allUrls.filter((url) => !inlineUrls.has(url));\n        const extractedContent = await fetchIncludedContent(urlsToFetch, signal, onUpdate);\n        fetchedContent = [...inlineContent, ...extractedContent];\n      }\n\n      // Build output\n      let output = \"\";\n      for (const r of results) {\n        if (queryList.length > 1) {\n          output += `## Query: \"${r.query}\"\\n\\n`;\n        }\n        if (r.error) {\n          output += `Error: ${r.error}\\n\\n`;\n        } else if (r.results.length === 0) {\n          output += \"No results found.\\n\\n\";\n        } else {\n          output += r.answer ? `${r.answer}\\n\\n---\\n\\n**Sources:**\\n` : \"**Sources:**\\n\";\n          output += r.results.map((s, i) => `${i + 1}. ${s.title}\\n   ${s.url}`).join(\"\\n\\n\");\n          output += \"\\n\\n\";\n        }\n      }\n\n      if (fetchedContent.length > 0) {\n        output += \"---\\n\\n**Fetched Content:**\\n\\n\";\n        for (const item of fetchedContent) {\n          output += `### ${item.title || item.url}\\n${item.url}\\n\\n`;\n          if (item.error) {\n            output += `Fetch error: ${item.error}\\n\\n`;\n          } else {\n            output += `${item.content.slice(0, 12000)}\\n\\n`;\n          }\n        }\n      }\n\n      return {\n        content: [{ type: \"text\" as const, text: output.trim() }],\n        details: {\n          queries: queryList,\n          queryCount: queryList.length,\n          successfulQueries: successfulCount,\n          totalResults,\n          fetchedContent: fetchedContent.length,\n          provider: lastProvider,\n        },\n      };\n    },\n\n    renderCall: renderSearchCall,\n\n    renderResult: renderSearchResult,\n  });\n\n  // ── Tool: fetch_content ────────────────────────────────────────────────────\n\n  pi.registerTool({\n    name: \"fetch_content\",\n    label: \"Fetch Content\",\n    description:\n      \"Fetch a specific http/https URL provided by the user and extract its readable content as markdown. \" +\n      \"Use this whenever the user provides a direct URL and asks to fetch, read, inspect, extract, summarize, analyze, or tell them what is on that page. \" +\n      \"Do not use this for broad topic research without a specific URL; use web_search instead. \" +\n      \"Handles standard HTML pages (via Readability) and falls back to Jina Reader for JavaScript-rendered pages. \" +\n      \"Returns clean markdown suitable for reading or analysis.\",\n    promptSnippet:\n      \"Routing: use fetch_content when the user provides a direct http/https URL or explicitly asks to fetch/read/summarize a page. Use web_search instead when no direct URL is provided.\",\n    parameters: Type.Object({\n      url: Type.String({\n        description: \"The URL to fetch and extract content from (http/https only)\",\n      }),\n    }),\n\n    execute: async (\n      _toolCallId: string,\n      params: { url: string },\n      signal: AbortSignal | undefined,\n      _onUpdate: undefined,\n      _ctx: ExtensionContext,\n    ) => {\n      try {\n        const result = await extractContent(params.url, signal);\n\n        if (result.error) {\n          return {\n            content: [\n              { type: \"text\" as const, text: `Failed to fetch ${params.url}: ${result.error}` },\n            ],\n            details: { url: params.url, title: result.title, error: result.error },\n          };\n        }\n\n        return {\n          content: [{ type: \"text\" as const, text: result.content }],\n          details: { url: params.url, title: result.title },\n        };\n      } catch (err) {\n        return {\n          content: [\n            { type: \"text\" as const, text: `Failed to fetch ${params.url}: ${errorMessage(err)}` },\n          ],\n          details: { url: params.url, error: errorMessage(err) },\n        };\n      }\n    },\n\n    renderCall: (args: { url: string }, theme: WebRenderTheme): Text => {\n      const url = args.url;\n      const display = url.length > 70 ? url.slice(0, 67) + \"...\" : url;\n      return new Text(\n        theme.fg(\"toolTitle\", theme.bold(\"fetch \")) + theme.fg(\"accent\", display),\n        0,\n        0,\n      );\n    },\n\n    renderResult: (\n      result: {\n        content?: Array<{ type: string; text?: string }>;\n        details?: Record<string, unknown>;\n      },\n      _options: { expanded: boolean; isPartial: boolean },\n      theme: WebRenderTheme,\n    ): Text => {\n      const details = result.details as { title?: string; error?: string } | undefined;\n      if (details?.error) {\n        return new Text(theme.fg(\"error\", `Error: ${details.error}`), 0, 0);\n      }\n      const title = details?.title ? `\"${details.title}\"` : \"\";\n      return new Text(theme.fg(\"success\", `Fetched ${title}`), 0, 0);\n    },\n  });\n\n  // ── Command: /web-status ─────────────────────────────────────────────────────\n\n  pi.registerCommand(\"web-status\", {\n    description: \"Show available search providers and config status\",\n    handler: async (_args: string, ctx: ExtensionContext) => {\n      ctx.ui.notify(formatStatus(pi, ctx), \"info\");\n    },\n  });\n};\n\nexport default webAccessExtension;\n"],"mappings":"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"}