lobster-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/brain/index.ts","../src/llm/errors.ts","../src/llm/openai-client.ts","../src/llm/utils.ts","../src/llm/client.ts","../src/browser/manager.ts","../src/utils/logger.ts","../src/browser/profiles.ts","../src/config/index.ts","../src/config/schema.ts","../src/browser/chrome-attach.ts","../src/browser/stealth.ts","../src/browser/dom/flat-tree.ts","../src/browser/dom/snapshot.ts","../src/browser/dom/compact-snapshot.ts","../src/browser/dom/semantic-tree.ts","../src/browser/dom/markdown.ts","../src/browser/dom/form-state.ts","../src/browser/dom/interactive.ts","../src/browser/interceptor.ts","../src/browser/semantic-find.ts","../src/browser/page-adapter.ts","../src/browser/lightpanda.ts","../src/pipeline/registry.ts","../src/pipeline/executor.ts","../src/pipeline/template.ts","../src/types/adapter.ts","../src/adapter/registry.ts","../src/discover/explore.ts","../src/discover/synthesize.ts","../src/cascade/index.ts","../src/router/decision.ts","../src/agent/core.ts","../src/agent/tools/click.ts","../src/agent/tools/type.ts","../src/agent/tools/scroll.ts","../src/agent/tools/select.ts","../src/agent/tools/wait.ts","../src/agent/tools/done.ts","../src/agent/tools/ask-user.ts","../src/agent/tools/execute-js.ts","../src/agent/tools/index.ts","../src/agent/macro-tool.ts","../src/agent/auto-fixer.ts","../src/domain-guard.ts","../src/output/table.ts","../src/output/json.ts","../src/output/markdown.ts","../src/output/csv.ts","../src/output/yaml.ts","../src/output/index.ts"],"sourcesContent":["/**\n * Brain — Intent classifier for LobsterCLI.\n *\n * Analyzes a user's question and decides what data sources are needed\n * to answer it. Uses a cheap/fast LLM call for classification,\n * with heuristic fallback when no LLM is available.\n *\n * Works in both CLI and extension contexts.\n */\n\nexport interface BrainDecision {\n /** Needs to SEE the page (images, layout, colors, visual content) */\n screenshot: boolean;\n /** Needs page text content (articles, paragraphs, written content) */\n markdown: boolean;\n /** Asking about forms, inputs, fields */\n forms: boolean;\n /** Asking about API calls, network requests */\n network: boolean;\n /** Brief description of what the user wants */\n intent: string;\n /** How the decision was made */\n source: 'llm' | 'heuristic';\n}\n\nconst CLASSIFIER_PROMPT = `You are an intent classifier for a web automation tool. Given a user's question about a webpage, decide what data sources are needed to answer it.\n\nRespond ONLY with a JSON object:\n{\n \"screenshot\": true/false,\n \"markdown\": true/false,\n \"forms\": true/false,\n \"network\": true/false,\n \"intent\": \"brief 5-word description\"\n}\n\nRules:\n- screenshot=true ONLY when the answer requires SEEING the page (images, visual layout, colors, charts, what something looks like)\n- markdown=true for ANY question about text content, meaning, topics, summaries\n- forms=true ONLY when specifically asking about form fields or inputs\n- network=true ONLY when asking about APIs, requests, or data fetching\n- Most questions need only markdown=true`;\n\n/**\n * Classify intent using LLM (requires a callable LLM function)\n */\nexport async function classifyIntent(\n prompt: string,\n pageTitle: string,\n llmCall?: (systemPrompt: string, userPrompt: string) => Promise<string>,\n): Promise<BrainDecision> {\n // If we have an LLM function, use it\n if (llmCall) {\n try {\n const systemPrompt = CLASSIFIER_PROMPT + `\\nCurrent page: \"${pageTitle}\"`;\n const response = await llmCall(systemPrompt, prompt);\n\n const jsonMatch = response.match(/\\{[\\s\\S]*?\\}/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n screenshot: !!parsed.screenshot,\n markdown: parsed.markdown !== false,\n forms: !!parsed.forms,\n network: !!parsed.network,\n intent: parsed.intent || '',\n source: 'llm',\n };\n }\n } catch {\n // Fall through to heuristic\n }\n }\n\n return heuristicClassify(prompt);\n}\n\n/**\n * Heuristic classification — no LLM needed, instant, free.\n */\nexport function heuristicClassify(prompt: string): BrainDecision {\n const lower = prompt.toLowerCase();\n\n const screenshot = /look|see|visual|image|screenshot|screen|what('s| is) (on|showing|displayed|visible)|describe.*layout|picture|colour|color|design|ui |logo|icon|chart|graph|photo|video|banner|appear/i.test(lower);\n\n const forms = /form|input|field|submit|login|sign.?in|password|checkbox|dropdown|select|textarea|search.?box|fill/i.test(lower);\n\n const network = /api|network|request|fetch|xhr|endpoint|call.*server|data.*load/i.test(lower);\n\n return {\n screenshot,\n markdown: true,\n forms,\n network,\n intent: 'heuristic classification',\n source: 'heuristic',\n };\n}\n","export enum InvokeErrorType {\n NETWORK_ERROR = 'NETWORK_ERROR',\n AUTH_ERROR = 'AUTH_ERROR',\n RATE_LIMIT = 'RATE_LIMIT',\n SERVER_ERROR = 'SERVER_ERROR',\n CONTEXT_LENGTH = 'CONTEXT_LENGTH',\n CONTENT_FILTER = 'CONTENT_FILTER',\n NO_TOOL_CALL = 'NO_TOOL_CALL',\n INVALID_TOOL_ARGS = 'INVALID_TOOL_ARGS',\n TOOL_EXECUTION_ERROR = 'TOOL_EXECUTION_ERROR',\n UNKNOWN = 'UNKNOWN',\n}\n\nexport class InvokeError extends Error {\n type: InvokeErrorType;\n retryable: boolean;\n rawError?: unknown;\n rawResponse?: unknown;\n\n constructor(type: InvokeErrorType, message: string, opts?: { retryable?: boolean; rawError?: unknown; rawResponse?: unknown }) {\n super(message);\n this.name = 'InvokeError';\n this.type = type;\n this.retryable = opts?.retryable ?? isRetryable(type);\n this.rawError = opts?.rawError;\n this.rawResponse = opts?.rawResponse;\n }\n}\n\nfunction isRetryable(type: InvokeErrorType): boolean {\n switch (type) {\n case InvokeErrorType.NETWORK_ERROR:\n case InvokeErrorType.RATE_LIMIT:\n case InvokeErrorType.SERVER_ERROR:\n case InvokeErrorType.NO_TOOL_CALL:\n case InvokeErrorType.INVALID_TOOL_ARGS:\n case InvokeErrorType.TOOL_EXECUTION_ERROR:\n case InvokeErrorType.UNKNOWN:\n return true;\n case InvokeErrorType.AUTH_ERROR:\n case InvokeErrorType.CONTEXT_LENGTH:\n case InvokeErrorType.CONTENT_FILTER:\n return false;\n }\n}\n","import type { Message, ToolCall } from '../types/llm.js';\nimport type { LLMTool } from '../types/llm.js';\nimport { InvokeError, InvokeErrorType } from './errors.js';\nimport type { LLMProvider } from '../config/schema.js';\n\nexport interface OpenAIClientConfig {\n baseURL: string;\n model: string;\n apiKey?: string;\n temperature?: number;\n provider?: LLMProvider;\n}\n\nexport class OpenAIClient {\n private config: OpenAIClientConfig;\n\n constructor(config: OpenAIClientConfig) {\n this.config = config;\n }\n\n /**\n * Build auth headers based on the provider.\n * - OpenAI/Gemini/Ollama: Bearer token\n * - Anthropic: x-api-key header + anthropic-version\n */\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (!this.config.apiKey) return headers;\n\n if (this.config.provider === 'anthropic') {\n headers['x-api-key'] = this.config.apiKey;\n headers['anthropic-version'] = '2023-06-01';\n } else {\n headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n }\n\n return headers;\n }\n\n /**\n * Build the request body based on provider.\n * Anthropic Messages API is different from OpenAI chat completions.\n */\n private buildBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n if (this.config.provider === 'anthropic') {\n return this.buildAnthropicBody(messages, tools, opts);\n }\n\n // OpenAI-compatible format (OpenAI, Gemini, Ollama all use this)\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (tools && tools.length > 0) {\n body.tools = tools;\n body.parallel_tool_calls = false;\n if (opts?.toolChoice) {\n body.tool_choice = typeof opts.toolChoice === 'string'\n ? opts.toolChoice\n : opts.toolChoice;\n }\n }\n\n return { url: `${this.config.baseURL}/chat/completions`, body };\n }\n\n /**\n * Build Anthropic Messages API request.\n * Converts OpenAI-style messages/tools to Anthropic format.\n */\n private buildAnthropicBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n // Extract system message\n let system: string | undefined;\n const anthropicMessages: Record<string, unknown>[] = [];\n\n for (const msg of messages) {\n if (msg.role === 'system') {\n system = msg.content as string;\n } else {\n anthropicMessages.push({\n role: msg.role === 'assistant' ? 'assistant' : 'user',\n content: msg.content,\n });\n }\n }\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages: anthropicMessages,\n max_tokens: 4096,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (system) body.system = system;\n\n // Convert OpenAI tools format to Anthropic tools format\n if (tools && tools.length > 0) {\n body.tools = tools.map((t) => {\n const fn = (t as any).function;\n return {\n name: fn.name,\n description: fn.description,\n input_schema: fn.parameters,\n };\n });\n\n if (opts?.toolChoice) {\n if (typeof opts.toolChoice === 'string') {\n body.tool_choice = opts.toolChoice === 'required'\n ? { type: 'any' }\n : { type: opts.toolChoice };\n } else {\n body.tool_choice = { type: 'tool', name: opts.toolChoice.function.name };\n }\n }\n }\n\n return { url: `${this.config.baseURL}/messages`, body };\n }\n\n /**\n * Parse Anthropic response into our unified format.\n */\n private parseAnthropicResponse(json: Record<string, unknown>): {\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n } {\n const content = json.content as any[];\n if (!content || !Array.isArray(content)) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No content in Anthropic response', { rawResponse: json });\n }\n\n let textContent: string | undefined;\n const toolCalls: ToolCall[] = [];\n\n for (const block of content) {\n if (block.type === 'text') {\n textContent = block.text;\n } else if (block.type === 'tool_use') {\n toolCalls.push({\n id: block.id,\n type: 'function',\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n });\n }\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n content: textContent,\n usage: usage ? {\n promptTokens: usage.input_tokens ?? 0,\n completionTokens: usage.output_tokens ?? 0,\n totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),\n } : undefined,\n };\n }\n\n async chatCompletion(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } }\n ): Promise<{\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n }> {\n const { url, body } = this.buildBody(messages, tools, opts);\n const headers = this.buildHeaders();\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n } catch (err) {\n throw new InvokeError(InvokeErrorType.NETWORK_ERROR, `Network error: ${err}`, { rawError: err });\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n if (response.status === 401) {\n throw new InvokeError(InvokeErrorType.AUTH_ERROR, `Authentication failed: ${text}`, { retryable: false, rawResponse: text });\n }\n if (response.status === 429) {\n throw new InvokeError(InvokeErrorType.RATE_LIMIT, `Rate limited: ${text}`, { rawResponse: text });\n }\n if (response.status >= 500) {\n throw new InvokeError(InvokeErrorType.SERVER_ERROR, `Server error ${response.status}: ${text}`, { rawResponse: text });\n }\n throw new InvokeError(InvokeErrorType.UNKNOWN, `HTTP ${response.status}: ${text}`, { rawResponse: text });\n }\n\n const json = await response.json() as Record<string, unknown>;\n\n // Route to provider-specific parser\n if (this.config.provider === 'anthropic') {\n return this.parseAnthropicResponse(json);\n }\n\n // OpenAI-compatible response parsing (OpenAI, Gemini, Ollama)\n const choice = (json.choices as any[])?.[0];\n if (!choice) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No choices in response', { rawResponse: json });\n }\n\n const message = choice.message;\n const finishReason = choice.finish_reason;\n\n if (finishReason === 'content_filter') {\n throw new InvokeError(InvokeErrorType.CONTENT_FILTER, 'Content filtered', { retryable: false, rawResponse: json });\n }\n\n if (finishReason === 'length') {\n throw new InvokeError(InvokeErrorType.CONTEXT_LENGTH, 'Context length exceeded', { retryable: false, rawResponse: json });\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: message.tool_calls as ToolCall[] | undefined,\n content: message.content as string | undefined,\n usage: usage ? {\n promptTokens: usage.prompt_tokens ?? 0,\n completionTokens: usage.completion_tokens ?? 0,\n totalTokens: usage.total_tokens ?? 0,\n } : undefined,\n };\n }\n}\n","import type { z } from 'zod';\nimport type { LLMTool } from '../types/llm.js';\n\nexport function zodToJsonSchema(schema: z.ZodType): Record<string, unknown> {\n // Simplified Zod-to-JSON-Schema converter for common types\n if ('_def' in schema) {\n const def = (schema as any)._def;\n const typeName = def.typeName;\n\n if (typeName === 'ZodObject') {\n const shape = def.shape();\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = zodToJsonSchema(value as z.ZodType);\n if (!((value as any)._def?.typeName === 'ZodOptional')) {\n required.push(key);\n }\n }\n const result: Record<string, unknown> = { type: 'object', properties };\n if (required.length > 0) result.required = required;\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodString') {\n const result: Record<string, unknown> = { type: 'string' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodNumber') {\n const result: Record<string, unknown> = { type: 'number' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodBoolean') {\n const result: Record<string, unknown> = { type: 'boolean' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodEnum') {\n return { type: 'string', enum: def.values, ...(def.description ? { description: def.description } : {}) };\n }\n\n if (typeName === 'ZodArray') {\n return { type: 'array', items: zodToJsonSchema(def.type), ...(def.description ? { description: def.description } : {}) };\n }\n\n if (typeName === 'ZodOptional') {\n return zodToJsonSchema(def.innerType);\n }\n\n if (typeName === 'ZodDefault') {\n const inner = zodToJsonSchema(def.innerType);\n return { ...inner, default: def.defaultValue() };\n }\n\n if (typeName === 'ZodUnion') {\n return { oneOf: def.options.map((opt: z.ZodType) => zodToJsonSchema(opt)) };\n }\n\n if (typeName === 'ZodRecord') {\n return { type: 'object', additionalProperties: zodToJsonSchema(def.valueType) };\n }\n\n if (typeName === 'ZodLiteral') {\n return { const: def.value };\n }\n\n if (typeName === 'ZodAny') {\n return {};\n }\n }\n\n return { type: 'string' };\n}\n\nexport function zodToOpenAITool(name: string, description: string, schema: z.ZodType): LLMTool {\n return {\n type: 'function',\n function: {\n name,\n description,\n parameters: zodToJsonSchema(schema),\n },\n };\n}\n","import type { z } from 'zod';\nimport type { Message, InvokeResult, LLMTool } from '../types/llm.js';\nimport type { LLMConfig } from '../types/llm.js';\nimport { OpenAIClient } from './openai-client.js';\nimport { InvokeError, InvokeErrorType } from './errors.js';\nimport { zodToOpenAITool } from './utils.js';\n\nexport interface MacroTool {\n name: string;\n description: string;\n schema: z.ZodType;\n execute: (args: Record<string, unknown>) => Promise<string>;\n}\n\nexport class LLM {\n private client: OpenAIClient;\n private config: LLMConfig;\n\n constructor(config: LLMConfig) {\n this.config = config;\n this.client = new OpenAIClient({\n baseURL: config.baseURL,\n model: config.model,\n apiKey: config.apiKey,\n temperature: config.temperature,\n provider: config.provider as any,\n });\n }\n\n async invoke(\n messages: Message[],\n tool: MacroTool,\n abortSignal?: AbortSignal\n ): Promise<InvokeResult> {\n const openaiTool = zodToOpenAITool(tool.name, tool.description, tool.schema);\n\n return this.withRetry(async () => {\n if (abortSignal?.aborted) throw new Error('Aborted');\n\n const response = await this.client.chatCompletion(\n messages,\n [openaiTool],\n { toolChoice: { type: 'function', function: { name: tool.name } } }\n );\n\n // Extract tool call\n const toolCall = response.toolCalls?.[0];\n if (!toolCall) {\n // Try to extract from content (some models put JSON in content)\n if (response.content) {\n const extracted = extractJsonFromString(response.content);\n if (extracted) {\n const args = typeof extracted === 'string' ? JSON.parse(extracted) : extracted;\n const result = await tool.execute(args);\n return {\n toolCall: { name: tool.name, args },\n toolResult: result,\n usage: response.usage,\n };\n }\n }\n throw new InvokeError(InvokeErrorType.NO_TOOL_CALL, 'No tool call in response');\n }\n\n let args: Record<string, unknown>;\n try {\n args = JSON.parse(toolCall.function.arguments);\n } catch {\n // Try double-parse (some models double-stringify)\n try {\n args = JSON.parse(JSON.parse(toolCall.function.arguments));\n } catch {\n throw new InvokeError(InvokeErrorType.INVALID_TOOL_ARGS, `Invalid JSON in tool args: ${toolCall.function.arguments}`);\n }\n }\n\n let result: string;\n try {\n result = await tool.execute(args);\n } catch (err) {\n throw new InvokeError(InvokeErrorType.TOOL_EXECUTION_ERROR, `Tool execution failed: ${err}`, { rawError: err });\n }\n\n return {\n toolCall: { name: tool.name, args },\n toolResult: result,\n usage: response.usage,\n };\n });\n }\n\n private async withRetry<T>(fn: () => Promise<T>): Promise<T> {\n const maxRetries = this.config.maxRetries ?? 3;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (err instanceof InvokeError && !err.retryable) throw err;\n if (err instanceof Error && err.name === 'AbortError') throw err;\n if (attempt < maxRetries) {\n await new Promise((r) => setTimeout(r, 100 * (attempt + 1)));\n }\n }\n }\n\n throw lastError;\n }\n}\n\nfunction extractJsonFromString(str: string): unknown | null {\n const start = str.indexOf('{');\n const end = str.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) return null;\n try {\n return JSON.parse(str.slice(start, end + 1));\n } catch {\n return null;\n }\n}\n","import puppeteer, { type Browser, type Page } from 'puppeteer-core';\nimport { existsSync } from 'node:fs';\nimport { log } from '../utils/logger.js';\nimport { getProfileDataDir } from './profiles.js';\nimport { resolveAttachTarget } from './chrome-attach.js';\nimport { injectStealth, STEALTH_ARGS } from './stealth.js';\n\nexport interface BrowserManagerConfig {\n executablePath?: string;\n headless?: boolean;\n cdpEndpoint?: string;\n connectTimeout?: number;\n profile?: string;\n attach?: boolean | string;\n stealth?: boolean;\n}\n\nexport class BrowserManager {\n private browser: Browser | null = null;\n private config: BrowserManagerConfig;\n private isAttached = false;\n\n constructor(config: BrowserManagerConfig = {}) {\n this.config = config;\n }\n\n async connect(): Promise<Browser> {\n if (this.browser?.connected) return this.browser;\n\n // Priority 1: Attach to running Chrome\n if (this.config.attach) {\n const wsEndpoint = await resolveAttachTarget(this.config.attach);\n log.info(`Attaching to Chrome: ${wsEndpoint}`);\n this.browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint });\n this.isAttached = true;\n return this.browser;\n }\n\n // Priority 2: Connect to CDP endpoint\n if (this.config.cdpEndpoint) {\n log.debug(`Connecting to CDP endpoint: ${this.config.cdpEndpoint}`);\n this.browser = await puppeteer.connect({\n browserWSEndpoint: this.config.cdpEndpoint,\n });\n this.isAttached = true;\n return this.browser;\n }\n\n // Priority 3: Launch new Chrome\n const executablePath = this.config.executablePath || findChrome();\n if (!executablePath) {\n throw new Error(\n 'Chrome/Chromium not found. Set LOBSTER_BROWSER_PATH or config browser.executablePath'\n );\n }\n\n // Build launch args\n const args = [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n '--disable-gpu',\n ];\n\n // Stealth args\n if (this.config.stealth) {\n args.push(...STEALTH_ARGS);\n }\n\n // Profile — set user data directory\n let userDataDir: string | undefined;\n if (this.config.profile) {\n userDataDir = getProfileDataDir(this.config.profile);\n log.info(`Using profile \"${this.config.profile}\" → ${userDataDir}`);\n }\n\n log.debug(`Launching Chrome: ${executablePath}`);\n this.browser = await puppeteer.launch({\n executablePath,\n headless: this.config.headless ?? true,\n userDataDir,\n args,\n });\n\n this.isAttached = false;\n return this.browser;\n }\n\n async newPage(): Promise<Page> {\n const browser = await this.connect();\n const page = await browser.newPage();\n\n // Inject stealth scripts before any navigation\n if (this.config.stealth) {\n await injectStealth(page);\n log.debug('Stealth mode enabled');\n }\n\n return page;\n }\n\n async close(): Promise<void> {\n if (this.browser) {\n if (this.isAttached) {\n // Don't close user's browser — just disconnect\n this.browser.disconnect();\n log.debug('Disconnected from Chrome (attached mode)');\n } else {\n await this.browser.close().catch(() => {});\n }\n this.browser = null;\n }\n }\n}\n\nfunction findChrome(): string | undefined {\n const paths =\n process.platform === 'darwin'\n ? [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n ]\n : process.platform === 'win32'\n ? [\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n 'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n ]\n : [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/chromium',\n ];\n\n return paths.find((p) => existsSync(p));\n}\n","import chalk from 'chalk';\n\nexport const log = {\n info: (msg: string) => console.log(chalk.blue('ℹ'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg),\n debug: (msg: string) => {\n if (process.env.LOBSTER_DEBUG) console.log(chalk.gray('⋯'), msg);\n },\n step: (n: number, msg: string) => console.log(chalk.cyan(`[${n}]`), msg),\n dim: (msg: string) => console.log(chalk.dim(msg)),\n};\n","/**\n * Persistent Profiles — store Chrome user data dirs so cookies,\n * auth, and extensions survive across sessions.\n *\n * Inspired by PinchTab's profile management, built from scratch.\n *\n * Storage: ~/.lobster/profiles/<name>/\n * Metadata: ~/.lobster/profiles/<name>/.lobster-meta.json\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, rmSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getConfigDir } from '../config/index.js';\nimport { log } from '../utils/logger.js';\n\nexport interface ProfileMeta {\n name: string;\n createdAt: string;\n lastUsed: string;\n sizeMB?: number;\n}\n\nconst PROFILES_DIR = () => join(getConfigDir(), 'profiles');\nconst META_FILE = '.lobster-meta.json';\n\n// Name validation: safe across Windows/Mac/Linux, no path traversal\nconst VALID_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;\nconst RESERVED_NAMES = new Set([\n 'default', 'system', 'con', 'prn', 'aux', 'nul',\n 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9',\n 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9',\n]);\n\n// Directories to delete on cache reset (keep cookies, extensions, local storage)\nconst CACHE_DIRS = [\n 'Cache', 'Code Cache', 'GPUCache', 'GrShaderCache', 'ShaderCache',\n 'Service Worker', 'Sessions', 'Session Storage', 'blob_storage',\n];\n\nfunction ensureProfilesDir(): void {\n const dir = PROFILES_DIR();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nfunction validateName(name: string): void {\n if (!VALID_NAME.test(name)) {\n throw new Error(`Invalid profile name \"${name}\". Use only letters, numbers, hyphens, underscores (max 64 chars).`);\n }\n if (RESERVED_NAMES.has(name.toLowerCase())) {\n throw new Error(`\"${name}\" is a reserved name. Choose a different profile name.`);\n }\n}\n\nfunction getProfileDir(name: string): string {\n return join(PROFILES_DIR(), name);\n}\n\nfunction readMeta(profileDir: string): ProfileMeta | null {\n const metaPath = join(profileDir, META_FILE);\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(profileDir: string, meta: ProfileMeta): void {\n writeFileSync(join(profileDir, META_FILE), JSON.stringify(meta, null, 2));\n}\n\nfunction getDirSizeMB(dirPath: string): number {\n let total = 0;\n try {\n const entries = readdirSync(dirPath, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isFile()) {\n total += statSync(fullPath).size;\n } else if (entry.isDirectory() && entry.name !== '.lobster-meta.json') {\n total += getDirSizeMB(fullPath) * 1024 * 1024; // recursive returns MB\n }\n }\n } catch {}\n return Math.round((total / (1024 * 1024)) * 10) / 10;\n}\n\n/**\n * Create a new profile.\n */\nexport function createProfile(name: string): ProfileMeta {\n validateName(name);\n ensureProfilesDir();\n\n const dir = getProfileDir(name);\n if (existsSync(dir)) {\n throw new Error(`Profile \"${name}\" already exists.`);\n }\n\n mkdirSync(dir, { recursive: true });\n\n const meta: ProfileMeta = {\n name,\n createdAt: new Date().toISOString(),\n lastUsed: new Date().toISOString(),\n };\n\n writeMeta(dir, meta);\n log.success(`Profile \"${name}\" created at ${dir}`);\n return meta;\n}\n\n/**\n * List all profiles.\n */\nexport function listProfiles(): ProfileMeta[] {\n ensureProfilesDir();\n const dir = PROFILES_DIR();\n const profiles: ProfileMeta[] = [];\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const profileDir = join(dir, entry.name);\n const meta = readMeta(profileDir);\n if (meta) {\n meta.sizeMB = getDirSizeMB(profileDir);\n profiles.push(meta);\n } else {\n // Directory exists but no meta — create meta\n profiles.push({\n name: entry.name,\n createdAt: 'unknown',\n lastUsed: 'unknown',\n sizeMB: getDirSizeMB(profileDir),\n });\n }\n }\n } catch {}\n\n return profiles.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Remove a profile and all its data.\n */\nexport function removeProfile(name: string): void {\n const dir = getProfileDir(name);\n if (!existsSync(dir)) {\n throw new Error(`Profile \"${name}\" does not exist.`);\n }\n\n rmSync(dir, { recursive: true, force: true });\n log.success(`Profile \"${name}\" deleted.`);\n}\n\n/**\n * Get the Chrome user data directory for a profile.\n * Updates lastUsed timestamp.\n */\nexport function getProfileDataDir(name: string): string {\n validateName(name);\n const dir = getProfileDir(name);\n\n if (!existsSync(dir)) {\n // Auto-create if doesn't exist\n createProfile(name);\n } else {\n // Update lastUsed\n const meta = readMeta(dir) || { name, createdAt: 'unknown', lastUsed: '' };\n meta.lastUsed = new Date().toISOString();\n writeMeta(dir, meta);\n }\n\n return dir;\n}\n\n/**\n * Reset cache directories but keep cookies, extensions, and local storage.\n */\nexport function resetProfileCache(name: string): void {\n const dir = getProfileDir(name);\n if (!existsSync(dir)) {\n throw new Error(`Profile \"${name}\" does not exist.`);\n }\n\n let cleaned = 0;\n for (const cacheDir of CACHE_DIRS) {\n // Check both root and Default/ subdirectory\n for (const base of [dir, join(dir, 'Default')]) {\n const target = join(base, cacheDir);\n if (existsSync(target)) {\n rmSync(target, { recursive: true, force: true });\n cleaned++;\n }\n }\n }\n\n log.success(`Profile \"${name}\" cache reset (${cleaned} directories cleaned).`);\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport yaml from 'js-yaml';\nimport { configSchema, type LobsterConfig } from './schema.js';\nimport { DEFAULT_CONFIG } from './defaults.js';\n\nexport type { LobsterConfig };\n\nconst CONFIG_DIR = join(homedir(), '.lobster');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.yaml');\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): LobsterConfig {\n ensureConfigDir();\n\n let fileConfig: Record<string, unknown> = {};\n if (existsSync(CONFIG_FILE)) {\n const raw = readFileSync(CONFIG_FILE, 'utf-8');\n fileConfig = (yaml.load(raw) as Record<string, unknown>) || {};\n }\n\n // Env var overrides\n const envOverrides: Record<string, unknown> = {};\n if (process.env.LOBSTER_API_KEY) {\n envOverrides.llm = { ...(fileConfig.llm as Record<string, unknown> || {}), apiKey: process.env.LOBSTER_API_KEY };\n }\n if (process.env.LOBSTER_MODEL) {\n envOverrides.llm = { ...(envOverrides.llm as Record<string, unknown> || fileConfig.llm as Record<string, unknown> || {}), model: process.env.LOBSTER_MODEL };\n }\n if (process.env.LOBSTER_BASE_URL) {\n envOverrides.llm = { ...(envOverrides.llm as Record<string, unknown> || fileConfig.llm as Record<string, unknown> || {}), baseURL: process.env.LOBSTER_BASE_URL };\n }\n if (process.env.LOBSTER_CDP_ENDPOINT) {\n envOverrides.browser = { ...(fileConfig.browser as Record<string, unknown> || {}), cdpEndpoint: process.env.LOBSTER_CDP_ENDPOINT };\n }\n if (process.env.LOBSTER_BROWSER_PATH) {\n envOverrides.browser = { ...(envOverrides.browser as Record<string, unknown> || fileConfig.browser as Record<string, unknown> || {}), executablePath: process.env.LOBSTER_BROWSER_PATH };\n }\n\n const merged = { ...fileConfig, ...envOverrides };\n return configSchema.parse(merged);\n}\n\nexport function saveConfig(config: Partial<LobsterConfig>): void {\n ensureConfigDir();\n const existing = loadConfig();\n const merged = deepMerge(existing, config);\n writeFileSync(CONFIG_FILE, yaml.dump(merged, { indent: 2 }), 'utf-8');\n}\n\nexport function setConfigValue(keyPath: string, value: string): void {\n const parts = keyPath.split('.');\n const obj: Record<string, unknown> = {};\n let current: Record<string, unknown> = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n // Try to parse as number or boolean\n let parsed: unknown = value;\n if (value === 'true') parsed = true;\n else if (value === 'false') parsed = false;\n else if (!isNaN(Number(value)) && value !== '') parsed = Number(value);\n\n current[parts[parts.length - 1]] = parsed;\n saveConfig(obj as Partial<LobsterConfig>);\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result = { ...target };\n for (const key of Object.keys(source)) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) &&\n target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {\n result[key] = deepMerge(target[key] as Record<string, unknown>, source[key] as Record<string, unknown>);\n } else {\n result[key] = source[key];\n }\n }\n return result;\n}\n","import { z } from 'zod';\n\nexport const LLM_PROVIDERS = {\n openai: {\n name: 'OpenAI',\n baseURL: 'https://api.openai.com/v1',\n defaultModel: 'gpt-4o',\n keyPrefix: 'sk-',\n keyEnvHint: 'https://platform.openai.com/api-keys',\n models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1', 'o1-mini', 'o3-mini'],\n },\n anthropic: {\n name: 'Anthropic',\n baseURL: 'https://api.anthropic.com/v1',\n defaultModel: 'claude-sonnet-4-20250514',\n keyPrefix: 'sk-ant-',\n keyEnvHint: 'https://console.anthropic.com/settings/keys',\n models: ['claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-haiku-4-5-20251001'],\n },\n gemini: {\n name: 'Google Gemini',\n baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',\n defaultModel: 'gemini-2.5-flash',\n keyPrefix: 'AI',\n keyEnvHint: 'https://aistudio.google.com/apikey',\n models: ['gemini-2.5-flash', 'gemini-2.5-flash-lite', 'gemini-2.5-pro', 'gemini-3-flash-preview'],\n },\n ollama: {\n name: 'Ollama (local, free)',\n baseURL: 'http://localhost:11434/v1',\n defaultModel: 'llama3.1',\n keyPrefix: '',\n keyEnvHint: 'No API key needed — install from https://ollama.ai',\n models: ['llama3.1', 'llama3.2', 'mistral', 'codestral', 'qwen2.5', 'deepseek-r1'],\n },\n} as const;\n\nexport type LLMProvider = keyof typeof LLM_PROVIDERS;\n\nexport const configSchema = z.object({\n llm: z.object({\n provider: z.enum(['openai', 'anthropic', 'gemini', 'ollama']).default('openai'),\n baseURL: z.string().default('https://api.openai.com/v1'),\n model: z.string().default('gpt-4o'),\n apiKey: z.string().default(''),\n temperature: z.number().min(0).max(2).default(0.1),\n maxRetries: z.number().int().min(0).default(3),\n }).default({}),\n browser: z.object({\n executablePath: z.string().default(''),\n headless: z.boolean().default(true),\n connectTimeout: z.number().default(30),\n commandTimeout: z.number().default(60),\n cdpEndpoint: z.string().default(''),\n profile: z.string().default(''),\n stealth: z.boolean().default(false),\n }).default({}),\n agent: z.object({\n maxSteps: z.number().int().default(40),\n stepDelay: z.number().default(0.4),\n }).default({}),\n domains: z.object({\n allow: z.array(z.string()).default([]),\n block: z.array(z.string()).default([]),\n blockMessage: z.string().default(''),\n }).default({}),\n output: z.object({\n defaultFormat: z.enum(['table', 'json', 'yaml', 'markdown', 'csv']).default('table'),\n color: z.boolean().default(true),\n }).default({}),\n});\n\nexport type LobsterConfig = z.infer<typeof configSchema>;\n","/**\n * Chrome Attach — discover and connect to a running Chrome instance.\n *\n * Probes common debug ports for Chrome's /json/version endpoint\n * and returns the WebSocket debugger URL for Puppeteer.connect().\n *\n * Inspired by PinchTab's attach mode, built from scratch.\n */\n\nimport http from 'node:http';\nimport { log } from '../utils/logger.js';\n\nexport interface ChromeDiscoveryResult {\n wsEndpoint: string;\n port: number;\n version: string;\n browser: string;\n}\n\nconst DEFAULT_PORTS = [9222, 9229, 9333, 9515];\nconst PROBE_TIMEOUT = 1500; // ms\n\n/**\n * Probe a single port for Chrome's DevTools endpoint.\n */\nfunction probePort(port: number): Promise<ChromeDiscoveryResult | null> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${port}/json/version`, {\n timeout: PROBE_TIMEOUT,\n }, (res) => {\n let data = '';\n res.on('data', (chunk: string) => { data += chunk; });\n res.on('end', () => {\n try {\n const info = JSON.parse(data);\n if (info.webSocketDebuggerUrl) {\n resolve({\n wsEndpoint: info.webSocketDebuggerUrl,\n port,\n version: info['Protocol-Version'] || '',\n browser: info.Browser || '',\n });\n } else {\n resolve(null);\n }\n } catch {\n resolve(null);\n }\n });\n });\n\n req.on('error', () => resolve(null));\n req.on('timeout', () => { req.destroy(); resolve(null); });\n });\n}\n\n/**\n * Discover a running Chrome instance by probing common debug ports.\n * Returns the first responding instance, or null if none found.\n */\nexport async function discoverChrome(ports?: number[]): Promise<ChromeDiscoveryResult | null> {\n const portsToCheck = ports || DEFAULT_PORTS;\n log.debug(`Scanning ports for Chrome: ${portsToCheck.join(', ')}`);\n\n // Probe all ports in parallel for speed\n const results = await Promise.all(portsToCheck.map(probePort));\n const found = results.find(Boolean) || null;\n\n if (found) {\n log.info(`Found Chrome on port ${found.port}: ${found.browser}`);\n } else {\n log.debug('No running Chrome instance found on debug ports.');\n }\n\n return found;\n}\n\n/**\n * Get WebSocket debugger URL from a specific port.\n */\nexport async function getWebSocketDebuggerUrl(port: number): Promise<string | null> {\n const result = await probePort(port);\n return result?.wsEndpoint || null;\n}\n\n/**\n * Parse an attach target — could be:\n * - \"true\" / true → auto-discover\n * - \"ws://...\" → explicit WebSocket URL\n * - \"9222\" → specific port number\n */\nexport async function resolveAttachTarget(target: boolean | string): Promise<string> {\n if (target === true || target === 'true') {\n const result = await discoverChrome();\n if (!result) {\n throw new Error(\n 'No running Chrome found. Start Chrome with:\\n' +\n ' google-chrome --remote-debugging-port=9222\\n' +\n ' # or on Mac:\\n' +\n ' /Applications/Google\\\\ Chrome.app/Contents/MacOS/Google\\\\ Chrome --remote-debugging-port=9222'\n );\n }\n return result.wsEndpoint;\n }\n\n if (typeof target === 'string') {\n // Explicit WebSocket URL\n if (target.startsWith('ws://') || target.startsWith('wss://')) {\n return target;\n }\n\n // Port number\n const port = parseInt(target, 10);\n if (!isNaN(port) && port > 0 && port < 65536) {\n const url = await getWebSocketDebuggerUrl(port);\n if (!url) {\n throw new Error(`No Chrome found on port ${port}. Make sure Chrome is running with --remote-debugging-port=${port}`);\n }\n return url;\n }\n\n throw new Error(`Invalid attach target: \"${target}\". Use \"true\" for auto-discover, a port number, or a ws:// URL.`);\n }\n\n throw new Error('Invalid attach target.');\n}\n","/**\n * Stealth Mode — anti-bot detection scripts.\n *\n * Injected via page.evaluateOnNewDocument() so it runs before\n * any page JavaScript, on every navigation.\n *\n * Inspired by PinchTab's 3-tier stealth system, built from scratch.\n * This is a comprehensive single-tier implementation covering the\n * most critical detection vectors.\n */\n\nimport type { Page } from 'puppeteer-core';\n\n/**\n * Comprehensive stealth script that evades common bot detection.\n */\nexport const STEALTH_SCRIPT = `\n(() => {\n // ── 1. navigator.webdriver removal ──\n // Most important: this is the #1 detection vector\n Object.defineProperty(navigator, 'webdriver', {\n get: () => undefined,\n configurable: true,\n });\n\n // Also delete from prototype\n delete Object.getPrototypeOf(navigator).webdriver;\n\n // ── 2. CDP marker removal ──\n // Chrome DevTools Protocol injects cdc_* properties on window\n for (const key of Object.keys(window)) {\n if (/^cdc_|^__webdriver|^__selenium|^__driver/.test(key)) {\n try { delete window[key]; } catch {}\n }\n }\n\n // ── 3. Chrome runtime spoofing ──\n // Real Chrome has window.chrome with runtime, loadTimes, csi\n if (!window.chrome) {\n window.chrome = {};\n }\n if (!window.chrome.runtime) {\n window.chrome.runtime = {\n connect: function() {},\n sendMessage: function() {},\n onMessage: { addListener: function() {} },\n id: undefined,\n };\n }\n if (!window.chrome.loadTimes) {\n window.chrome.loadTimes = function() {\n return {\n commitLoadTime: Date.now() / 1000 - 0.5,\n connectionInfo: 'h2',\n finishDocumentLoadTime: Date.now() / 1000 - 0.1,\n finishLoadTime: Date.now() / 1000 - 0.05,\n firstPaintAfterLoadTime: 0,\n firstPaintTime: Date.now() / 1000 - 0.3,\n navigationType: 'Other',\n npnNegotiatedProtocol: 'h2',\n requestTime: Date.now() / 1000 - 1,\n startLoadTime: Date.now() / 1000 - 0.8,\n wasAlternateProtocolAvailable: false,\n wasFetchedViaSpdy: true,\n wasNpnNegotiated: true,\n };\n };\n }\n if (!window.chrome.csi) {\n window.chrome.csi = function() {\n return {\n onloadT: Date.now(),\n startE: Date.now() - 500,\n pageT: 500,\n tran: 15,\n };\n };\n }\n\n // ── 4. Plugin array spoofing ──\n // Headless Chrome reports empty plugins; real Chrome has at least 2\n const fakePlugins = [\n { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format', length: 1 },\n { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '', length: 1 },\n { name: 'Native Client', filename: 'internal-nacl-plugin', description: '', length: 2 },\n ];\n\n Object.defineProperty(navigator, 'plugins', {\n get: () => {\n const arr = fakePlugins.map(p => {\n const plugin = { ...p, item: (i) => plugin, namedItem: (n) => plugin };\n return plugin;\n });\n arr.item = (i) => arr[i];\n arr.namedItem = (n) => arr.find(p => p.name === n);\n arr.refresh = () => {};\n return arr;\n },\n });\n\n // ── 5. Languages ──\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US', 'en'],\n });\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n });\n\n // ── 6. Platform consistency ──\n // Ensure platform matches user agent\n const platform = navigator.userAgent.includes('Mac') ? 'MacIntel' :\n navigator.userAgent.includes('Win') ? 'Win32' :\n navigator.userAgent.includes('Linux') ? 'Linux x86_64' : navigator.platform;\n Object.defineProperty(navigator, 'platform', { get: () => platform });\n\n // ── 7. Hardware concurrency & device memory ──\n // Headless often reports unusual values\n if (navigator.hardwareConcurrency < 2) {\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });\n }\n if (!navigator.deviceMemory || navigator.deviceMemory < 2) {\n Object.defineProperty(navigator, 'deviceMemory', { get: () => 8 });\n }\n\n // ── 8. WebGL vendor/renderer spoofing ──\n // Headless reports \"Google SwiftShader\" which is a dead giveaway\n const origGetParameter = WebGLRenderingContext.prototype.getParameter;\n WebGLRenderingContext.prototype.getParameter = function(param) {\n // UNMASKED_VENDOR_WEBGL\n if (param === 0x9245) return 'Intel Inc.';\n // UNMASKED_RENDERER_WEBGL\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return origGetParameter.call(this, param);\n };\n\n // Also for WebGL2\n if (typeof WebGL2RenderingContext !== 'undefined') {\n const origGetParameter2 = WebGL2RenderingContext.prototype.getParameter;\n WebGL2RenderingContext.prototype.getParameter = function(param) {\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return origGetParameter2.call(this, param);\n };\n }\n\n // ── 9. Canvas fingerprint noise ──\n // Adds subtle deterministic noise to canvas output based on domain\n const seed = location.hostname.split('').reduce((a, c) => a + c.charCodeAt(0), 0);\n const origToDataURL = HTMLCanvasElement.prototype.toDataURL;\n HTMLCanvasElement.prototype.toDataURL = function(type) {\n const ctx = this.getContext('2d');\n if (ctx && this.width > 0 && this.height > 0) {\n try {\n const imageData = ctx.getImageData(0, 0, 1, 1);\n // Flip a single pixel with seeded noise\n imageData.data[0] = (imageData.data[0] + seed) % 256;\n ctx.putImageData(imageData, 0, 0);\n } catch {}\n }\n return origToDataURL.apply(this, arguments);\n };\n\n // ── 10. Permissions API ──\n // Headless returns 'denied' for notifications; real Chrome returns 'prompt'\n const origQuery = navigator.permissions?.query?.bind(navigator.permissions);\n if (origQuery) {\n navigator.permissions.query = function(descriptor) {\n if (descriptor.name === 'notifications') {\n return Promise.resolve({ state: Notification.permission || 'prompt', onchange: null });\n }\n return origQuery(descriptor);\n };\n }\n\n // ── 11. Notification constructor ──\n if (!window.Notification) {\n window.Notification = function() {};\n window.Notification.permission = 'default';\n window.Notification.requestPermission = () => Promise.resolve('default');\n }\n\n // ── 12. Connection type ──\n if (navigator.connection) {\n Object.defineProperty(navigator.connection, 'rtt', { get: () => 50 });\n }\n})()\n`;\n\n/**\n * Inject stealth script into a Puppeteer page.\n * Must be called before first navigation for full effectiveness.\n */\nexport async function injectStealth(page: Page): Promise<void> {\n await page.evaluateOnNewDocument(STEALTH_SCRIPT);\n}\n\n/**\n * Chrome launch args for stealth mode.\n */\nexport const STEALTH_ARGS = [\n '--disable-blink-features=AutomationControlled',\n '--disable-features=IsolateOrigins,site-per-process',\n '--disable-infobars',\n '--window-size=1920,1080',\n];\n","/**\n * Script that runs inside the browser to extract a flat DOM tree\n * with indexed interactive elements — the format the AI agent uses.\n *\n * Based on Page Agent's DOM extraction approach.\n */\nexport const FLAT_TREE_SCRIPT = `\n(() => {\n const INTERACTIVE_TAGS = new Set([\n 'a', 'button', 'input', 'select', 'textarea', 'details', 'summary',\n 'label', 'option', 'fieldset', 'legend',\n ]);\n\n const INTERACTIVE_ROLES = new Set([\n 'button', 'link', 'textbox', 'checkbox', 'radio', 'combobox',\n 'listbox', 'menu', 'menuitem', 'tab', 'switch', 'slider',\n 'searchbox', 'spinbutton', 'option', 'menuitemcheckbox', 'menuitemradio',\n ]);\n\n const ATTR_WHITELIST = [\n 'type', 'role', 'aria-label', 'aria-expanded', 'aria-selected',\n 'aria-checked', 'aria-disabled', 'placeholder', 'title', 'href',\n 'value', 'name', 'alt', 'src',\n ];\n\n let highlightIndex = 0;\n const nodes = {};\n const selectorMap = {};\n\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0) return false;\n const style = getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n return true;\n }\n\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) return true;\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.getAttribute('contenteditable') === 'true') return true;\n if (el.getAttribute('tabindex') !== null && parseInt(el.getAttribute('tabindex')) >= 0) return true;\n if (el.onclick || el.getAttribute('onclick')) return true;\n return false;\n }\n\n function getAttributes(el) {\n const attrs = {};\n for (const attr of ATTR_WHITELIST) {\n const val = el.getAttribute(attr);\n if (val !== null && val !== '') attrs[attr] = val;\n }\n return attrs;\n }\n\n function getScrollable(el) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n const overflowX = style.overflowX;\n const isScrollableY = (overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight;\n const isScrollableX = (overflowX === 'auto' || overflowX === 'scroll') && el.scrollWidth > el.clientWidth;\n if (!isScrollableY && !isScrollableX) return null;\n return {\n left: el.scrollLeft,\n top: el.scrollTop,\n right: el.scrollWidth - el.clientWidth - el.scrollLeft,\n bottom: el.scrollHeight - el.clientHeight - el.scrollTop,\n };\n }\n\n function walk(el, parentId) {\n if (!el || el.nodeType === 8) return; // skip comments\n\n if (el.nodeType === 3) { // text node\n const text = el.textContent.trim();\n if (!text) return;\n const id = 'text_' + Math.random().toString(36).slice(2, 8);\n nodes[id] = { id, tagName: '#text', text, parentId };\n if (parentId && nodes[parentId]) {\n nodes[parentId].children = nodes[parentId].children || [];\n nodes[parentId].children.push(id);\n }\n return;\n }\n\n if (el.nodeType !== 1) return; // only elements\n\n const tag = el.tagName.toLowerCase();\n if (['script', 'style', 'noscript', 'svg', 'path'].includes(tag)) return;\n if (!isVisible(el)) return;\n\n const id = tag + '_' + Math.random().toString(36).slice(2, 8);\n const interactive = isInteractive(el);\n const node = {\n id,\n tagName: tag,\n attributes: getAttributes(el),\n parentId,\n children: [],\n isInteractive: interactive,\n };\n\n if (interactive) {\n node.highlightIndex = highlightIndex;\n selectorMap[highlightIndex] = id;\n highlightIndex++;\n }\n\n const scrollable = getScrollable(el);\n if (scrollable) node.scrollable = scrollable;\n\n const text = [];\n for (const child of el.childNodes) {\n if (child.nodeType === 3 && child.textContent.trim()) {\n text.push(child.textContent.trim());\n }\n }\n if (text.length > 0) node.text = text.join(' ').slice(0, 200);\n\n nodes[id] = node;\n\n if (parentId && nodes[parentId]) {\n nodes[parentId].children.push(id);\n }\n\n for (const child of el.children) {\n walk(child, id);\n }\n }\n\n const rootId = 'root';\n nodes[rootId] = { id: rootId, tagName: 'body', children: [], attributes: {} };\n for (const child of document.body.children) {\n walk(child, rootId);\n }\n\n return { rootId, map: nodes, selectorMap };\n})()\n`;\n\n/**\n * Convert a FlatDomTree into the indexed text format that the LLM agent reads.\n * Example output:\n * [0]<button type=submit>Search</>\n * [1]<input type=text placeholder=\"Enter query\" />\n */\nexport function flatTreeToString(tree: { rootId: string; map: Record<string, any> }): string {\n const lines: string[] = [];\n\n function walk(nodeId: string, depth: number) {\n const node = tree.map[nodeId];\n if (!node) return;\n\n const indent = '\\t'.repeat(depth);\n\n if (node.tagName === '#text') {\n if (node.text) lines.push(`${indent}${node.text}`);\n return;\n }\n\n const attrs = node.attributes || {};\n const attrStr = Object.entries(attrs)\n .map(([k, v]) => (v === '' ? k : `${k}=\"${v}\"`))\n .join(' ');\n\n const prefix = node.highlightIndex !== undefined ? `[${node.highlightIndex}]` : '';\n const scrollInfo = node.scrollable\n ? ` |scroll: ${Math.round(node.scrollable.top)}px up, ${Math.round(node.scrollable.bottom)}px down|`\n : '';\n\n const text = node.text || '';\n const tag = node.tagName;\n\n if (prefix || text || node.children?.length > 0) {\n const opening = `${indent}${prefix}<${tag}${attrStr ? ' ' + attrStr : ''}${scrollInfo}>`;\n\n if (!node.children?.length || (node.children.length === 0 && text)) {\n lines.push(`${opening}${text}</>`);\n } else {\n lines.push(`${opening}${text}`);\n for (const childId of node.children || []) {\n walk(childId, depth + 1);\n }\n }\n } else {\n for (const childId of node.children || []) {\n walk(childId, depth);\n }\n }\n }\n\n walk(tree.rootId, 0);\n return lines.join('\\n');\n}\n","/**\n * Advanced DOM snapshot script — runs inside the browser.\n * Multi-stage pruning pipeline producing LLM-optimized output.\n *\n * Stages:\n * 1. Walk DOM, collect visibility + layout + interactivity signals\n * 2. Prune invisible, zero-area, non-content elements\n * 3. SVG & decoration collapse\n * 4. Shadow DOM traversal\n * 5. Same-origin iframe extraction\n * 6. Bounding-box parent-child dedup (link/button wrapping)\n * 7. Paint-order occlusion detection (overlay/modal coverage)\n * 8. Attribute whitelist filtering\n * 9. Ad/tracker filtering\n * 10. Scroll position info\n * 11. data-ref annotation for targeting\n * 12. Token-efficient serialization with interactive indices\n */\n/**\n * Build snapshot script with optional previous hashes for diff marking.\n * Elements new since last snapshot get a `*` prefix on their index.\n */\nexport function buildSnapshotScript(previousHashes?: string[]): string {\n return SNAPSHOT_SCRIPT_FN(previousHashes || []);\n}\n\nfunction SNAPSHOT_SCRIPT_FN(prevHashes: string[]): string {\n return `\n(() => {\n let idx = 0;\n const __prevHashes = new Set(${JSON.stringify(prevHashes)});\n const __currentHashes = [];\n`;\n}\n\nexport const SNAPSHOT_SCRIPT = `\n(() => {\n let idx = 0;\n const __prevHashes = (window.__lobster_prev_hashes) ? new Set(window.__lobster_prev_hashes) : null;\n const __currentHashes = [];\n\n const SKIP_TAGS = new Set([\n 'script','style','noscript','svg','path','meta','link','head',\n 'template','slot','colgroup','col',\n ]);\n\n const INTERACTIVE_TAGS = new Set([\n 'a','button','input','select','textarea','details','summary','label',\n ]);\n\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n\n const ATTR_WHITELIST = [\n 'type','role','aria-label','aria-expanded','aria-selected','aria-checked',\n 'aria-disabled','aria-haspopup','aria-pressed','placeholder','title',\n 'href','value','name','alt','src','action','method','for',\n 'data-testid','data-id','contenteditable','tabindex',\n ];\n\n const AD_PATTERNS = /ad[-_]?banner|ad[-_]?container|google[-_]?ad|doubleclick|adsbygoogle|sponsored|^ad$/i;\n\n // ── Stage 1: Visibility check ──\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0 && el.tagName !== 'INPUT') return false;\n const s = getComputedStyle(el);\n if (s.display === 'none') return false;\n if (s.visibility === 'hidden' || s.visibility === 'collapse') return false;\n if (s.opacity === '0') return false;\n if (s.clipPath === 'inset(100%)') return false;\n // Check for offscreen positioning\n const rect = el.getBoundingClientRect();\n if (rect.right < 0 || rect.bottom < 0) return false;\n return true;\n }\n\n // ── Stage 2: Interactive detection ──\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) {\n // Skip disabled elements\n if (el.disabled) return false;\n // Skip hidden inputs\n if (tag === 'input' && el.type === 'hidden') return false;\n return true;\n }\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.contentEditable === 'true') return true;\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) return true;\n if (el.onclick) return true;\n return false;\n }\n\n // ── Stage 8: Attribute filtering ──\n function getAttrs(el) {\n const parts = [];\n for (const name of ATTR_WHITELIST) {\n let v = el.getAttribute(name);\n if (v === null || v === '') continue;\n // Truncate long values\n if (v.length > 80) v = v.slice(0, 77) + '...';\n // Skip href=\"javascript:...\"\n if (name === 'href' && v.startsWith('javascript:')) continue;\n parts.push(name + '=' + v);\n }\n return parts.length ? ' ' + parts.join(' ') : '';\n }\n\n // ── Stage 9: Ad filtering ──\n function isAd(el) {\n const id = el.id || '';\n const cls = el.className || '';\n if (typeof cls === 'string' && AD_PATTERNS.test(cls)) return true;\n if (AD_PATTERNS.test(id)) return true;\n if (el.tagName === 'IFRAME' && AD_PATTERNS.test(el.src || '')) return true;\n return false;\n }\n\n // ── Stage 10: Scroll info ──\n function getScrollInfo(el) {\n const s = getComputedStyle(el);\n const overflowY = s.overflowY;\n const overflowX = s.overflowX;\n const scrollableY = (overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight;\n const scrollableX = (overflowX === 'auto' || overflowX === 'scroll') && el.scrollWidth > el.clientWidth;\n if (!scrollableY && !scrollableX) return '';\n\n const parts = [];\n if (scrollableY) {\n const up = Math.round(el.scrollTop);\n const down = Math.round(el.scrollHeight - el.clientHeight - el.scrollTop);\n if (up > 0) parts.push(up + 'px up');\n if (down > 0) parts.push(down + 'px down');\n }\n if (scrollableX) {\n const left = Math.round(el.scrollLeft);\n const right = Math.round(el.scrollWidth - el.clientWidth - el.scrollLeft);\n if (left > 0) parts.push(left + 'px left');\n if (right > 0) parts.push(right + 'px right');\n }\n return parts.length ? ' |scroll: ' + parts.join(', ') + '|' : '';\n }\n\n // ── Stage 6: Bounding-box dedup ──\n // If a parent and child are both interactive and have ~same bounding box,\n // skip the parent (e.g., <a><button>Click</button></a>)\n function isWrappingInteractive(el) {\n if (!isInteractive(el)) return false;\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return false;\n for (const child of el.children) {\n if (!isInteractive(child)) continue;\n const cr = child.getBoundingClientRect();\n const overlapX = Math.min(rect.right, cr.right) - Math.max(rect.left, cr.left);\n const overlapY = Math.min(rect.bottom, cr.bottom) - Math.max(rect.top, cr.top);\n const overlapArea = Math.max(0, overlapX) * Math.max(0, overlapY);\n const parentArea = rect.width * rect.height;\n if (parentArea > 0 && overlapArea / parentArea > 0.85) return true;\n }\n return false;\n }\n\n // ── Stage 7: Occlusion detection ──\n function isOccluded(el) {\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return false;\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n const topEl = document.elementFromPoint(cx, cy);\n if (!topEl) return false;\n if (topEl === el || el.contains(topEl) || topEl.contains(el)) return false;\n // Check z-index — if top element is a modal/overlay, mark as occluded\n const topZ = parseInt(getComputedStyle(topEl).zIndex) || 0;\n const elZ = parseInt(getComputedStyle(el).zIndex) || 0;\n return topZ > elZ + 10;\n }\n\n // ── Stage 5: Iframe content extraction ──\n function getIframeContent(iframe, depth, maxDepth) {\n try {\n const doc = iframe.contentDocument;\n if (!doc || !doc.body) return '';\n return '\\\\n' + walkNode(doc.body, depth, maxDepth);\n } catch { return ''; }\n }\n\n // ── Stage 4: Shadow DOM traversal ──\n function getShadowContent(el, depth, maxDepth) {\n if (!el.shadowRoot) return '';\n let out = '';\n for (const child of el.shadowRoot.childNodes) {\n out += walkNode(child, depth, maxDepth);\n }\n return out;\n }\n\n // ── Input value hint ──\n function getInputHint(el) {\n const tag = el.tagName.toLowerCase();\n if (tag === 'input') {\n const type = el.type || 'text';\n const val = el.value || '';\n const checked = el.checked;\n if (type === 'checkbox' || type === 'radio') {\n return checked ? ' [checked]' : ' [unchecked]';\n }\n if (val) return ' value=\"' + val.slice(0, 50) + '\"';\n }\n if (tag === 'textarea' && el.value) {\n return ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n if (tag === 'select' && el.selectedOptions?.length) {\n return ' selected=\"' + el.selectedOptions[0].text.slice(0, 40) + '\"';\n }\n return '';\n }\n\n const MAX_DEPTH = 25;\n const MAX_TEXT = 150;\n\n function walkNode(node, depth, maxDepth) {\n if (depth > maxDepth) return '';\n if (!node) return '';\n\n // Text node\n if (node.nodeType === 3) {\n const t = node.textContent.trim();\n if (!t) return '';\n const text = t.length > MAX_TEXT ? t.slice(0, MAX_TEXT) + '...' : t;\n return ' '.repeat(depth) + text + '\\\\n';\n }\n\n // Comment node — skip\n if (node.nodeType === 8) return '';\n\n // Only element nodes from here\n if (node.nodeType !== 1) return '';\n\n const el = node;\n const tag = el.tagName.toLowerCase();\n\n // ── Stage 3: Skip tags ──\n if (SKIP_TAGS.has(tag)) return '';\n\n // ── Stage 2: Visibility ──\n if (!isVisible(el)) return '';\n\n // ── Stage 9: Ad filtering ──\n if (isAd(el)) return '';\n\n // ── Stage 6: Bbox dedup — skip wrapping interactive parent ──\n const skipSelf = isWrappingInteractive(el);\n\n const indent = ' '.repeat(depth);\n const inter = !skipSelf && isInteractive(el);\n let prefix = '';\n if (inter) {\n const thisIdx = idx++;\n // Hash: tag + text + key attributes for diff tracking\n const hashText = tag + ':' + (el.textContent || '').trim().slice(0, 40) + ':' + (el.getAttribute('href') || '') + ':' + (el.getAttribute('aria-label') || '');\n __currentHashes.push(hashText);\n const isNew = __prevHashes && __prevHashes.size > 0 && !__prevHashes.has(hashText);\n prefix = isNew ? '*[' + thisIdx + ']' : '[' + thisIdx + ']';\n }\n\n // ── Stage 11: Annotate with data-ref ──\n if (inter) {\n try { el.dataset.ref = String(idx - 1); } catch {}\n }\n\n // ── Stage 7: Occlusion check for interactive elements ──\n if (inter && isOccluded(el)) {\n // Still include but mark as occluded\n // (agent needs to know element exists but may need to scroll/close modal)\n }\n\n const a = getAttrs(el);\n const scrollInfo = getScrollInfo(el);\n const inputHint = inter ? getInputHint(el) : '';\n\n // Leaf text extraction\n let leafText = '';\n if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) {\n const t = el.childNodes[0].textContent.trim();\n if (t) leafText = t.length > MAX_TEXT ? t.slice(0, MAX_TEXT) + '...' : t;\n }\n\n // ── Stage 5: Iframe ──\n if (tag === 'iframe') {\n const iframeContent = getIframeContent(el, depth + 1, maxDepth);\n if (iframeContent) {\n return indent + prefix + '<iframe' + a + '>\\\\n' + iframeContent;\n }\n return '';\n }\n\n // Build output\n let out = '';\n\n if (skipSelf) {\n // Skip self but render children\n for (const c of el.childNodes) out += walkNode(c, depth, maxDepth);\n out += getShadowContent(el, depth, maxDepth);\n return out;\n }\n\n if (inter || leafText || el.children.length === 0) {\n if (leafText) {\n out = indent + prefix + '<' + tag + a + scrollInfo + inputHint + '>' + leafText + '</' + tag + '>\\\\n';\n } else {\n out = indent + prefix + '<' + tag + a + scrollInfo + inputHint + '>\\\\n';\n for (const c of el.childNodes) out += walkNode(c, depth + 1, maxDepth);\n out += getShadowContent(el, depth + 1, maxDepth);\n }\n } else {\n // Non-interactive container — flatten depth if no useful info\n if (scrollInfo) {\n out = indent + '<' + tag + scrollInfo + '>\\\\n';\n for (const c of el.childNodes) out += walkNode(c, depth + 1, maxDepth);\n out += getShadowContent(el, depth + 1, maxDepth);\n } else {\n for (const c of el.childNodes) out += walkNode(c, depth, maxDepth);\n out += getShadowContent(el, depth, maxDepth);\n }\n }\n\n return out;\n }\n\n // ── Page-level scroll info header ──\n const scrollY = window.scrollY;\n const scrollMax = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPct = scrollMax > 0 ? Math.round((scrollY / scrollMax) * 100) : 0;\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const pageH = document.documentElement.scrollHeight;\n\n let header = '';\n header += 'viewport: ' + vpW + 'x' + vpH + ' | page_height: ' + pageH + 'px';\n header += ' | scroll: ' + scrollPct + '%';\n if (scrollY > 50) header += ' (' + Math.round(scrollY) + 'px from top)';\n if (scrollMax - scrollY > 50) header += ' (' + Math.round(scrollMax - scrollY) + 'px more below)';\n header += '\\\\n---\\\\n';\n\n // Store current hashes for next diff comparison\n window.__lobster_prev_hashes = __currentHashes;\n\n return header + walkNode(document.body, 0, MAX_DEPTH);\n})()\n`;\n","/**\n * Compact Snapshot — token-efficient DOM snapshot (~800 tokens).\n *\n * Only emits interactive elements + landmark section headers.\n * Format: [0] button \"Sign In\" (one line per element)\n *\n * Inspired by PinchTab's token-counting approach, built from scratch.\n */\n\nexport const COMPACT_SNAPSHOT_SCRIPT = `\n(() => {\n const TOKEN_BUDGET = 800;\n const CHARS_PER_TOKEN = 4;\n\n const INTERACTIVE_TAGS = new Set([\n 'a','button','input','select','textarea','details','summary','label',\n ]);\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n const LANDMARK_TAGS = new Map([\n ['nav', 'Navigation'],\n ['main', 'Main Content'],\n ['header', 'Header'],\n ['footer', 'Footer'],\n ['aside', 'Sidebar'],\n ['form', 'Form'],\n ]);\n const LANDMARK_ROLES = new Map([\n ['navigation', 'Navigation'],\n ['main', 'Main Content'],\n ['banner', 'Header'],\n ['contentinfo', 'Footer'],\n ['complementary', 'Sidebar'],\n ['search', 'Search'],\n ['dialog', 'Dialog'],\n ]);\n\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0 && el.tagName !== 'INPUT') return false;\n const s = getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n }\n\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) {\n if (el.disabled) return false;\n if (tag === 'input' && el.type === 'hidden') return false;\n return true;\n }\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.contentEditable === 'true') return true;\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) return true;\n return false;\n }\n\n function getRole(el) {\n const role = el.getAttribute('role');\n if (role) return role;\n const tag = el.tagName.toLowerCase();\n if (tag === 'a') return 'link';\n if (tag === 'button' || tag === 'summary') return 'button';\n if (tag === 'input') return el.type || 'text';\n if (tag === 'select') return 'select';\n if (tag === 'textarea') return 'textarea';\n if (tag === 'label') return 'label';\n return tag;\n }\n\n function getName(el) {\n return (\n el.getAttribute('aria-label') ||\n el.getAttribute('alt') ||\n el.getAttribute('title') ||\n el.getAttribute('placeholder') ||\n (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button') ? el.value : '') ||\n (el.id ? document.querySelector('label[for=\"' + el.id + '\"]')?.textContent?.trim() : '') ||\n (el.children.length <= 2 ? el.textContent?.trim() : '') ||\n ''\n ).slice(0, 60);\n }\n\n function getValue(el) {\n const tag = el.tagName.toLowerCase();\n if (tag === 'input') {\n const type = el.type || 'text';\n if (type === 'checkbox' || type === 'radio') return el.checked ? 'checked' : 'unchecked';\n if (type === 'password') return el.value ? '****' : '';\n return el.value ? el.value.slice(0, 30) : '';\n }\n if (tag === 'textarea') return el.value ? el.value.slice(0, 30) : '';\n if (tag === 'select' && el.selectedOptions?.length) return el.selectedOptions[0].text.slice(0, 30);\n return '';\n }\n\n // Collect elements\n let idx = 0;\n let charsUsed = 0;\n const lines = [];\n let lastLandmark = '';\n\n // Page header\n const scrollY = window.scrollY;\n const scrollMax = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPct = scrollMax > 0 ? Math.round((scrollY / scrollMax) * 100) : 0;\n const header = 'url: ' + location.href + ' | scroll: ' + scrollPct + '%';\n lines.push(header);\n charsUsed += header.length;\n\n // Walk DOM\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n if (!isVisible(node)) continue;\n\n const tag = node.tagName.toLowerCase();\n if (['script','style','noscript','svg','path','meta','link','head','template'].includes(tag)) continue;\n\n // Check for landmark\n const role = node.getAttribute('role');\n const landmark = LANDMARK_TAGS.get(tag) || (role ? LANDMARK_ROLES.get(role) : null);\n if (landmark && landmark !== lastLandmark) {\n const sectionLine = '--- ' + landmark + ' ---';\n if (charsUsed + sectionLine.length > TOKEN_BUDGET * CHARS_PER_TOKEN) break;\n lines.push(sectionLine);\n charsUsed += sectionLine.length;\n lastLandmark = landmark;\n }\n\n // Only emit interactive elements\n if (!isInteractive(node)) continue;\n\n const elRole = getRole(node);\n const name = getName(node);\n const value = getValue(node);\n\n // Build compact line\n let line = '[' + idx + '] ' + elRole;\n if (name) line += ' \"' + name.replace(/\"/g, \"'\") + '\"';\n if (value) line += ' val=\"' + value.replace(/\"/g, \"'\") + '\"';\n\n // Check token budget\n if (charsUsed + line.length > TOKEN_BUDGET * CHARS_PER_TOKEN) {\n lines.push('... (' + (document.querySelectorAll('a,button,input,select,textarea,[role]').length - idx) + ' more elements)');\n break;\n }\n\n // Annotate element with ref for clicking\n try { node.dataset.ref = String(idx); } catch {}\n\n lines.push(line);\n charsUsed += line.length;\n idx++;\n }\n\n return lines.join('\\\\n');\n})()\n`;\n\n/**\n * Build compact snapshot script with custom token budget.\n */\nexport function buildCompactSnapshotScript(tokenBudget: number = 800): string {\n return COMPACT_SNAPSHOT_SCRIPT.replace('const TOKEN_BUDGET = 800;', `const TOKEN_BUDGET = ${tokenBudget};`);\n}\n","/**\n * Semantic tree — W3C accessible name algorithm, XPath, listener detection.\n *\n * Based on Lightpanda's SemanticTree.zig approach:\n * - Accessible name: aria-labelledby → aria-label → alt → title → placeholder → text content\n * - XPath generation for element location\n * - Interactive classification: native, aria, contenteditable, listener, focusable\n * - Disabled state with fieldset inheritance\n * - Input value, option, checked state extraction\n */\nexport const SEMANTIC_TREE_SCRIPT = `\n(() => {\n const SKIP = new Set(['script','style','noscript','svg','head','meta','link','template']);\n\n const ROLE_MAP = {\n a: 'link', button: 'button', input: 'textbox', select: 'combobox',\n textarea: 'textbox', h1: 'heading', h2: 'heading', h3: 'heading',\n h4: 'heading', h5: 'heading', h6: 'heading', nav: 'navigation',\n main: 'main', header: 'banner', footer: 'contentinfo', aside: 'complementary',\n form: 'form', table: 'table', img: 'img', ul: 'list', ol: 'list', li: 'listitem',\n section: 'region', article: 'article', dialog: 'dialog', details: 'group',\n summary: 'button', progress: 'progressbar', meter: 'meter', output: 'status',\n label: 'label', legend: 'legend', fieldset: 'group', option: 'option',\n tr: 'row', td: 'cell', th: 'columnheader', caption: 'caption',\n };\n\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n\n // ── W3C Accessible Name Algorithm (simplified) ──\n function getAccessibleName(el) {\n // 1. aria-labelledby (highest priority)\n const labelledBy = el.getAttribute('aria-labelledby');\n if (labelledBy) {\n const ids = labelledBy.split(/\\\\s+/);\n const parts = ids.map(id => {\n const ref = document.getElementById(id);\n return ref ? ref.textContent.trim() : '';\n }).filter(Boolean);\n if (parts.length > 0) return parts.join(' ').slice(0, 120);\n }\n\n // 2. aria-label\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return ariaLabel.slice(0, 120);\n\n // 3. alt (for images)\n const alt = el.getAttribute('alt');\n if (alt) return alt.slice(0, 120);\n\n // 4. title\n const title = el.getAttribute('title');\n if (title) return title.slice(0, 120);\n\n // 5. placeholder (for inputs)\n const placeholder = el.getAttribute('placeholder');\n if (placeholder) return placeholder.slice(0, 120);\n\n // 6. value (for buttons)\n if (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button')) {\n const val = el.getAttribute('value');\n if (val) return val.slice(0, 120);\n }\n\n // 7. Associated label\n if (el.id) {\n const label = document.querySelector('label[for=\"' + el.id + '\"]');\n if (label) return label.textContent.trim().slice(0, 120);\n }\n\n // 8. Direct text content (only for leaf-ish elements)\n if (el.children.length <= 2) {\n const text = el.textContent.trim();\n if (text && text.length < 120) return text;\n }\n\n return '';\n }\n\n // ── XPath generation ──\n function getXPath(el) {\n const parts = [];\n let current = el;\n while (current && current.nodeType === 1) {\n let index = 1;\n let sibling = current.previousElementSibling;\n while (sibling) {\n if (sibling.tagName === current.tagName) index++;\n sibling = sibling.previousElementSibling;\n }\n const tag = current.tagName.toLowerCase();\n parts.unshift(tag + '[' + index + ']');\n current = current.parentElement;\n }\n return '/' + parts.join('/');\n }\n\n // ── Interactivity classification ──\n function classifyInteractivity(el) {\n const types = [];\n const tag = el.tagName.toLowerCase();\n\n // Native\n if (['a','button','input','select','textarea','details','summary'].includes(tag)) {\n if (tag === 'a' && !el.href) {} // anchor without href is not interactive\n else if (tag === 'input' && el.type === 'hidden') {} // hidden inputs\n else types.push('native');\n }\n\n // ARIA role\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) types.push('aria');\n\n // Contenteditable\n if (el.contentEditable === 'true') types.push('contenteditable');\n\n // Focusable\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) types.push('focusable');\n\n // Event listeners (check onclick and common inline handlers)\n if (el.onclick || el.onmousedown || el.onkeydown || el.onkeypress ||\n el.getAttribute('onclick') || el.getAttribute('onmousedown')) {\n types.push('listener');\n }\n\n return types;\n }\n\n // ── Disabled state with fieldset inheritance ──\n function isDisabled(el) {\n if (el.disabled) return true;\n // Check fieldset disabled inheritance\n let parent = el.parentElement;\n while (parent) {\n if (parent.tagName === 'FIELDSET' && parent.disabled) {\n // Exception: elements inside the first legend child are NOT disabled\n const firstLegend = parent.querySelector(':scope > legend');\n if (firstLegend && firstLegend.contains(el)) return false;\n return true;\n }\n parent = parent.parentElement;\n }\n return false;\n }\n\n // ── Walk the DOM ──\n function walk(el, depth, maxDepth) {\n if (!el || depth > maxDepth) return '';\n\n if (el.nodeType === 3) {\n const t = el.textContent.trim();\n return t ? ' '.repeat(depth) + 'text \"' + t.slice(0, 100) + '\"\\\\n' : '';\n }\n\n if (el.nodeType !== 1) return '';\n const tag = el.tagName.toLowerCase();\n if (SKIP.has(tag)) return '';\n\n const style = getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden') return '';\n\n const indent = ' '.repeat(depth);\n const role = el.getAttribute('role') || ROLE_MAP[tag] || '';\n const name = getAccessibleName(el);\n const interTypes = classifyInteractivity(el);\n const interactive = interTypes.length > 0;\n const disabled = interactive && isDisabled(el);\n\n let line = indent;\n line += role || tag;\n\n if (name) line += ' \"' + name.slice(0, 80) + '\"';\n\n if (interactive) {\n line += ' [' + interTypes.join(',') + ']';\n if (disabled) line += ' {disabled}';\n line += ' xpath=' + getXPath(el);\n }\n\n // Input state\n if (tag === 'input') {\n const type = el.type || 'text';\n line += ' type=' + type;\n if (type === 'checkbox' || type === 'radio') {\n line += el.checked ? ' [checked]' : ' [unchecked]';\n } else if (el.value) {\n line += ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n }\n if (tag === 'textarea' && el.value) {\n line += ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n if (tag === 'select') {\n const opts = Array.from(el.options || []).map(o => ({\n text: o.text.slice(0, 30),\n value: o.value,\n selected: o.selected,\n }));\n const selected = opts.find(o => o.selected);\n if (selected) line += ' selected=\"' + selected.text + '\"';\n if (opts.length <= 10) {\n line += ' options=[' + opts.map(o => o.text).join('|') + ']';\n }\n }\n\n line += '\\\\n';\n\n let out = line;\n for (const c of el.childNodes) {\n out += walk(c, depth + 1, maxDepth);\n }\n\n // Shadow DOM\n if (el.shadowRoot) {\n for (const c of el.shadowRoot.childNodes) {\n out += walk(c, depth + 1, maxDepth);\n }\n }\n\n return out;\n }\n\n return walk(document.body, 0, 20);\n})()\n`;\n","/**\n * DOM-to-Markdown converter — runs inside the browser.\n *\n * Full-featured conversion based on Lightpanda's markdown.zig:\n * - Table support with header separator rows\n * - URL resolution (relative → absolute)\n * - Nested ordered/unordered lists with proper indentation\n * - Character escaping for Markdown special chars\n * - Strikethrough, code blocks, blockquotes\n * - Smart anchor handling (inline vs block)\n * - Whitespace collapsing\n */\nexport const MARKDOWN_SCRIPT = `\n(() => {\n const SKIP = new Set(['script','style','noscript','svg','head','template']);\n const baseUrl = location.href;\n\n // Resolve relative URLs to absolute\n function resolveUrl(href) {\n if (!href || href.startsWith('javascript:') || href.startsWith('#')) return href;\n try { return new URL(href, baseUrl).href; } catch { return href; }\n }\n\n // Escape Markdown special chars in text\n function escapeText(text) {\n return text\n .replace(/\\\\\\\\/g, '\\\\\\\\\\\\\\\\')\n .replace(/([*_~\\`\\\\[\\\\]|])/g, '\\\\\\\\$1');\n }\n\n // State tracking\n let listDepth = 0;\n let orderedCounters = [];\n let inPre = false;\n let inTable = false;\n\n function listIndent() { return ' '.repeat(listDepth); }\n\n function walk(el) {\n if (!el) return '';\n\n // Text node\n if (el.nodeType === 3) {\n const text = el.textContent || '';\n if (inPre) return text;\n // Collapse whitespace\n const collapsed = text.replace(/\\\\s+/g, ' ');\n return collapsed === ' ' && !el.previousSibling && !el.nextSibling ? '' : collapsed;\n }\n\n if (el.nodeType !== 1) return '';\n const tag = el.tagName.toLowerCase();\n if (SKIP.has(tag)) return '';\n\n // Visibility check\n try {\n const s = getComputedStyle(el);\n if (s.display === 'none' || s.visibility === 'hidden') return '';\n } catch {}\n\n // Get children content\n function childContent() {\n let out = '';\n for (const c of el.childNodes) out += walk(c);\n return out;\n }\n\n switch (tag) {\n // ── Headings ──\n case 'h1': return '\\\\n\\\\n# ' + childContent().trim() + '\\\\n\\\\n';\n case 'h2': return '\\\\n\\\\n## ' + childContent().trim() + '\\\\n\\\\n';\n case 'h3': return '\\\\n\\\\n### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h4': return '\\\\n\\\\n#### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h5': return '\\\\n\\\\n##### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h6': return '\\\\n\\\\n###### ' + childContent().trim() + '\\\\n\\\\n';\n\n // ── Block elements ──\n case 'p': return '\\\\n\\\\n' + childContent().trim() + '\\\\n\\\\n';\n case 'br': return '\\\\n';\n case 'hr': return '\\\\n\\\\n---\\\\n\\\\n';\n\n // ── Inline formatting ──\n case 'strong': case 'b': {\n const inner = childContent().trim();\n return inner ? '**' + inner + '**' : '';\n }\n case 'em': case 'i': {\n const inner = childContent().trim();\n return inner ? '*' + inner + '*' : '';\n }\n case 's': case 'del': case 'strike': {\n const inner = childContent().trim();\n return inner ? '~~' + inner + '~~' : '';\n }\n case 'code': {\n if (inPre) return childContent();\n const inner = childContent();\n return inner ? '\\\\x60' + inner + '\\\\x60' : '';\n }\n\n // ── Code blocks ──\n case 'pre': {\n inPre = true;\n const inner = childContent();\n inPre = false;\n const lang = el.querySelector('code')?.className?.match(/language-(\\\\w+)/)?.[1] || '';\n return '\\\\n\\\\n\\\\x60\\\\x60\\\\x60' + lang + '\\\\n' + inner.trim() + '\\\\n\\\\x60\\\\x60\\\\x60\\\\n\\\\n';\n }\n\n // ── Links ──\n case 'a': {\n const href = resolveUrl(el.getAttribute('href') || '');\n const inner = childContent().trim();\n const name = inner || el.getAttribute('aria-label') || el.getAttribute('title') || '';\n if (!name) return '';\n if (!href || href === '#' || href.startsWith('javascript:')) return name;\n return '[' + name + '](' + href + ')';\n }\n\n // ── Images ──\n case 'img': {\n const alt = el.getAttribute('alt') || '';\n const src = resolveUrl(el.getAttribute('src') || '');\n return src ? '![' + alt + '](' + src + ')' : '';\n }\n\n // ── Lists ──\n case 'ul': {\n listDepth++;\n orderedCounters.push(0);\n const inner = childContent();\n listDepth--;\n orderedCounters.pop();\n return '\\\\n' + inner;\n }\n case 'ol': {\n listDepth++;\n orderedCounters.push(0);\n const inner = childContent();\n listDepth--;\n orderedCounters.pop();\n return '\\\\n' + inner;\n }\n case 'li': {\n const parent = el.parentElement?.tagName?.toLowerCase();\n const isOrdered = parent === 'ol';\n const inner = childContent().trim();\n if (!inner) return '';\n if (isOrdered) {\n const counter = orderedCounters.length > 0\n ? ++orderedCounters[orderedCounters.length - 1] : 1;\n return listIndent() + counter + '. ' + inner + '\\\\n';\n }\n return listIndent() + '- ' + inner + '\\\\n';\n }\n\n // ── Blockquote ──\n case 'blockquote': {\n const inner = childContent().trim();\n if (!inner) return '';\n return '\\\\n\\\\n' + inner.split('\\\\n').map(line => '> ' + line).join('\\\\n') + '\\\\n\\\\n';\n }\n\n // ── Tables ──\n case 'table': {\n inTable = true;\n let out = '\\\\n\\\\n';\n const rows = el.querySelectorAll('tr');\n let headerDone = false;\n\n for (let i = 0; i < rows.length; i++) {\n const cells = rows[i].querySelectorAll('th, td');\n const isHeader = rows[i].querySelector('th') !== null;\n const cellTexts = [];\n for (const cell of cells) {\n let cellText = '';\n for (const c of cell.childNodes) cellText += walk(c);\n cellTexts.push(cellText.trim().replace(/\\\\|/g, '\\\\\\\\|').replace(/\\\\n/g, ' '));\n }\n\n out += '| ' + cellTexts.join(' | ') + ' |\\\\n';\n\n if (isHeader && !headerDone) {\n out += '| ' + cellTexts.map(() => '---').join(' | ') + ' |\\\\n';\n headerDone = true;\n }\n\n // First data row without headers — synthesize separator\n if (i === 0 && !isHeader && !headerDone) {\n out += '| ' + cellTexts.map(() => '---').join(' | ') + ' |\\\\n';\n headerDone = true;\n }\n }\n\n inTable = false;\n return out + '\\\\n';\n }\n case 'thead': case 'tbody': case 'tfoot':\n return childContent();\n case 'tr': case 'td': case 'th':\n // Handled by table walker above; fallback for orphaned elements\n return childContent();\n\n // ── Definition lists ──\n case 'dl': return '\\\\n\\\\n' + childContent() + '\\\\n\\\\n';\n case 'dt': return '\\\\n**' + childContent().trim() + '**\\\\n';\n case 'dd': return ': ' + childContent().trim() + '\\\\n';\n\n // ── Figure ──\n case 'figure': return '\\\\n\\\\n' + childContent().trim() + '\\\\n\\\\n';\n case 'figcaption': return '\\\\n*' + childContent().trim() + '*\\\\n';\n\n // ── Details/Summary ──\n case 'details': return '\\\\n\\\\n' + childContent() + '\\\\n\\\\n';\n case 'summary': return '**' + childContent().trim() + '**\\\\n\\\\n';\n\n // ── Generic blocks ──\n case 'div': case 'section': case 'article': case 'main': case 'aside':\n case 'header': case 'footer': case 'nav':\n return '\\\\n' + childContent() + '\\\\n';\n\n case 'span': case 'small': case 'sub': case 'sup': case 'abbr':\n case 'time': case 'mark': case 'cite': case 'q':\n return childContent();\n\n default:\n return childContent();\n }\n }\n\n const raw = walk(document.body);\n // Clean up: collapse 3+ newlines to 2, trim\n return raw.replace(/\\\\n{3,}/g, '\\\\n\\\\n').replace(/^\\\\n+|\\\\n+$/g, '').trim();\n})()\n`;\n","/**\n * Form state extraction — runs inside the browser.\n *\n * Extracts all form fields (including orphan fields not in <form> tags),\n * their types, labels, values, required/disabled state.\n *\n * Based on OpenCLI's getFormStateJs() pattern.\n */\nexport const FORM_STATE_SCRIPT = `\n(() => {\n function extractField(el) {\n const tag = el.tagName.toLowerCase();\n const type = (el.getAttribute('type') || tag).toLowerCase();\n\n // Skip non-user-facing inputs\n if (['hidden', 'submit', 'button', 'reset', 'image'].includes(type)) return null;\n\n const name = el.name || el.id || '';\n\n // Find label via multiple strategies\n const label =\n el.getAttribute('aria-label') ||\n (el.id ? document.querySelector('label[for=\"' + el.id + '\"]')?.textContent?.trim() : null) ||\n el.closest('label')?.textContent?.trim() ||\n el.placeholder ||\n '';\n\n // Extract value based on type\n let value;\n if (tag === 'select') {\n const selected = el.options[el.selectedIndex];\n value = selected ? selected.textContent.trim() : '';\n } else if (type === 'checkbox' || type === 'radio') {\n value = el.checked;\n } else if (type === 'password') {\n value = el.value ? '••••' : '';\n } else if (el.isContentEditable) {\n value = el.textContent?.trim()?.slice(0, 200) || '';\n } else {\n value = el.value || '';\n }\n\n return {\n tag,\n type,\n name,\n label: label.slice(0, 80),\n value: typeof value === 'string' ? value.slice(0, 200) : value,\n required: !!el.required,\n disabled: !!el.disabled,\n ref: el.dataset?.ref || null,\n };\n }\n\n const result = { forms: [], orphanFields: [] };\n\n // Collect forms\n for (const form of document.forms) {\n const fields = [];\n for (const el of form.elements) {\n const field = extractField(el);\n if (field) fields.push(field);\n }\n result.forms.push({\n id: form.id || '',\n name: form.name || '',\n action: form.action || '',\n method: (form.method || 'get').toUpperCase(),\n fields,\n });\n }\n\n // Collect orphan fields (not in a <form>)\n const allInputs = document.querySelectorAll(\n 'input, textarea, select, [contenteditable=\"true\"]'\n );\n for (const el of allInputs) {\n if (!el.form) {\n const field = extractField(el);\n if (field) result.orphanFields.push(field);\n }\n }\n\n return result;\n})()\n`;\n","/**\n * Interactive element classification — identifies what's clickable/editable.\n * Based on Lightpanda's InteractivityType approach.\n */\nexport const INTERACTIVE_ELEMENTS_SCRIPT = `\n(() => {\n const results = [];\n\n function classify(el) {\n const tag = el.tagName.toLowerCase();\n const role = el.getAttribute('role');\n const types = [];\n\n // Native interactive\n if (['a', 'button', 'input', 'select', 'textarea', 'details', 'summary'].includes(tag)) {\n types.push('native');\n }\n\n // ARIA role interactive\n if (role && ['button', 'link', 'textbox', 'checkbox', 'radio', 'combobox', 'tab', 'switch', 'menuitem', 'slider'].includes(role)) {\n types.push('aria');\n }\n\n // Contenteditable\n if (el.contentEditable === 'true') types.push('contenteditable');\n\n // Focusable\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) types.push('focusable');\n\n // Has click listener (approximate)\n if (el.onclick) types.push('listener');\n\n return types;\n }\n\n let idx = 0;\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while (node = walker.nextNode()) {\n const types = classify(node);\n if (types.length === 0) continue;\n\n const style = getComputedStyle(node);\n if (style.display === 'none' || style.visibility === 'hidden') continue;\n\n const rect = node.getBoundingClientRect();\n results.push({\n index: idx++,\n tag: node.tagName.toLowerCase(),\n role: node.getAttribute('role') || '',\n text: (node.textContent || '').trim().slice(0, 100),\n types,\n ariaLabel: node.getAttribute('aria-label') || '',\n rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n });\n }\n\n return results;\n})()\n`;\n","/**\n * Network interceptor script — patches fetch and XHR to capture responses.\n * Based on OpenCLI's interception approach.\n */\nexport function buildInterceptorScript(pattern: string): string {\n return `\n(() => {\n if (window.__lobster_interceptor__) return;\n window.__lobster_interceptor__ = { requests: [] };\n const store = window.__lobster_interceptor__;\n const pattern = ${JSON.stringify(pattern)};\n\n // Patch fetch\n const origFetch = window.fetch;\n window.fetch = async function(...args) {\n const url = typeof args[0] === 'string' ? args[0] : args[0]?.url || '';\n const resp = await origFetch.apply(this, args);\n if (url.includes(pattern)) {\n const clone = resp.clone();\n try {\n const body = await clone.json();\n store.requests.push({ url, method: 'GET', status: resp.status, body, timestamp: Date.now() });\n } catch {}\n }\n return resp;\n };\n\n // Patch XHR\n const origOpen = XMLHttpRequest.prototype.open;\n const origSend = XMLHttpRequest.prototype.send;\n XMLHttpRequest.prototype.open = function(method, url, ...rest) {\n this.__url = url;\n this.__method = method;\n return origOpen.call(this, method, url, ...rest);\n };\n XMLHttpRequest.prototype.send = function(...args) {\n this.addEventListener('load', function() {\n if (this.__url && this.__url.includes(pattern)) {\n try {\n const body = JSON.parse(this.responseText);\n store.requests.push({ url: this.__url, method: this.__method, status: this.status, body, timestamp: Date.now() });\n } catch {}\n }\n });\n return origSend.apply(this, args);\n };\n})()\n`;\n}\n\nexport const GET_INTERCEPTED_SCRIPT = `\n(() => {\n const store = window.__lobster_interceptor__;\n if (!store) return [];\n const reqs = [...store.requests];\n store.requests = [];\n return reqs;\n})()\n`;\n","/**\n * Semantic Element Finding — match elements by natural language.\n *\n * Uses Jaccard similarity with synonym expansion, role boost,\n * and prefix matching. Zero external dependencies — runs in Node.\n *\n * Inspired by PinchTab's hybrid lexical+embedding matcher, built from scratch.\n */\n\nexport interface FindMatch {\n ref: number;\n score: number;\n text: string;\n role: string;\n tag: string;\n}\n\nexport interface FindOptions {\n maxResults?: number; // default 5\n minScore?: number; // default 0.3\n}\n\ninterface InteractiveElement {\n index: number;\n tag: string;\n role: string;\n text: string;\n types: string[];\n ariaLabel: string;\n}\n\n// ── Synonym table ──\nconst SYNONYMS: Record<string, string[]> = {\n btn: ['button'],\n button: ['btn', 'submit', 'click'],\n submit: ['go', 'send', 'ok', 'confirm', 'done', 'button'],\n search: ['find', 'lookup', 'query', 'filter'],\n login: ['signin', 'sign-in', 'log-in', 'authenticate'],\n signup: ['register', 'create-account', 'sign-up', 'join'],\n logout: ['signout', 'sign-out', 'log-out'],\n close: ['dismiss', 'x', 'cancel', 'exit'],\n menu: ['nav', 'navigation', 'hamburger', 'sidebar'],\n nav: ['navigation', 'menu', 'navbar'],\n input: ['field', 'textbox', 'text', 'entry'],\n email: ['mail', 'e-mail'],\n password: ['pass', 'pwd', 'secret'],\n next: ['continue', 'forward', 'proceed'],\n back: ['previous', 'return', 'go-back'],\n save: ['store', 'keep', 'persist'],\n delete: ['remove', 'trash', 'discard', 'destroy'],\n edit: ['modify', 'change', 'update'],\n add: ['create', 'new', 'plus', 'insert'],\n settings: ['preferences', 'config', 'options', 'gear'],\n profile: ['account', 'user', 'avatar'],\n home: ['main', 'dashboard', 'start'],\n link: ['anchor', 'href', 'url'],\n select: ['dropdown', 'combo', 'picker', 'choose'],\n checkbox: ['check', 'toggle', 'tick'],\n upload: ['attach', 'file', 'browse'],\n download: ['save', 'export'],\n};\n\n// ── Role keywords that boost score ──\nconst ROLE_KEYWORDS = new Set([\n 'button', 'link', 'input', 'textbox', 'checkbox', 'radio',\n 'select', 'dropdown', 'tab', 'menu', 'menuitem', 'switch',\n 'slider', 'combobox', 'searchbox', 'option',\n]);\n\n/**\n * Tokenize a string into lowercase words.\n */\nfunction tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, ' ')\n .split(/[\\s-]+/)\n .filter((t) => t.length > 0);\n}\n\n/**\n * Expand tokens with synonyms.\n */\nfunction expandSynonyms(tokens: string[]): Set<string> {\n const expanded = new Set(tokens);\n for (const token of tokens) {\n const syns = SYNONYMS[token];\n if (syns) {\n for (const syn of syns) expanded.add(syn);\n }\n }\n return expanded;\n}\n\n/**\n * Build frequency map.\n */\nfunction freqMap(tokens: string[]): Map<string, number> {\n const map = new Map<string, number>();\n for (const t of tokens) {\n map.set(t, (map.get(t) || 0) + 1);\n }\n return map;\n}\n\n/**\n * Jaccard similarity with frequency weighting.\n */\nfunction jaccardScore(queryTokens: string[], descTokens: string[]): number {\n const qFreq = freqMap(queryTokens);\n const dFreq = freqMap(descTokens);\n\n let intersection = 0;\n let union = 0;\n\n const allTokens = new Set([...qFreq.keys(), ...dFreq.keys()]);\n for (const token of allTokens) {\n const qCount = qFreq.get(token) || 0;\n const dCount = dFreq.get(token) || 0;\n intersection += Math.min(qCount, dCount);\n union += Math.max(qCount, dCount);\n }\n\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Prefix matching score — handles abbreviations.\n * \"btn\" matches \"button\" partially.\n */\nfunction prefixScore(queryTokens: string[], descTokens: string[]): number {\n if (queryTokens.length === 0 || descTokens.length === 0) return 0;\n\n let matches = 0;\n for (const qt of queryTokens) {\n if (qt.length < 3) continue;\n for (const dt of descTokens) {\n if (dt.startsWith(qt) || qt.startsWith(dt)) {\n matches += 0.5;\n break;\n }\n }\n }\n\n return Math.min(matches / queryTokens.length, 0.3);\n}\n\n/**\n * Role keyword boost — if query mentions a role and element matches.\n */\nfunction roleBoost(queryTokens: string[], elementRole: string): number {\n const roleLower = elementRole.toLowerCase();\n for (const qt of queryTokens) {\n if (ROLE_KEYWORDS.has(qt) && roleLower.includes(qt)) {\n return 0.2;\n }\n }\n return 0;\n}\n\n/**\n * Score a single element against the query.\n */\nfunction scoreElement(\n queryTokens: string[],\n queryExpanded: Set<string>,\n element: InteractiveElement,\n): number {\n // Build description from all element text sources\n const descParts = [\n element.text,\n element.role,\n element.tag,\n element.ariaLabel,\n ].filter(Boolean);\n const descText = descParts.join(' ');\n const descTokens = tokenize(descText);\n\n if (descTokens.length === 0) return 0;\n\n // Expand description tokens too\n const descExpanded = expandSynonyms(descTokens);\n\n // 1. Jaccard similarity on expanded token sets\n const expandedQueryTokens = [...queryExpanded];\n const expandedDescTokens = [...descExpanded];\n const jaccard = jaccardScore(expandedQueryTokens, expandedDescTokens);\n\n // 2. Prefix matching\n const prefix = prefixScore(queryTokens, descTokens);\n\n // 3. Role keyword boost\n const role = roleBoost(queryTokens, element.role || element.tag);\n\n // 4. Exact substring match bonus\n const queryStr = queryTokens.join(' ');\n const descStr = descTokens.join(' ');\n const exactBonus = descStr.includes(queryStr) ? 0.3 : 0;\n\n return Math.min(jaccard + prefix + role + exactBonus, 1.0);\n}\n\n/**\n * Find elements matching a natural language query.\n *\n * @param elements - Interactive elements from INTERACTIVE_ELEMENTS_SCRIPT\n * @param query - Natural language description (e.g., \"login button\")\n * @param options - maxResults (default 5), minScore (default 0.3)\n */\nexport function semanticFind(\n elements: InteractiveElement[],\n query: string,\n options?: FindOptions,\n): FindMatch[] {\n const maxResults = options?.maxResults ?? 5;\n const minScore = options?.minScore ?? 0.3;\n\n const queryTokens = tokenize(query);\n if (queryTokens.length === 0) return [];\n\n const queryExpanded = expandSynonyms(queryTokens);\n\n const scored: FindMatch[] = [];\n\n for (const el of elements) {\n const score = scoreElement(queryTokens, queryExpanded, el);\n if (score >= minScore) {\n scored.push({\n ref: el.index,\n score: Math.round(score * 100) / 100,\n text: (el.text || el.ariaLabel || '').slice(0, 60),\n role: el.role || el.tag,\n tag: el.tag,\n });\n }\n }\n\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, maxResults);\n}\n","import type { Page } from 'puppeteer-core';\nimport type {\n IPage, WaitCondition, Cookie, NetworkEntry, TabInfo,\n SnapshotOptions, SemanticTreeOptions, FlatDomTree, BrowserState, FormState,\n FindMatch, FindOptions,\n} from '../types/page.js';\nimport { FLAT_TREE_SCRIPT, flatTreeToString } from './dom/flat-tree.js';\nimport { SNAPSHOT_SCRIPT } from './dom/snapshot.js';\nimport { COMPACT_SNAPSHOT_SCRIPT } from './dom/compact-snapshot.js';\nimport { SEMANTIC_TREE_SCRIPT } from './dom/semantic-tree.js';\nimport { MARKDOWN_SCRIPT } from './dom/markdown.js';\nimport { FORM_STATE_SCRIPT } from './dom/form-state.js';\nimport { INTERACTIVE_ELEMENTS_SCRIPT } from './dom/interactive.js';\nimport { buildInterceptorScript, GET_INTERCEPTED_SCRIPT } from './interceptor.js';\nimport { semanticFind } from './semantic-find.js';\n\nexport class PuppeteerPage implements IPage {\n private page: Page;\n\n constructor(page: Page) {\n this.page = page;\n }\n\n get raw(): Page { return this.page; }\n\n async goto(url: string, options?: { waitUntil?: WaitCondition; timeout?: number }): Promise<void> {\n await this.page.goto(url, {\n waitUntil: (options?.waitUntil as any) || 'networkidle2',\n timeout: options?.timeout || 30000,\n });\n }\n\n async goBack(): Promise<void> {\n await this.page.goBack({ waitUntil: 'networkidle2' });\n }\n\n async url(): Promise<string> {\n return this.page.url();\n }\n\n async title(): Promise<string> {\n return this.page.title();\n }\n\n async evaluate<T = unknown>(js: string): Promise<T> {\n return this.page.evaluate(js) as Promise<T>;\n }\n\n async snapshot(opts?: SnapshotOptions): Promise<string> {\n if (opts?.compact) {\n return this.page.evaluate(COMPACT_SNAPSHOT_SCRIPT) as Promise<string>;\n }\n return this.page.evaluate(SNAPSHOT_SCRIPT) as Promise<string>;\n }\n\n async semanticTree(_opts?: SemanticTreeOptions): Promise<string> {\n return this.page.evaluate(SEMANTIC_TREE_SCRIPT) as Promise<string>;\n }\n\n async flatTree(): Promise<FlatDomTree> {\n const raw = await this.page.evaluate(FLAT_TREE_SCRIPT);\n return raw as FlatDomTree;\n }\n\n async markdown(): Promise<string> {\n return this.page.evaluate(MARKDOWN_SCRIPT) as Promise<string>;\n }\n\n async browserState(): Promise<BrowserState> {\n const state = await this.page.evaluate(`\n (() => {\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const pageW = document.documentElement.scrollWidth;\n const pageH = document.documentElement.scrollHeight;\n const maxScrollY = pageH - vpH;\n return {\n url: location.href,\n title: document.title,\n viewportWidth: vpW,\n viewportHeight: vpH,\n pageWidth: pageW,\n pageHeight: pageH,\n scrollX: scrollX,\n scrollY: scrollY,\n scrollPercent: maxScrollY > 0 ? Math.round((scrollY / maxScrollY) * 100) : 0,\n pixelsAbove: Math.round(scrollY),\n pixelsBelow: Math.round(Math.max(0, maxScrollY - scrollY)),\n };\n })()\n `) as BrowserState;\n return state;\n }\n\n async formState(): Promise<FormState> {\n return this.page.evaluate(FORM_STATE_SCRIPT) as Promise<FormState>;\n }\n\n async click(ref: string | number): Promise<void> {\n if (typeof ref === 'number') {\n await this.page.evaluate((idx) => {\n const el = document.querySelector('[data-ref=\"' + idx + '\"]') as HTMLElement;\n if (!el) throw new Error('Element with index ' + idx + ' not found');\n\n // Blur previously focused element\n const prev = document.activeElement as HTMLElement | null;\n if (prev && prev !== el && prev !== document.body) {\n prev.blur();\n prev.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, cancelable: true }));\n prev.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false, cancelable: true }));\n }\n\n // Scroll into view\n if (typeof (el as any).scrollIntoViewIfNeeded === 'function') {\n (el as any).scrollIntoViewIfNeeded();\n } else {\n el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' });\n }\n\n // Full mouse event sequence — required for React, analytics, custom handlers\n el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));\n el.focus();\n el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));\n }, ref);\n // Wait for click processing (animations, state updates)\n await new Promise((r) => setTimeout(r, 200));\n } else {\n await this.page.click(ref);\n }\n }\n\n async typeText(ref: string | number, text: string): Promise<void> {\n if (typeof ref === 'number') {\n // First click the element (triggers full event sequence + focus)\n await this.click(ref);\n\n await this.page.evaluate((idx, txt) => {\n const el = document.querySelector('[data-ref=\"' + idx + '\"]') as HTMLElement;\n if (!el) throw new Error('Element with index ' + idx + ' not found');\n\n const isInput = el.tagName === 'INPUT' || el.tagName === 'TEXTAREA';\n const isContentEditable = el.isContentEditable;\n\n if (isContentEditable) {\n // ── Contenteditable: Plan A — synthetic InputEvents ──\n // Works for: React contenteditable, Quill\n // Clear existing content\n if (el.dispatchEvent(new InputEvent('beforeinput', {\n bubbles: true, cancelable: true, inputType: 'deleteContent',\n }))) {\n el.innerText = '';\n el.dispatchEvent(new InputEvent('input', {\n bubbles: true, inputType: 'deleteContent',\n }));\n }\n\n // Insert new text\n if (el.dispatchEvent(new InputEvent('beforeinput', {\n bubbles: true, cancelable: true, inputType: 'insertText', data: txt,\n }))) {\n el.innerText = txt;\n el.dispatchEvent(new InputEvent('input', {\n bubbles: true, inputType: 'insertText', data: txt,\n }));\n }\n\n // Verify Plan A worked\n const planAOk = el.innerText.trim() === txt.trim();\n\n if (!planAOk) {\n // ── Plan B — execCommand fallback ──\n // Works for: Slate.js, some rich-text editors\n el.focus();\n const doc = el.ownerDocument;\n const sel = (doc.defaultView || window).getSelection();\n const range = doc.createRange();\n range.selectNodeContents(el);\n sel?.removeAllRanges();\n sel?.addRange(range);\n doc.execCommand('delete', false);\n doc.execCommand('insertText', false, txt);\n }\n\n el.dispatchEvent(new Event('change', { bubbles: true }));\n el.blur();\n\n } else if (isInput) {\n // ── Input/Textarea: use native value setter to bypass React/Vue ──\n const inputEl = el as HTMLInputElement | HTMLTextAreaElement;\n const proto = Object.getPrototypeOf(inputEl);\n const descriptor =\n Object.getOwnPropertyDescriptor(proto, 'value') ||\n Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value') ||\n Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n\n if (descriptor?.set) {\n descriptor.set.call(inputEl, txt);\n } else {\n inputEl.value = txt;\n }\n\n inputEl.dispatchEvent(new Event('input', { bubbles: true }));\n inputEl.dispatchEvent(new Event('change', { bubbles: true }));\n } else {\n // Fallback: try setting value anyway\n (el as any).value = txt;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }, ref, text);\n } else {\n // CSS selector path — click to focus, then use keyboard\n await this.page.click(ref, { count: 3 });\n await this.page.keyboard.type(text);\n }\n }\n\n async pressKey(key: string): Promise<void> {\n await this.page.keyboard.press(key as any);\n }\n\n async selectOption(ref: string | number, value: string): Promise<void> {\n const selector = typeof ref === 'number' ? '[data-ref=\"' + ref + '\"]' : ref;\n await this.page.select(selector, value);\n }\n\n async scroll(direction: 'up' | 'down' | 'left' | 'right', amount?: number): Promise<void> {\n const distance = amount || 500;\n const isVertical = direction === 'up' || direction === 'down';\n const positive = direction === 'down' || direction === 'right';\n const delta = positive ? distance : -distance;\n\n await this.page.evaluate((dy, dx, isVert) => {\n // Helper: check if element is a valid scroll container\n const canScroll = (el) => {\n if (!el) return false;\n const s = getComputedStyle(el);\n if (isVert) {\n return /(auto|scroll|overlay)/.test(s.overflowY) &&\n el.scrollHeight > el.clientHeight &&\n el.clientHeight >= window.innerHeight * 0.3;\n } else {\n return /(auto|scroll|overlay)/.test(s.overflowX) &&\n el.scrollWidth > el.clientWidth &&\n el.clientWidth >= window.innerWidth * 0.3;\n }\n };\n\n // Walk from active element up to find a scrollable container\n let el = document.activeElement;\n while (el && !canScroll(el) && el !== document.body) {\n el = el.parentElement;\n }\n\n // If no scrollable ancestor, search the DOM\n if (!canScroll(el)) {\n el = Array.from(document.querySelectorAll('*')).find(canScroll) || null;\n }\n\n const isPageLevel = !el || el === document.body ||\n el === document.documentElement || el === document.scrollingElement;\n\n if (isPageLevel) {\n // Page-level scroll\n if (isVert) {\n window.scrollBy(0, dy);\n } else {\n window.scrollBy(dx, 0);\n }\n } else {\n // Container scroll\n if (isVert) {\n el.scrollBy({ top: dy, behavior: 'smooth' });\n } else {\n el.scrollBy({ left: dx, behavior: 'smooth' });\n }\n }\n }, isVertical ? delta : 0, isVertical ? 0 : delta, isVertical);\n\n // Wait for smooth scroll to settle\n await new Promise((r) => setTimeout(r, 150));\n }\n\n async scrollToElement(ref: string | number): Promise<void> {\n const selector = typeof ref === 'number' ? '[data-ref=\"' + ref + '\"]' : ref;\n await this.page.evaluate((sel) => {\n const el = document.querySelector(sel);\n if (!el) return;\n if (typeof (el as any).scrollIntoViewIfNeeded === 'function') {\n (el as any).scrollIntoViewIfNeeded();\n } else {\n el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' });\n }\n }, selector);\n }\n\n async getCookies(opts?: { domain?: string }): Promise<Cookie[]> {\n const cookies = await this.page.cookies();\n const filtered = opts?.domain\n ? cookies.filter((c) => c.domain.includes(opts.domain!))\n : cookies;\n return filtered.map((c) => ({\n name: c.name,\n value: c.value,\n domain: c.domain,\n path: c.path,\n expires: c.expires,\n httpOnly: c.httpOnly,\n secure: c.secure,\n sameSite: c.sameSite as Cookie['sameSite'],\n }));\n }\n\n async wait(options: number | { text?: string; time?: number; timeout?: number }): Promise<void> {\n if (typeof options === 'number') {\n await new Promise((r) => setTimeout(r, options * 1000));\n return;\n }\n if (options.time) {\n await new Promise((r) => setTimeout(r, options.time! * 1000));\n }\n if (options.text) {\n await this.page.waitForFunction(\n (t) => document.body.innerText.includes(t),\n { timeout: options.timeout || 30000 },\n options.text\n );\n }\n }\n\n async networkRequests(includeStatic?: boolean): Promise<NetworkEntry[]> {\n // Use Performance API to extract network requests from the browser\n const entries = await this.page.evaluate(`\n (() => {\n const entries = performance.getEntriesByType('resource');\n const staticTypes = new Set(['img', 'font', 'css', 'script', 'link']);\n const includeStatic = ${!!includeStatic};\n\n return entries\n .filter(e => includeStatic || !staticTypes.has(e.initiatorType))\n .map(e => ({\n url: e.name,\n method: 'GET',\n status: 200,\n type: e.initiatorType || 'other',\n size: e.transferSize || e.encodedBodySize || 0,\n duration: Math.round(e.duration),\n }));\n })()\n `) as NetworkEntry[];\n return entries || [];\n }\n\n async installInterceptor(pattern: string): Promise<void> {\n await this.page.evaluate(buildInterceptorScript(pattern));\n }\n\n async getInterceptedRequests(): Promise<unknown[]> {\n return this.page.evaluate(GET_INTERCEPTED_SCRIPT) as Promise<unknown[]>;\n }\n\n async screenshot(opts?: { format?: 'png' | 'jpeg'; fullPage?: boolean }): Promise<Buffer> {\n const result = await this.page.screenshot({\n type: opts?.format || 'png',\n fullPage: opts?.fullPage ?? false,\n });\n return Buffer.from(result);\n }\n\n async tabs(): Promise<TabInfo[]> {\n const browser = this.page.browser();\n const pages = await browser.pages();\n return pages.map((p, i) => ({\n id: i,\n url: p.url(),\n title: '',\n active: p === this.page,\n }));\n }\n\n async find(query: string, options?: FindOptions): Promise<FindMatch[]> {\n const elements = await this.page.evaluate(INTERACTIVE_ELEMENTS_SCRIPT) as any[];\n return semanticFind(elements, query, options);\n }\n\n async close(): Promise<void> {\n await this.page.close();\n }\n}\n","/**\n * LobsterEngine — In-house lightweight HTML parser + content extractor.\n *\n * No Chrome, no external binary. Pure Node.js.\n * Fetches HTML via HTTP, parses into a DOM tree, extracts content\n * as markdown, text, links, or structured snapshot.\n *\n * Inspired by Lightpanda's approach but 100% our code.\n * Works for server-rendered pages. For JS-heavy SPAs, use Chrome engine.\n */\n\n// ── HTML Node types ──\n\nexport interface HtmlNode {\n type: 'element' | 'text' | 'comment';\n tag?: string;\n attributes?: Record<string, string>;\n children?: HtmlNode[];\n text?: string;\n selfClosing?: boolean;\n}\n\n// ── HTML Parser ──\n\nconst SELF_CLOSING = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr',\n]);\n\nconst RAWTEXT_TAGS = new Set(['script', 'style', 'textarea', 'title']);\n\n/**\n * Parse HTML string into a tree of HtmlNodes.\n * Handles: tags, attributes, self-closing, rawtext, comments, entities.\n */\nexport function parseHtml(html: string): HtmlNode[] {\n const root: HtmlNode[] = [];\n const stack: { node: HtmlNode; children: HtmlNode[] }[] = [{ node: { type: 'element', tag: 'root', children: root }, children: root }];\n let pos = 0;\n\n function current() { return stack[stack.length - 1]; }\n\n function addText(text: string) {\n if (!text) return;\n const decoded = decodeEntities(text);\n if (decoded.trim() || decoded.includes('\\n')) {\n current().children.push({ type: 'text', text: decoded });\n }\n }\n\n while (pos < html.length) {\n const nextTag = html.indexOf('<', pos);\n\n if (nextTag === -1) {\n addText(html.slice(pos));\n break;\n }\n\n if (nextTag > pos) {\n addText(html.slice(pos, nextTag));\n }\n\n // Comment\n if (html.startsWith('<!--', nextTag)) {\n const endComment = html.indexOf('-->', nextTag + 4);\n pos = endComment === -1 ? html.length : endComment + 3;\n continue;\n }\n\n // Doctype\n if (html.startsWith('<!', nextTag) || html.startsWith('<?', nextTag)) {\n const endDoctype = html.indexOf('>', nextTag);\n pos = endDoctype === -1 ? html.length : endDoctype + 1;\n continue;\n }\n\n // Closing tag\n if (html[nextTag + 1] === '/') {\n const endClose = html.indexOf('>', nextTag);\n if (endClose === -1) { pos = html.length; break; }\n const closeTag = html.slice(nextTag + 2, endClose).trim().toLowerCase();\n pos = endClose + 1;\n\n // Pop stack until we find matching tag\n for (let i = stack.length - 1; i > 0; i--) {\n if (stack[i].node.tag === closeTag) {\n stack.length = i;\n break;\n }\n }\n continue;\n }\n\n // Opening tag\n const tagEnd = html.indexOf('>', nextTag);\n if (tagEnd === -1) { pos = html.length; break; }\n\n const tagContent = html.slice(nextTag + 1, tagEnd);\n const selfClose = tagContent.endsWith('/');\n const cleanContent = selfClose ? tagContent.slice(0, -1).trim() : tagContent.trim();\n\n // Parse tag name and attributes\n const spaceIdx = cleanContent.search(/[\\s/]/);\n const tagName = (spaceIdx === -1 ? cleanContent : cleanContent.slice(0, spaceIdx)).toLowerCase();\n const attrStr = spaceIdx === -1 ? '' : cleanContent.slice(spaceIdx);\n\n if (!tagName || tagName.startsWith('!')) {\n pos = tagEnd + 1;\n continue;\n }\n\n const attributes = parseAttributes(attrStr);\n const isSelfClosing = selfClose || SELF_CLOSING.has(tagName);\n\n const node: HtmlNode = {\n type: 'element',\n tag: tagName,\n attributes,\n children: isSelfClosing ? undefined : [],\n selfClosing: isSelfClosing,\n };\n\n current().children.push(node);\n pos = tagEnd + 1;\n\n if (isSelfClosing) continue;\n\n // Raw text tags (script, style) — consume until closing tag\n if (RAWTEXT_TAGS.has(tagName)) {\n const endRaw = html.toLowerCase().indexOf(`</${tagName}`, pos);\n if (endRaw !== -1) {\n const rawText = html.slice(pos, endRaw);\n if (rawText.trim()) {\n node.children!.push({ type: 'text', text: rawText });\n }\n pos = html.indexOf('>', endRaw) + 1;\n }\n continue;\n }\n\n // Push onto stack for children\n stack.push({ node, children: node.children! });\n\n // Auto-close certain tags\n if (tagName === 'p' || tagName === 'li' || tagName === 'td' || tagName === 'th' || tagName === 'dt' || tagName === 'dd') {\n // Check if parent is same tag — auto-close\n if (stack.length >= 3 && stack[stack.length - 2].node.tag === tagName) {\n stack.splice(stack.length - 2, 1);\n }\n }\n }\n\n return root;\n}\n\nfunction parseAttributes(str: string): Record<string, string> {\n const attrs: Record<string, string> = {};\n const re = /(\\w[\\w-]*)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|(\\S+)))?/g;\n let m;\n while ((m = re.exec(str)) !== null) {\n attrs[m[1].toLowerCase()] = decodeEntities(m[2] ?? m[3] ?? m[4] ?? '');\n }\n return attrs;\n}\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&apos;/g, \"'\")\n .replace(/&nbsp;/g, ' ')\n .replace(/&#(\\d+);/g, (_, n) => String.fromCharCode(parseInt(n)))\n .replace(/&#x([0-9a-fA-F]+);/g, (_, n) => String.fromCharCode(parseInt(n, 16)));\n}\n\n// ── Content Extractors ──\n\nconst SKIP_TAGS = new Set(['script', 'style', 'noscript', 'svg', 'head', 'template', 'iframe']);\nconst BLOCK_TAGS = new Set(['div', 'p', 'section', 'article', 'main', 'aside', 'blockquote', 'pre', 'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'br', 'hr', 'figure', 'figcaption', 'details', 'summary', 'dl', 'dt', 'dd', 'header', 'footer', 'nav', 'form']);\nconst HEADING_LEVELS: Record<string, string> = { h1: '#', h2: '##', h3: '###', h4: '####', h5: '#####', h6: '######' };\n\nconst INTERACTIVE_TAGS = new Set(['a', 'button', 'input', 'select', 'textarea', 'details', 'summary']);\nconst INTERACTIVE_ROLES = new Set(['button', 'link', 'textbox', 'checkbox', 'radio', 'combobox', 'tab', 'switch', 'menuitem']);\n\n/**\n * Extract plain text from parsed HTML.\n */\nexport function extractText(nodes: HtmlNode[]): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n out += node.text;\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const inner = node.children ? extractText(node.children) : '';\n if (BLOCK_TAGS.has(node.tag)) {\n out += '\\n' + inner.trim() + '\\n';\n } else {\n out += inner;\n }\n }\n return out.replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Extract Markdown from parsed HTML.\n */\nexport function extractMarkdown(nodes: HtmlNode[], baseUrl?: string): string {\n let listDepth = 0;\n let olCounter: number[] = [];\n\n function resolveUrl(href: string): string {\n if (!href || href.startsWith('javascript:') || href.startsWith('#')) return href;\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) return href;\n if (baseUrl) {\n try { return new URL(href, baseUrl).href; } catch {}\n }\n return href;\n }\n\n function walk(nodes: HtmlNode[]): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n out += node.text?.replace(/\\s+/g, ' ') || '';\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const tag = node.tag;\n const children = node.children || [];\n const inner = walk(children).trim();\n\n // Headings\n if (HEADING_LEVELS[tag]) {\n out += `\\n\\n${HEADING_LEVELS[tag]} ${inner}\\n\\n`;\n continue;\n }\n\n switch (tag) {\n case 'p': out += `\\n\\n${inner}\\n\\n`; break;\n case 'br': out += '\\n'; break;\n case 'hr': out += '\\n\\n---\\n\\n'; break;\n case 'strong': case 'b': if (inner) out += `**${inner}**`; break;\n case 'em': case 'i': if (inner) out += `*${inner}*`; break;\n case 's': case 'del': case 'strike': if (inner) out += `~~${inner}~~`; break;\n case 'code': if (inner) out += `\\`${inner}\\``; break;\n case 'pre': {\n const lang = children.find(c => c.tag === 'code')?.attributes?.class?.match(/language-(\\w+)/)?.[1] || '';\n out += `\\n\\n\\`\\`\\`${lang}\\n${inner}\\n\\`\\`\\`\\n\\n`;\n break;\n }\n case 'a': {\n const href = resolveUrl(node.attributes?.href || '');\n const text = inner || node.attributes?.['aria-label'] || node.attributes?.title || '';\n if (!text) break;\n if (!href || href === '#' || href.startsWith('javascript:')) { out += text; break; }\n out += `[${text}](${href})`;\n break;\n }\n case 'img': {\n const alt = node.attributes?.alt || '';\n const src = resolveUrl(node.attributes?.src || '');\n if (src) out += `![${alt}](${src})`;\n break;\n }\n case 'ul': listDepth++; olCounter.push(0); out += '\\n' + walk(children); listDepth--; olCounter.pop(); break;\n case 'ol': listDepth++; olCounter.push(0); out += '\\n' + walk(children); listDepth--; olCounter.pop(); break;\n case 'li': {\n const indent = ' '.repeat(Math.max(0, listDepth - 1));\n const isOrdered = olCounter.length > 0 && olCounter[olCounter.length - 1] >= 0;\n if (isOrdered && olCounter.length > 0) olCounter[olCounter.length - 1]++;\n const counter = isOrdered && olCounter.length > 0 ? olCounter[olCounter.length - 1] : 0;\n const bullet = isOrdered ? `${counter}. ` : '- ';\n out += `${indent}${bullet}${inner}\\n`;\n break;\n }\n case 'blockquote': {\n if (inner) out += '\\n\\n' + inner.split('\\n').map(l => `> ${l}`).join('\\n') + '\\n\\n';\n break;\n }\n case 'table': {\n // Collect rows\n const rows = collectTableRows(children);\n if (rows.length > 0) {\n out += '\\n\\n';\n for (let i = 0; i < rows.length; i++) {\n out += '| ' + rows[i].join(' | ') + ' |\\n';\n if (i === 0) out += '| ' + rows[i].map(() => '---').join(' | ') + ' |\\n';\n }\n out += '\\n';\n }\n break;\n }\n case 'dt': out += `\\n**${inner}**\\n`; break;\n case 'dd': out += `: ${inner}\\n`; break;\n case 'figcaption': out += `\\n*${inner}*\\n`; break;\n case 'summary': out += `**${inner}**\\n\\n`; break;\n default:\n if (BLOCK_TAGS.has(tag)) {\n out += '\\n' + walk(children) + '\\n';\n } else {\n out += walk(children);\n }\n }\n }\n return out;\n }\n\n function collectTableRows(nodes: HtmlNode[]): string[][] {\n const rows: string[][] = [];\n for (const node of nodes) {\n if (node.tag === 'tr') {\n const cells: string[] = [];\n for (const cell of node.children || []) {\n if (cell.tag === 'td' || cell.tag === 'th') {\n cells.push(walk(cell.children || []).trim().replace(/\\|/g, '\\\\|').replace(/\\n/g, ' '));\n }\n }\n if (cells.length > 0) rows.push(cells);\n } else if (node.tag === 'thead' || node.tag === 'tbody' || node.tag === 'tfoot') {\n rows.push(...collectTableRows(node.children || []));\n }\n }\n return rows;\n }\n\n const raw = walk(nodes);\n return raw.replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Extract a snapshot with interactive element indices.\n */\nexport function extractSnapshot(nodes: HtmlNode[]): string {\n let idx = 0;\n const ATTR_WHITELIST = ['type', 'role', 'aria-label', 'placeholder', 'href', 'value', 'name', 'alt'];\n\n function isInteractive(node: HtmlNode): boolean {\n if (!node.tag) return false;\n if (INTERACTIVE_TAGS.has(node.tag)) return true;\n const role = node.attributes?.role;\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (node.attributes?.contenteditable === 'true') return true;\n if (node.attributes?.tabindex && parseInt(node.attributes.tabindex) >= 0) return true;\n return false;\n }\n\n function getAttrs(node: HtmlNode): string {\n const parts: string[] = [];\n for (const name of ATTR_WHITELIST) {\n const v = node.attributes?.[name];\n if (v) parts.push(`${name}=${v.slice(0, 60)}`);\n }\n return parts.length ? ' ' + parts.join(' ') : '';\n }\n\n function walk(nodes: HtmlNode[], depth: number): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n const t = node.text?.trim();\n if (t) out += ' '.repeat(depth) + t.slice(0, 150) + '\\n';\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const indent = ' '.repeat(depth);\n const inter = isInteractive(node);\n const prefix = inter ? `[${idx++}]` : '';\n const attrs = getAttrs(node);\n\n // Leaf text\n const leafText = node.children?.length === 1 && node.children[0].type === 'text'\n ? (node.children[0].text?.trim().slice(0, 150) || '') : '';\n\n if (inter || leafText || !node.children?.length) {\n if (leafText) {\n out += `${indent}${prefix}<${node.tag}${attrs}>${leafText}</${node.tag}>\\n`;\n } else {\n out += `${indent}${prefix}<${node.tag}${attrs}>\\n`;\n if (node.children) out += walk(node.children, depth + 1);\n }\n } else {\n if (node.children) out += walk(node.children, depth);\n }\n }\n return out;\n }\n\n return walk(nodes, 0);\n}\n\n/**\n * Extract links from parsed HTML.\n */\nexport function extractLinks(nodes: HtmlNode[], baseUrl?: string): { text: string; href: string }[] {\n const links: { text: string; href: string }[] = [];\n\n function walk(nodes: HtmlNode[]) {\n for (const node of nodes) {\n if (node.type === 'element' && node.tag === 'a' && node.attributes?.href) {\n let href = node.attributes.href;\n if (baseUrl && !href.startsWith('http')) {\n try { href = new URL(href, baseUrl).href; } catch {}\n }\n const text = extractText(node.children || []).trim();\n if (text && href && !href.startsWith('javascript:')) {\n links.push({ text: text.slice(0, 200), href });\n }\n }\n if (node.children) walk(node.children);\n }\n }\n\n walk(nodes);\n return links;\n}\n\n// ── Main fetch function (replaces Lightpanda binary) ──\n\nexport interface LobsterFetchResult {\n url: string;\n finalUrl: string;\n status: number;\n title: string;\n content: string;\n links?: { text: string; href: string }[];\n duration: number;\n}\n\n/**\n * Fetch a URL and extract content — no Chrome, no external binary.\n * Uses our in-house HTML parser.\n */\nexport async function lobsterFetch(\n url: string,\n options?: {\n dump?: 'markdown' | 'text' | 'snapshot' | 'html' | 'links';\n timeout?: number;\n headers?: Record<string, string>;\n followRedirects?: boolean;\n },\n): Promise<LobsterFetchResult> {\n const timeout = options?.timeout || 30000;\n const dump = options?.dump || 'markdown';\n\n const start = Date.now();\n\n const resp = await fetch(url, {\n headers: {\n 'User-Agent': 'LobsterCLI/0.1 (+https://github.com/iexcalibur/lobster-cli)',\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.5',\n ...(options?.headers || {}),\n },\n redirect: options?.followRedirects !== false ? 'follow' : 'manual',\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!resp.ok) {\n throw new Error(`HTTP ${resp.status} ${resp.statusText}`);\n }\n\n const html = await resp.text();\n const duration = Date.now() - start;\n const finalUrl = resp.url || url;\n\n // Parse\n const nodes = parseHtml(html);\n\n // Extract title\n let title = '';\n function findTitle(nodes: HtmlNode[]): void {\n for (const node of nodes) {\n if (node.tag === 'title' && node.children?.[0]?.text) {\n title = node.children[0].text.trim();\n return;\n }\n if (node.children) findTitle(node.children);\n }\n }\n findTitle(nodes);\n\n // Extract content based on dump format\n let content: string;\n let links: { text: string; href: string }[] | undefined;\n\n switch (dump) {\n case 'markdown':\n content = extractMarkdown(nodes, finalUrl);\n break;\n case 'text':\n content = extractText(nodes);\n break;\n case 'snapshot':\n content = extractSnapshot(nodes);\n break;\n case 'html':\n content = html;\n break;\n case 'links':\n links = extractLinks(nodes, finalUrl);\n content = links.map((l, i) => `${i + 1}. [${l.text}](${l.href})`).join('\\n');\n break;\n default:\n content = extractMarkdown(nodes, finalUrl);\n }\n\n return { url, finalUrl, status: resp.status, title, content, links, duration };\n}\n\n// Keep these exports for backward compatibility\nexport function isLightpandaAvailable(): boolean { return true; } // Our engine is always available\nexport function getInstallInstructions(): string { return 'Built-in — no installation needed'; }\n","import type { StepHandler } from '../types/pipeline.js';\n\nconst stepHandlers = new Map<string, StepHandler>();\n\nexport function registerStep(name: string, handler: StepHandler): void {\n stepHandlers.set(name, handler);\n}\n\nexport function getStep(name: string): StepHandler | undefined {\n return stepHandlers.get(name);\n}\n\nexport function getStepNames(): string[] {\n return [...stepHandlers.keys()];\n}\n","import type { IPage } from '../types/page.js';\nimport type { PipelineContext, PipelineStepDef } from '../types/pipeline.js';\nimport { getStep } from './registry.js';\nimport { log } from '../utils/logger.js';\n\nexport async function executePipeline(\n steps: PipelineStepDef[],\n page: IPage | null,\n args: Record<string, unknown>,\n debug = false\n): Promise<unknown> {\n const ctx: PipelineContext = { page, args, data: null, debug };\n\n for (let i = 0; i < steps.length; i++) {\n const stepDef = steps[i];\n const [stepName, params] = Object.entries(stepDef)[0];\n\n const handler = getStep(stepName);\n if (!handler) {\n throw new Error(`Unknown pipeline step: ${stepName}`);\n }\n\n if (debug) {\n log.step(i + 1, `${stepName}`);\n }\n\n ctx.data = await handler(ctx, params);\n\n if (debug && ctx.data !== undefined) {\n const preview = JSON.stringify(ctx.data)?.slice(0, 200);\n log.dim(` → ${preview}...`);\n }\n }\n\n return ctx.data;\n}\n","/**\n * Template expression engine for pipeline YAML.\n * Resolves ${{ expr }} expressions with context variables and filters.\n */\n\nconst EXPR_RE = /\\$\\{\\{\\s*(.*?)\\s*\\}\\}/g;\n\ninterface RenderContext {\n args: Record<string, unknown>;\n item?: unknown;\n data?: unknown;\n index?: number;\n}\n\nexport function renderTemplate(template: unknown, ctx: RenderContext): unknown {\n if (typeof template !== 'string') {\n if (typeof template === 'object' && template !== null) {\n if (Array.isArray(template)) return template.map((v) => renderTemplate(v, ctx));\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(template)) {\n result[k] = renderTemplate(v, ctx);\n }\n return result;\n }\n return template;\n }\n\n // Full expression: entire string is one expression — return raw value (not stringified)\n const fullMatch = template.match(/^\\$\\{\\{\\s*(.*?)\\s*\\}\\}$/);\n if (fullMatch) {\n return evaluateExpression(fullMatch[1], ctx);\n }\n\n // Partial: interpolate into string\n return template.replace(EXPR_RE, (_, expr) => {\n const val = evaluateExpression(expr, ctx);\n return val === null || val === undefined ? '' : String(val);\n });\n}\n\nfunction evaluateExpression(expr: string, ctx: RenderContext): unknown {\n // Handle pipe filters: expr | filter(arg)\n const parts = expr.split(/\\s*\\|\\s*/);\n let value = resolveValue(parts[0].trim(), ctx);\n\n for (let i = 1; i < parts.length; i++) {\n value = applyFilter(value, parts[i].trim());\n }\n\n return value;\n}\n\nfunction resolveValue(path: string, ctx: RenderContext): unknown {\n // Handle simple arithmetic: index + 1\n const arithMatch = path.match(/^(\\w[\\w.]*)\\s*([+\\-*])\\s*(\\d+)$/);\n if (arithMatch) {\n const base = Number(resolvePath(arithMatch[1], ctx));\n const op = arithMatch[2];\n const num = Number(arithMatch[3]);\n if (op === '+') return base + num;\n if (op === '-') return base - num;\n if (op === '*') return base * num;\n }\n\n // Handle logical OR: a || b\n const orMatch = path.match(/^(.+?)\\s*\\|\\|\\s*(.+)$/);\n if (orMatch) {\n const left = resolvePath(orMatch[1].trim(), ctx);\n if (left !== null && left !== undefined && left !== '' && left !== false) return left;\n // Right side: could be a string literal\n const right = orMatch[2].trim();\n if ((right.startsWith(\"'\") && right.endsWith(\"'\")) || (right.startsWith('\"') && right.endsWith('\"'))) {\n return right.slice(1, -1);\n }\n return resolvePath(right, ctx);\n }\n\n // String literal\n if ((path.startsWith(\"'\") && path.endsWith(\"'\")) || (path.startsWith('\"') && path.endsWith('\"'))) {\n return path.slice(1, -1);\n }\n\n // Number literal\n if (!isNaN(Number(path)) && path !== '') return Number(path);\n\n return resolvePath(path, ctx);\n}\n\nfunction resolvePath(path: string, ctx: RenderContext): unknown {\n // Resolve against context: args.*, item.*, data.*, index\n if (path === 'index') return ctx.index ?? 0;\n\n const parts = path.split('.');\n let root: unknown;\n\n if (parts[0] === 'args') {\n root = ctx.args;\n parts.shift();\n } else if (parts[0] === 'item') {\n root = ctx.item;\n parts.shift();\n } else if (parts[0] === 'data') {\n root = ctx.data;\n parts.shift();\n } else {\n // Try item first, then args, then data\n root = getNestedValue(ctx.item, parts);\n if (root !== undefined) return root;\n root = getNestedValue(ctx.args, parts);\n if (root !== undefined) return root;\n root = getNestedValue(ctx.data, parts);\n if (root !== undefined) return root;\n return undefined;\n }\n\n return getNestedValue(root, parts);\n}\n\nfunction getNestedValue(obj: unknown, parts: string[]): unknown {\n let current = obj;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current === 'object') {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\nfunction applyFilter(value: unknown, filter: string): unknown {\n const match = filter.match(/^(\\w+)(?:\\((.+)\\))?$/);\n if (!match) return value;\n\n const name = match[1];\n const arg = match[2]?.replace(/^['\"]|['\"]$/g, '');\n\n switch (name) {\n case 'default':\n return value === null || value === undefined || value === '' ? arg : value;\n case 'join':\n return Array.isArray(value) ? value.join(arg || ', ') : value;\n case 'upper':\n return typeof value === 'string' ? value.toUpperCase() : value;\n case 'lower':\n return typeof value === 'string' ? value.toLowerCase() : value;\n case 'trim':\n return typeof value === 'string' ? value.trim() : value;\n case 'truncate': {\n const len = parseInt(arg || '100');\n if (typeof value === 'string' && value.length > len) return value.slice(0, len) + '...';\n return value;\n }\n case 'replace': {\n if (typeof value !== 'string' || !arg) return value;\n const [from, to] = arg.split(',').map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''));\n return value.replaceAll(from, to || '');\n }\n case 'keys':\n return typeof value === 'object' && value !== null ? Object.keys(value) : [];\n case 'length':\n return Array.isArray(value) ? value.length : typeof value === 'string' ? value.length : 0;\n case 'first':\n return Array.isArray(value) ? value[0] : value;\n case 'last':\n return Array.isArray(value) ? value[value.length - 1] : value;\n case 'json':\n return JSON.stringify(value);\n case 'slugify':\n return typeof value === 'string' ? value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') : value;\n case 'sanitize':\n // Filename-safe: remove/replace dangerous chars\n return typeof value === 'string' ? value.replace(/[<>:\"/\\\\|?*\\x00-\\x1f]/g, '_').replace(/__+/g, '_').trim() : value;\n case 'ext': {\n // Extract file extension from URL/path\n if (typeof value !== 'string') return '';\n const extMatch = value.match(/\\.([a-zA-Z0-9]+)(?:\\?.*)?$/);\n return extMatch ? extMatch[1] : '';\n }\n case 'basename': {\n // Extract filename from URL/path\n if (typeof value !== 'string') return '';\n try { return new URL(value).pathname.split('/').pop() || ''; } catch {}\n return value.split('/').pop() || '';\n }\n default:\n return value;\n }\n}\n","import type { IPage } from './page.js';\n\nexport enum Strategy {\n PUBLIC = 'public',\n COOKIE = 'cookie',\n HEADER = 'header',\n INTERCEPT = 'intercept',\n UI = 'ui',\n}\n\nexport interface Arg {\n name: string;\n type?: 'string' | 'int' | 'float' | 'boolean';\n default?: unknown;\n required?: boolean;\n positional?: boolean;\n help?: string;\n choices?: string[];\n}\n\nexport interface Adapter {\n site: string;\n name: string;\n description: string;\n domain?: string;\n strategy: Strategy;\n browser: boolean;\n args: Arg[];\n columns?: string[];\n func?: (page: IPage, kwargs: Record<string, unknown>) => Promise<unknown>;\n pipeline?: Record<string, unknown>[];\n timeoutSeconds?: number;\n navigateBefore?: boolean | string;\n}\n","import type { Adapter } from '../types/adapter.js';\nimport { Strategy } from '../types/adapter.js';\n\n// Global registry — shared across module instances (critical for plugins)\nconst REGISTRY_KEY = '__lobster_registry__';\nif (!(globalThis as any)[REGISTRY_KEY]) {\n (globalThis as any)[REGISTRY_KEY] = new Map<string, Adapter>();\n}\n\nfunction getRegistry(): Map<string, Adapter> {\n return (globalThis as any)[REGISTRY_KEY];\n}\n\nexport function cli(def: Partial<Adapter> & { site: string; name: string }): Adapter {\n const adapter: Adapter = {\n site: def.site,\n name: def.name,\n description: def.description || `${def.site} ${def.name}`,\n domain: def.domain,\n strategy: def.strategy || Strategy.PUBLIC,\n browser: def.browser ?? (def.strategy !== Strategy.PUBLIC),\n args: def.args || [],\n columns: def.columns,\n func: def.func,\n pipeline: def.pipeline,\n timeoutSeconds: def.timeoutSeconds,\n navigateBefore: def.navigateBefore,\n };\n\n const fullName = `${adapter.site}/${adapter.name}`;\n getRegistry().set(fullName, adapter);\n return adapter;\n}\n\nexport function getAdapter(site: string, name: string): Adapter | undefined {\n return getRegistry().get(`${site}/${name}`);\n}\n\nexport function getAdapterBySite(site: string): Adapter[] {\n const adapters: Adapter[] = [];\n for (const [key, adapter] of getRegistry()) {\n if (key.startsWith(`${site}/`)) adapters.push(adapter);\n }\n return adapters;\n}\n\nexport function getAdapterByDomain(domain: string): Adapter[] {\n const adapters: Adapter[] = [];\n for (const adapter of getRegistry().values()) {\n if (adapter.domain && domain.includes(adapter.domain)) adapters.push(adapter);\n }\n return adapters;\n}\n\nexport function getAllAdapters(): Adapter[] {\n return [...getRegistry().values()];\n}\n\nexport function getAllSites(): string[] {\n const sites = new Set<string>();\n for (const adapter of getRegistry().values()) {\n sites.add(adapter.site);\n }\n return [...sites].sort();\n}\n\nexport { Strategy };\n","/**\n * Site exploration: navigate, capture network, analyze APIs, infer capabilities.\n *\n * Based on OpenCLI's explore module with:\n * - URL pattern normalization (/123 → /{id})\n * - Auth detection (bearer, CSRF, signature)\n * - Response body analysis (item arrays, field roles)\n * - Framework & store detection\n * - Artifact generation\n */\n\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IPage } from '../types/page.js';\nimport { log } from '../utils/logger.js';\n\n// ── Known site aliases ──\nconst SITE_ALIASES: Record<string, string> = {\n 'x.com': 'twitter', 'twitter.com': 'twitter',\n 'news.ycombinator.com': 'hackernews',\n 'old.reddit.com': 'reddit', 'www.reddit.com': 'reddit',\n 'bilibili.com': 'bilibili', 'www.bilibili.com': 'bilibili',\n 'zhihu.com': 'zhihu', 'www.zhihu.com': 'zhihu',\n};\n\n// ── Field role mapping ──\nconst FIELD_ROLES: Record<string, string[]> = {\n title: ['title', 'name', 'headline', 'subject', 'text', 'caption'],\n url: ['url', 'link', 'href', 'permalink', 'uri', 'web_url'],\n author: ['author', 'user', 'creator', 'owner', 'by', 'username', 'screen_name', 'display_name'],\n score: ['score', 'points', 'likes', 'upvotes', 'karma', 'vote_count', 'favorite_count', 'retweet_count'],\n time: ['time', 'date', 'created', 'created_at', 'timestamp', 'published', 'updated_at', 'posted_at'],\n description: ['description', 'summary', 'snippet', 'excerpt', 'body', 'content', 'selftext'],\n image: ['image', 'thumbnail', 'avatar', 'icon', 'photo', 'cover', 'poster'],\n id: ['id', 'uid', 'pid', 'mid', 'aid', 'bvid'],\n};\n\n// ── Volatile query params to ignore ──\nconst VOLATILE_PARAMS = new Set([\n '_', 't', 'ts', 'timestamp', 'nonce', 'rand', 'random',\n 'callback', 'jsonp', '_t', '__t',\n]);\n\nexport interface EndpointInfo {\n url: string;\n pattern: string;\n method: string;\n status: number;\n contentType: string;\n queryParams: string[];\n hasItems: boolean;\n itemCount: number;\n fields: string[];\n fieldRoles: Record<string, string>;\n authIndicators: string[];\n score: number;\n}\n\nexport interface ExploreResult {\n site: string;\n domain: string;\n endpoints: EndpointInfo[];\n strategy: string;\n framework?: string;\n stores?: { name: string; type: string; actions: string[] }[];\n capabilities: string[];\n artifactDir?: string;\n}\n\nexport interface ExploreOptions {\n wait?: number;\n scroll?: boolean;\n fuzz?: boolean;\n outputDir?: string;\n maxButtons?: number;\n scrollAttempts?: number;\n}\n\n/**\n * Normalize a URL path to a pattern:\n * /users/123/posts → /users/{id}/posts\n * /item/abc123def → /item/{hex}\n */\nfunction normalizeUrlPattern(urlStr: string): string {\n try {\n const u = new URL(urlStr);\n const parts = u.pathname.split('/');\n const normalized = parts.map((p) => {\n if (!p) return p;\n if (/^\\d+$/.test(p)) return '{id}';\n if (/^[a-f0-9]{8,}$/i.test(p)) return '{hex}';\n if (/^BV[a-zA-Z0-9]+$/.test(p)) return '{bvid}';\n if (/^[a-z0-9]{20,}$/i.test(p)) return '{token}';\n return p;\n });\n return u.origin + normalized.join('/');\n } catch {\n return urlStr;\n }\n}\n\n/**\n * Detect auth indicators in request headers/URL.\n */\nfunction detectAuth(url: string, headers?: Record<string, string>): string[] {\n const indicators: string[] = [];\n if (url.includes('signature') || url.includes('sign=') || url.includes('sig=')) indicators.push('signature');\n if (url.includes('token=') || url.includes('access_token=')) indicators.push('token');\n if (url.includes('api_key=') || url.includes('apikey=')) indicators.push('api_key');\n if (headers) {\n if (headers['authorization']?.startsWith('Bearer')) indicators.push('bearer');\n if (headers['x-csrf-token'] || headers['x-xsrf-token']) indicators.push('csrf');\n }\n return indicators;\n}\n\n/**\n * Analyze a JSON response body to find item arrays and extract fields.\n */\nfunction analyzeResponseBody(body: unknown): {\n hasItems: boolean;\n itemCount: number;\n fields: string[];\n fieldRoles: Record<string, string>;\n} {\n if (!body || typeof body !== 'object') {\n return { hasItems: false, itemCount: 0, fields: [], fieldRoles: {} };\n }\n\n // Find the item array — could be at root or nested\n let items: unknown[] | null = null;\n\n if (Array.isArray(body)) {\n items = body;\n } else {\n // Search common nested paths: data, results, items, list, entries, records, hits\n const obj = body as Record<string, unknown>;\n for (const key of ['data', 'results', 'items', 'list', 'entries', 'records', 'hits', 'posts', 'articles', 'stories']) {\n const val = obj[key];\n if (Array.isArray(val) && val.length > 0) {\n items = val;\n break;\n }\n // One level deeper: data.items, data.list, etc.\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n for (const subKey of ['items', 'list', 'data', 'results', 'entries']) {\n const subVal = (val as Record<string, unknown>)[subKey];\n if (Array.isArray(subVal) && subVal.length > 0) {\n items = subVal;\n break;\n }\n }\n if (items) break;\n }\n }\n }\n\n if (!items || items.length === 0) {\n return { hasItems: false, itemCount: 0, fields: [], fieldRoles: {} };\n }\n\n // Extract fields from first item\n const firstItem = items[0];\n if (!firstItem || typeof firstItem !== 'object') {\n return { hasItems: true, itemCount: items.length, fields: [], fieldRoles: {} };\n }\n\n const fields = Object.keys(firstItem as Record<string, unknown>);\n\n // Map fields to semantic roles\n const fieldRoles: Record<string, string> = {};\n for (const field of fields) {\n const lower = field.toLowerCase();\n for (const [role, patterns] of Object.entries(FIELD_ROLES)) {\n if (patterns.some((p) => lower.includes(p))) {\n fieldRoles[field] = role;\n break;\n }\n }\n }\n\n return { hasItems: true, itemCount: items.length, fields, fieldRoles };\n}\n\n/**\n * Score an endpoint for relevance.\n */\nfunction scoreEndpoint(ep: Omit<EndpointInfo, 'score'>): number {\n let score = 0;\n\n // Content type\n if (ep.contentType.includes('json')) score += 10;\n\n // Response analysis\n if (ep.hasItems) score += 5;\n if (ep.itemCount > 3) score += 3;\n if (ep.itemCount > 10) score += 2;\n if (Object.keys(ep.fieldRoles).length > 2) score += 3;\n\n // URL patterns\n if (ep.url.includes('/api/')) score += 5;\n if (ep.url.includes('/v1/') || ep.url.includes('/v2/') || ep.url.includes('/v3/')) score += 3;\n const path = new URL(ep.url).pathname.toLowerCase();\n if (/search|query|find/.test(path)) score += 4;\n if (/hot|trending|popular|top|feed|timeline/.test(path)) score += 4;\n if (/list|index|all|latest|recent/.test(path)) score += 3;\n\n // Query params\n if (ep.queryParams.some((p) => /search|keyword|query|q/.test(p))) score += 3;\n if (ep.queryParams.some((p) => /page|offset|cursor|limit|count|num/.test(p))) score += 2;\n\n // Method\n if (ep.method === 'GET') score += 2;\n\n // Auth complexity penalty\n if (ep.authIndicators.includes('signature')) score -= 2;\n\n // Penalize static assets\n if (/\\.(js|css|png|jpg|gif|svg|woff|ico)/.test(ep.url)) score -= 30;\n\n // Penalize tracking/analytics\n if (/analytics|tracking|pixel|beacon|log\\b/.test(ep.url)) score -= 20;\n\n return score;\n}\n\n/**\n * Infer capabilities from discovered endpoints.\n */\nfunction inferCapabilities(endpoints: EndpointInfo[]): string[] {\n const caps: string[] = [];\n for (const ep of endpoints) {\n const path = ep.url.toLowerCase();\n if (/search|query|find/.test(path) && !caps.includes('search')) caps.push('search');\n if (/hot|trending|popular/.test(path) && !caps.includes('hot')) caps.push('hot');\n if (/feed|timeline|home/.test(path) && !caps.includes('feed')) caps.push('feed');\n if (/detail|item\\/\\{|article\\/\\{|post\\/\\{/.test(ep.pattern) && !caps.includes('detail')) caps.push('detail');\n if (/comment|reply|discuss/.test(path) && !caps.includes('comments')) caps.push('comments');\n if (/user|profile|me\\b|account/.test(path) && !caps.includes('me')) caps.push('me');\n if (/favorite|bookmark|saved|like/.test(path) && !caps.includes('favorites')) caps.push('favorites');\n if (/history|watch|read/.test(path) && !caps.includes('history')) caps.push('history');\n }\n return caps;\n}\n\n/**\n * Smart auto-scroll with MutationObserver-based lazy-load detection.\n * Waits for new DOM nodes to appear after each scroll instead of fixed delays.\n */\nasync function smartAutoScroll(page: IPage, attempts: number): Promise<void> {\n for (let i = 0; i < attempts; i++) {\n const scrolled = await page.evaluate<boolean>(`\n (async () => {\n const lastHeight = document.body.scrollHeight;\n window.scrollTo(0, lastHeight);\n\n // Wait for new content via MutationObserver or timeout\n const result = await new Promise((resolve) => {\n let timeoutId;\n const observer = new MutationObserver(() => {\n if (document.body.scrollHeight > lastHeight) {\n clearTimeout(timeoutId);\n observer.disconnect();\n setTimeout(() => resolve(true), 100);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n timeoutId = setTimeout(() => { observer.disconnect(); resolve(false); }, 2000);\n });\n return result;\n })()\n `);\n if (!scrolled) break; // No new content loaded, stop scrolling\n }\n}\n\n/**\n * Interactive fuzzing — click buttons/tabs to trigger hidden API calls.\n * Clicks up to maxButtons interactive elements that look like data triggers.\n */\nasync function interactiveFuzz(page: IPage, maxButtons: number): Promise<void> {\n await page.evaluate(`\n (async () => {\n const clickTargets = [];\n const selectors = [\n 'button:not([disabled])',\n '[role=\"tab\"]',\n '[role=\"button\"]',\n '.tab', '.nav-link', '.dropdown-toggle',\n 'a[data-toggle]', '[data-bs-toggle]',\n ];\n\n for (const sel of selectors) {\n for (const el of document.querySelectorAll(sel)) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0 &&\n rect.top >= 0 && rect.top < window.innerHeight * 2) {\n const text = el.textContent?.trim()?.slice(0, 40) || '';\n // Skip destructive-looking buttons\n if (/delete|remove|logout|sign.?out|cancel|close/i.test(text)) continue;\n clickTargets.push(el);\n }\n }\n }\n\n // Click up to N targets with delays\n const max = Math.min(${maxButtons}, clickTargets.length);\n for (let i = 0; i < max; i++) {\n try {\n clickTargets[i].click();\n await new Promise(r => setTimeout(r, 800));\n } catch {}\n }\n })()\n `);\n await page.wait(1.5);\n}\n\n/**\n * Re-fetch JSON endpoints whose response body was missing from interception.\n * Uses an iframe to avoid CORS issues (same-origin cookies).\n */\nasync function recoverMissingBodies(\n page: IPage,\n endpoints: EndpointInfo[],\n): Promise<void> {\n const needsRecovery = endpoints.filter(\n (ep) => !ep.hasItems && ep.contentType.includes('json') && ep.score > 5,\n );\n\n if (needsRecovery.length === 0) return;\n\n const urls = needsRecovery.map((ep) => ep.url).slice(0, 8);\n\n const bodies = await page.evaluate<(unknown | null)[]>(`\n (async () => {\n const urls = ${JSON.stringify(urls)};\n const results = [];\n for (const url of urls) {\n try {\n const resp = await fetch(url, { credentials: 'include' });\n if (resp.ok) {\n const json = await resp.json();\n results.push(json);\n } else {\n results.push(null);\n }\n } catch { results.push(null); }\n }\n return results;\n })()\n `);\n\n if (!bodies) return;\n\n for (let i = 0; i < urls.length; i++) {\n if (!bodies[i]) continue;\n const ep = needsRecovery[i];\n const analysis = analyzeResponseBody(bodies[i]);\n if (analysis.hasItems) {\n ep.hasItems = analysis.hasItems;\n ep.itemCount = analysis.itemCount;\n ep.fields = analysis.fields;\n ep.fieldRoles = analysis.fieldRoles;\n ep.score = scoreEndpoint(ep);\n }\n }\n}\n\n/**\n * Write exploration artifacts to disk.\n */\nfunction writeArtifacts(dir: string, result: ExploreResult): void {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n // manifest.json — site metadata\n writeFileSync(join(dir, 'manifest.json'), JSON.stringify({\n site: result.site,\n domain: result.domain,\n framework: result.framework,\n strategy: result.strategy,\n capabilities: result.capabilities,\n endpointCount: result.endpoints.length,\n exploredAt: new Date().toISOString(),\n }, null, 2));\n\n // endpoints.json — all discovered endpoints with scores/fields\n writeFileSync(join(dir, 'endpoints.json'), JSON.stringify(\n result.endpoints.map((ep) => ({\n url: ep.url,\n pattern: ep.pattern,\n method: ep.method,\n status: ep.status,\n score: ep.score,\n hasItems: ep.hasItems,\n itemCount: ep.itemCount,\n fields: ep.fields,\n fieldRoles: ep.fieldRoles,\n queryParams: ep.queryParams,\n authIndicators: ep.authIndicators,\n })),\n null, 2,\n ));\n\n // capabilities.json — inferred CLI commands\n writeFileSync(join(dir, 'capabilities.json'), JSON.stringify(\n result.capabilities.map((cap) => {\n const matchingEndpoints = result.endpoints.filter((ep) => {\n const path = ep.url.toLowerCase();\n if (cap === 'search') return /search|query|find/.test(path);\n if (cap === 'hot') return /hot|trending|popular/.test(path);\n if (cap === 'feed') return /feed|timeline|home/.test(path);\n return false;\n });\n return {\n name: cap,\n description: `${cap} capability`,\n endpoint: matchingEndpoints[0]?.pattern || null,\n strategy: result.strategy,\n confidence: matchingEndpoints.length > 0 ? 0.8 : 0.5,\n recommendedColumns: matchingEndpoints[0]?.fields?.slice(0, 6) || [],\n };\n }),\n null, 2,\n ));\n\n // auth.json — auth indicators\n const authSummary: Record<string, string[]> = {};\n for (const ep of result.endpoints) {\n for (const ind of ep.authIndicators) {\n if (!authSummary[ind]) authSummary[ind] = [];\n authSummary[ind].push(ep.pattern);\n }\n }\n writeFileSync(join(dir, 'auth.json'), JSON.stringify(authSummary, null, 2));\n\n // stores.json — Vue/React stores if detected\n if (result.stores && result.stores.length > 0) {\n writeFileSync(join(dir, 'stores.json'), JSON.stringify(result.stores, null, 2));\n }\n\n log.success(`Artifacts written to ${dir}/`);\n}\n\nexport async function exploreSite(\n page: IPage,\n url: string,\n options?: ExploreOptions,\n): Promise<ExploreResult> {\n const parsedUrl = new URL(url);\n const domain = parsedUrl.hostname;\n const site = SITE_ALIASES[domain] || domain.replace(/^www\\./, '').split('.')[0];\n\n log.info(`Exploring ${url}...`);\n\n // Install network interceptor before navigation\n await page.installInterceptor('');\n await page.goto(url);\n await page.wait(options?.wait || 3);\n\n // Smart auto-scroll with MutationObserver lazy-load detection\n if (options?.scroll !== false) {\n log.debug('Smart auto-scrolling to trigger lazy-loaded APIs...');\n await smartAutoScroll(page, options?.scrollAttempts || 4);\n }\n\n // Interactive fuzzing — click buttons/tabs to discover hidden APIs\n if (options?.fuzz !== false) {\n log.debug('Fuzzing interactive elements...');\n await interactiveFuzz(page, options?.maxButtons || 12);\n }\n\n // Capture intercepted network requests\n const rawRequests = await page.getInterceptedRequests();\n\n // Analyze each request\n const seen = new Set<string>();\n const endpoints: EndpointInfo[] = [];\n\n for (const raw of rawRequests as any[]) {\n if (!raw?.url || !raw?.status) continue;\n if (raw.status < 200 || raw.status >= 400) continue;\n\n const pattern = normalizeUrlPattern(raw.url);\n const dedupeKey = `${raw.method || 'GET'}:${pattern}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n\n // Extract query params\n let queryParams: string[] = [];\n try {\n const u = new URL(raw.url);\n queryParams = [...u.searchParams.keys()].filter((k) => !VOLATILE_PARAMS.has(k));\n } catch {}\n\n const authIndicators = detectAuth(raw.url);\n const bodyAnalysis = analyzeResponseBody(raw.body);\n\n const ep: Omit<EndpointInfo, 'score'> = {\n url: raw.url,\n pattern,\n method: raw.method || 'GET',\n status: raw.status,\n contentType: 'json',\n queryParams,\n ...bodyAnalysis,\n authIndicators,\n };\n\n endpoints.push({ ...ep, score: scoreEndpoint(ep) });\n }\n\n // Response body recovery — re-fetch endpoints that had missing bodies\n log.debug('Recovering missing response bodies...');\n await recoverMissingBodies(page, endpoints);\n\n endpoints.sort((a, b) => b.score - a.score);\n\n // Detect framework\n const framework = await page.evaluate<string>(`\n (() => {\n const app = document.querySelector('#app');\n if (window.__NEXT_DATA__) return 'nextjs';\n if (window.__NUXT__) return 'nuxt';\n if (app && app.__vue_app__) {\n const gp = app.__vue_app__.config?.globalProperties;\n if (gp?.$pinia) return 'vue+pinia';\n if (gp?.$store) return 'vue+vuex';\n return 'vue';\n }\n if (app && app.__vue__) return 'vue2';\n if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) return 'react';\n if (document.querySelector('[data-reactroot]') || document.querySelector('#__next') || document.querySelector('#root')?.['_reactRootContainer']) return 'react';\n if (window.angular || document.querySelector('[ng-version]')) return 'angular';\n if (window.__svelte_meta) return 'svelte';\n return 'unknown';\n })()\n `).catch(() => 'unknown');\n\n // Detect stores (Pinia/Vuex) — improved detection via __vue_app__\n const stores = await page.evaluate<{ name: string; type: string; actions: string[] }[]>(`\n (() => {\n const results = [];\n const app = document.querySelector('#app');\n\n // Pinia via __vue_app__\n if (app && app.__vue_app__) {\n try {\n const pinia = app.__vue_app__.config?.globalProperties?.$pinia;\n if (pinia && pinia._s) {\n pinia._s.forEach((store, id) => {\n const actions = Object.keys(store).filter(k =>\n typeof store[k] === 'function' && !k.startsWith('$') && !k.startsWith('_')\n );\n const stateKeys = Object.keys(store).filter(k =>\n typeof store[k] !== 'function' && !k.startsWith('$') && !k.startsWith('_')\n );\n results.push({ name: id, type: 'pinia', actions: actions.slice(0, 20), stateKeys: stateKeys.slice(0, 20) });\n });\n }\n } catch {}\n\n // Vuex via __vue_app__\n try {\n const store = app.__vue_app__.config?.globalProperties?.$store;\n if (store && store._actions) {\n const actions = Object.keys(store._actions);\n results.push({ name: 'vuex', type: 'vuex', actions: actions.slice(0, 20) });\n }\n } catch {}\n }\n\n // Legacy Pinia global\n if (results.length === 0 && window.__pinia) {\n try {\n const pinia = window.__pinia;\n for (const [id, store] of pinia._s || []) {\n const actions = Object.keys(store).filter(k => typeof store[k] === 'function' && !k.startsWith('$') && !k.startsWith('_'));\n results.push({ name: id, type: 'pinia', actions: actions.slice(0, 20) });\n }\n } catch {}\n }\n\n return results;\n })()\n `).catch(() => []);\n\n // Infer strategy\n let strategy = 'public';\n if (endpoints.length > 0) {\n const topEp = endpoints[0];\n if (topEp.authIndicators.includes('signature')) strategy = 'intercept';\n else if (topEp.authIndicators.includes('bearer') || topEp.authIndicators.includes('csrf')) strategy = 'header';\n else if (endpoints.some((e) => !e.hasItems) && endpoints.some((e) => e.hasItems)) strategy = 'cookie';\n } else {\n strategy = 'cookie';\n }\n\n const capabilities = inferCapabilities(endpoints);\n\n const result: ExploreResult = {\n site,\n domain,\n endpoints: endpoints.slice(0, 30),\n strategy,\n framework,\n stores: stores.length > 0 ? stores : undefined,\n capabilities,\n };\n\n // Write artifacts to disk if outputDir specified\n const outputDir = options?.outputDir || join(process.cwd(), '.lobster', 'explore', site);\n writeArtifacts(outputDir, result);\n result.artifactDir = outputDir;\n\n return result;\n}\n","import yaml from 'js-yaml';\nimport type { ExploreResult } from './explore.js';\n\n/**\n * Generate adapter YAML from explore results.\n * Uses field role mapping to auto-detect column names.\n */\nexport function synthesizeAdapter(result: ExploreResult, goal?: string): string {\n const topEndpoints = result.endpoints.filter((e) => e.score > 0).slice(0, 3);\n if (topEndpoints.length === 0) {\n return `# No API endpoints discovered for ${result.site}\\n# Try using: lobster agent \"your task\" --url https://${result.domain}`;\n }\n\n const endpoint = topEndpoints[0];\n\n // Infer command name from goal or endpoint URL\n let name = goal || 'data';\n if (!goal) {\n const path = new URL(endpoint.url).pathname.toLowerCase();\n if (/search|query/.test(path)) name = 'search';\n else if (/hot|trending|popular/.test(path)) name = 'hot';\n else if (/feed|timeline|home/.test(path)) name = 'feed';\n else if (/top|best|rank/.test(path)) name = 'top';\n }\n\n // Build args from query params\n const args: Record<string, unknown> = {\n limit: { type: 'int', default: 20 },\n };\n for (const param of endpoint.queryParams) {\n if (/search|keyword|query|q/.test(param)) {\n args[param] = { required: true, positional: true, help: 'Search query' };\n } else if (/page|offset|cursor/.test(param)) {\n args[param] = { type: 'int', default: 1 };\n } else if (/limit|count|num|size/.test(param)) {\n // Already have limit\n }\n }\n\n // Build columns from field roles\n const columns: string[] = [];\n const mapTemplate: Record<string, string> = {};\n\n for (const [field, role] of Object.entries(endpoint.fieldRoles)) {\n if (['title', 'url', 'author', 'score', 'time', 'description'].includes(role)) {\n columns.push(role);\n mapTemplate[role] = `\\${{ item.${field} }}`;\n }\n }\n\n // Fallback columns if no roles detected\n if (columns.length === 0) {\n for (const field of endpoint.fields.slice(0, 5)) {\n columns.push(field);\n mapTemplate[field] = `\\${{ item.${field} }}`;\n }\n }\n\n // Build pipeline\n const pipeline: Record<string, unknown>[] = [];\n\n if (result.strategy === 'public' && !endpoint.authIndicators.length) {\n pipeline.push({ fetch: endpoint.url });\n } else {\n // Browser-based fetch with credentials\n pipeline.push({ navigate: `https://${result.domain}` });\n pipeline.push({\n evaluate: `(async () => { const r = await fetch(${JSON.stringify(endpoint.url)}, {credentials:'include'}); return r.json(); })()`,\n });\n }\n\n // Add select step if items are nested\n if (endpoint.hasItems && endpoint.itemCount > 0) {\n // Try to find the array path — check common patterns\n for (const path of ['data', 'results', 'items', 'list', 'data.items', 'data.list']) {\n pipeline.push({ select: path });\n break;\n }\n }\n\n if (Object.keys(mapTemplate).length > 0) {\n pipeline.push({ map: mapTemplate });\n }\n\n pipeline.push({ limit: '${{ args.limit }}' });\n\n const adapter = {\n site: result.site,\n name,\n description: `${name} from ${result.domain}`,\n domain: result.domain,\n strategy: result.strategy,\n browser: result.strategy !== 'public',\n args,\n pipeline,\n columns: columns.length > 0 ? columns : undefined,\n };\n\n return yaml.dump(adapter, { indent: 2, lineWidth: 120 });\n}\n","/**\n * Strategy Cascade: automatic strategy downgrade chain.\n *\n * Probes an API endpoint starting from the simplest strategy (PUBLIC)\n * and downgrades through tiers until one works:\n *\n * PUBLIC → COOKIE → HEADER → INTERCEPT → UI\n */\n\nimport { Strategy } from '../types/adapter.js';\nimport type { IPage } from '../types/page.js';\nimport { log } from '../utils/logger.js';\n\nconst CASCADE_ORDER: Strategy[] = [\n Strategy.PUBLIC,\n Strategy.COOKIE,\n Strategy.HEADER,\n Strategy.INTERCEPT,\n Strategy.UI,\n];\n\nexport interface ProbeResult {\n strategy: Strategy;\n success: boolean;\n statusCode?: number;\n hasData?: boolean;\n error?: string;\n responsePreview?: string;\n}\n\nexport interface CascadeResult {\n bestStrategy: Strategy;\n probes: ProbeResult[];\n confidence: number;\n}\n\n/**\n * Build JavaScript source for a fetch probe that runs inside the browser.\n * Handles credentials and CSRF token extraction.\n */\nfunction buildFetchProbeJs(url: string, opts: {\n credentials?: boolean;\n extractCsrf?: boolean;\n}): string {\n const credentialsLine = opts.credentials ? `credentials: 'include',` : '';\n const headerSetup = opts.extractCsrf\n ? `\n const cookies = document.cookie.split(';').map(c => c.trim());\n const csrf = cookies.find(c =>\n c.startsWith('ct0=') || c.startsWith('csrf_token=') ||\n c.startsWith('_csrf=') || c.startsWith('XSRF-TOKEN=')\n )?.split('=').slice(1).join('=');\n const headers = {};\n if (csrf) { headers['X-Csrf-Token'] = csrf; headers['X-XSRF-Token'] = csrf; }\n `\n : 'const headers = {};';\n\n return `\n (async () => {\n try {\n ${headerSetup}\n const resp = await fetch(${JSON.stringify(url)}, {\n ${credentialsLine}\n headers\n });\n const status = resp.status;\n if (!resp.ok) return { status, ok: false };\n const text = await resp.text();\n let hasData = false;\n try {\n const json = JSON.parse(text);\n hasData = !!json && (Array.isArray(json) ? json.length > 0 :\n typeof json === 'object' && Object.keys(json).length > 0);\n // API-level error codes (common in Chinese sites)\n if (json.code !== undefined && json.code !== 0) hasData = false;\n if (json.error || json.message === 'Unauthorized') hasData = false;\n } catch {}\n return { status, ok: true, hasData, preview: text.slice(0, 200) };\n } catch (e) { return { ok: false, error: e.message }; }\n })()\n `;\n}\n\n/**\n * Probe an endpoint with a specific strategy using in-browser JS evaluation.\n */\nexport async function probeEndpoint(\n page: IPage,\n url: string,\n strategy: Strategy,\n): Promise<ProbeResult> {\n const result: ProbeResult = { strategy, success: false };\n\n try {\n switch (strategy) {\n case Strategy.PUBLIC: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, {}));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.COOKIE: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, { credentials: true }));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.HEADER: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, { credentials: true, extractCsrf: true }));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.INTERCEPT:\n case Strategy.UI:\n result.success = false;\n result.error = `Strategy ${strategy} requires site-specific implementation`;\n break;\n }\n } catch (err: any) {\n result.success = false;\n result.error = err.message ?? String(err);\n }\n\n return result;\n}\n\n/**\n * Run the cascade: try each strategy in order until one works.\n */\nexport async function cascadeProbe(\n page: IPage,\n url: string,\n opts: { maxStrategy?: Strategy } = {},\n): Promise<CascadeResult> {\n const maxIdx = opts.maxStrategy\n ? CASCADE_ORDER.indexOf(opts.maxStrategy)\n : CASCADE_ORDER.indexOf(Strategy.HEADER);\n\n const probes: ProbeResult[] = [];\n\n for (let i = 0; i <= Math.min(maxIdx, CASCADE_ORDER.length - 1); i++) {\n const strategy = CASCADE_ORDER[i];\n log.debug(`Probing strategy: ${strategy}`);\n const probe = await probeEndpoint(page, url, strategy);\n probes.push(probe);\n\n if (probe.success) {\n return {\n bestStrategy: strategy,\n probes,\n confidence: 1.0 - (i * 0.1),\n };\n }\n }\n\n return {\n bestStrategy: Strategy.COOKIE,\n probes,\n confidence: 0.3,\n };\n}\n\nexport function renderCascadeResult(result: CascadeResult): string {\n const lines = [\n `Strategy Cascade: ${result.bestStrategy} (${(result.confidence * 100).toFixed(0)}% confidence)`,\n ];\n for (const probe of result.probes) {\n const icon = probe.success ? '\\u2705' : '\\u274C';\n const status = probe.statusCode ? ` [${probe.statusCode}]` : '';\n const err = probe.error ? ` \\u2014 ${probe.error}` : '';\n lines.push(` ${icon} ${probe.strategy}${status}${err}`);\n }\n return lines.join('\\n');\n}\n","import { ExecutionLevel } from '../types/router.js';\nimport type { RoutingDecision, ExecutionRequest } from '../types/router.js';\nimport { getAdapter, getAdapterByDomain } from '../adapter/registry.js';\n\nexport function makeRoutingDecision(request: ExecutionRequest): RoutingDecision {\n // 1. Explicit adapter match\n if (request.site && request.command) {\n const adapter = getAdapter(request.site, request.command);\n if (adapter) {\n return {\n level: ExecutionLevel.ADAPTER,\n reason: `Matched adapter: ${request.site}/${request.command}`,\n adapter,\n };\n }\n }\n\n // 2. URL-based adapter match\n if (request.url) {\n try {\n const domain = new URL(request.url).hostname;\n const adapters = getAdapterByDomain(domain);\n if (adapters.length > 0) {\n return {\n level: ExecutionLevel.ADAPTER,\n reason: `Found adapter for domain: ${domain}`,\n adapter: adapters[0],\n };\n }\n } catch {}\n }\n\n // 3. Simple HTTP check — URL-only request with no interaction task\n if (request.url && !request.task) {\n return {\n level: ExecutionLevel.HTTP,\n reason: 'Direct URL fetch (no task specified)',\n };\n }\n\n // 4. Simple fetch detection — URL looks like an API\n if (request.url) {\n const url = request.url;\n if (url.endsWith('.json') || url.includes('/api/') || url.includes('/v1/') || url.includes('/v2/')) {\n return {\n level: ExecutionLevel.HTTP,\n reason: 'URL appears to be an API endpoint',\n };\n }\n }\n\n // 5. Task requires interaction — use agent\n if (request.task) {\n const taskLower = request.task.toLowerCase();\n const interactionWords = ['click', 'scroll', 'fill', 'type', 'login', 'sign in', 'search', 'navigate', 'find', 'extract', 'get'];\n const needsInteraction = interactionWords.some((w) => taskLower.includes(w));\n\n if (needsInteraction || request.url) {\n return {\n level: ExecutionLevel.AGENT,\n reason: 'Task requires web interaction',\n };\n }\n }\n\n // Default: agent for anything unrecognized\n return {\n level: ExecutionLevel.AGENT,\n reason: 'Defaulting to AI agent for unrecognized task',\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { IPage } from '../types/page.js';\nimport type {\n AgentConfig, AgentTool, ExecutionResult, HistoricalEvent,\n AgentStepEvent, ObservationEvent, AgentStatus,\n AgentEvent, AgentEventListener, AgentEventType,\n} from '../types/agent.js';\nimport { LLM } from '../llm/client.js';\nimport type { Message } from '../types/llm.js';\nimport { createDefaultTools } from './tools/index.js';\nimport { packMacroTool } from './macro-tool.js';\nimport { flatTreeToString } from '../browser/dom/flat-tree.js';\nimport { log } from '../utils/logger.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport class AgentCore {\n private page: IPage;\n private config: AgentConfig;\n private llm: LLM;\n private history: HistoricalEvent[] = [];\n private _status: AgentStatus = 'idle';\n private listeners = new Map<AgentEventType, Set<AgentEventListener>>();\n private previousElementHashes = new Set<string>();\n private totalWaitTime = 0;\n\n constructor(page: IPage, config: AgentConfig) {\n this.page = page;\n this.config = config;\n this.llm = new LLM(config.llm);\n }\n\n // ── Event system ──\n on(event: AgentEventType, listener: AgentEventListener): void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(listener);\n }\n\n off(event: AgentEventType, listener: AgentEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n private emit(event: AgentEvent): void {\n const listeners = this.listeners.get(event.type as AgentEventType);\n if (listeners) {\n for (const fn of listeners) {\n try { fn(event); } catch {}\n }\n }\n }\n\n get status(): AgentStatus { return this._status; }\n\n private setStatus(newStatus: AgentStatus): void {\n const prev = this._status;\n this._status = newStatus;\n this.emit({ type: 'statuschange', status: newStatus, previousStatus: prev });\n }\n\n private pushHistory(event: HistoricalEvent): void {\n this.history.push(event);\n this.emit({ type: 'historychange', history: this.history });\n }\n\n async execute(task: string, abortSignal?: AbortSignal): Promise<ExecutionResult> {\n this.setStatus('running');\n this.history = [];\n this.previousElementHashes.clear();\n this.totalWaitTime = 0;\n\n const maxSteps = this.config.maxSteps ?? 40;\n const stepDelay = this.config.stepDelay ?? 0.4;\n\n // Build tools\n const tools: Record<string, AgentTool> = {\n ...createDefaultTools(this.page),\n ...(this.config.customTools || {}),\n };\n for (const [name, tool] of Object.entries(tools)) {\n if (tool === null) delete tools[name];\n }\n\n const macroTool = packMacroTool(tools as Record<string, AgentTool>);\n\n // Load system prompt\n let systemPrompt: string;\n try {\n systemPrompt = readFileSync(join(__dirname, 'prompts', 'system.md'), 'utf-8');\n } catch {\n systemPrompt = 'You are an AI web agent that navigates web pages to complete tasks.';\n }\n\n if (this.config.instructions?.system) {\n systemPrompt += '\\n\\n' + this.config.instructions.system;\n }\n\n let lastURL = '';\n\n for (let step = 1; step <= maxSteps; step++) {\n if (abortSignal?.aborted) {\n this.setStatus('error');\n return { success: false, data: 'Aborted', history: this.history };\n }\n\n // ── Observe phase ──\n const browserState = await this.page.browserState().catch(() => ({\n url: '', title: '', viewportWidth: 0, viewportHeight: 0,\n pageWidth: 0, pageHeight: 0, scrollX: 0, scrollY: 0,\n scrollPercent: 0, pixelsAbove: 0, pixelsBelow: 0,\n }));\n\n const flatTree = await this.page.flatTree().catch(() => ({ rootId: '', map: {} }));\n const pageContent = flatTreeToString(flatTree);\n\n // ── New element tracking ──\n const currentHashes = new Set<string>();\n let newElementCount = 0;\n for (const node of Object.values(flatTree.map)) {\n if (node.isInteractive && node.highlightIndex !== undefined) {\n const hash = `${node.tagName}:${node.text || ''}:${JSON.stringify(node.attributes || {})}`;\n currentHashes.add(hash);\n if (!this.previousElementHashes.has(hash)) {\n newElementCount++;\n }\n }\n }\n this.previousElementHashes = currentHashes;\n\n // ── Build observations ──\n const observations: string[] = [];\n if (browserState.url !== lastURL && lastURL) {\n observations.push(`Navigated to ${browserState.url}`);\n }\n lastURL = browserState.url;\n\n if (newElementCount > 0 && step > 1) {\n observations.push(`${newElementCount} new interactive element(s) appeared`);\n }\n\n if (this.totalWaitTime > 3) {\n observations.push(`Total wait time: ${this.totalWaitTime.toFixed(1)}s — consider if page is still loading`);\n }\n\n if (step >= maxSteps - 5) {\n observations.push(`Warning: ${maxSteps - step} steps remaining`);\n }\n\n if (this.config.instructions?.getPageInstructions) {\n try {\n const pi = this.config.instructions.getPageInstructions(browserState.url);\n if (pi) observations.push(`Page instructions: ${pi}`);\n } catch {}\n }\n\n for (const obs of observations) {\n this.pushHistory({ type: 'observation', message: obs } as ObservationEvent);\n this.emit({ type: 'activity', kind: 'observation', message: obs, step });\n }\n\n // ── Assemble user prompt with browser state ──\n const userPrompt = assembleUserPrompt(\n task, pageContent, browserState, this.history, step, maxSteps,\n );\n\n // ── Think phase ──\n const messages: Message[] = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ];\n\n log.step(step, `Thinking... (${browserState.url})`);\n this.emit({ type: 'activity', kind: 'thinking', message: `Step ${step}: thinking`, step });\n\n if (this.config.onBeforeStep) await this.config.onBeforeStep(step);\n\n const startTime = Date.now();\n let result;\n try {\n result = await this.llm.invoke(messages, macroTool, abortSignal);\n } catch (err) {\n log.error(`LLM error at step ${step}: ${err}`);\n this.pushHistory({ type: 'error', error: String(err), step });\n this.emit({ type: 'activity', kind: 'error', message: String(err), step });\n continue;\n }\n const duration = Date.now() - startTime;\n\n // ── Act phase ──\n const args = result.toolCall.args;\n const action = (args.action || args) as Record<string, unknown>;\n const [actionName, actionInput] = Object.entries(action)[0] || ['unknown', {}];\n\n this.emit({ type: 'activity', kind: 'executing', message: actionName, step });\n\n // Track wait time\n if (actionName === 'wait') {\n const secs = (actionInput as any)?.seconds || 0;\n this.totalWaitTime += secs;\n }\n\n const stepEvent: AgentStepEvent = {\n type: 'step',\n step,\n reflection: {\n evaluation_previous_goal: (args.evaluation_previous_goal as string) || '',\n memory: (args.memory as string) || '',\n next_goal: (args.next_goal as string) || '',\n },\n action: { name: actionName, args: actionInput as Record<string, unknown> },\n output: result.toolResult,\n duration,\n };\n this.pushHistory(stepEvent);\n\n log.step(step, `Action: ${actionName} → ${result.toolResult.slice(0, 100)}`);\n this.emit({ type: 'activity', kind: 'executed', message: `${actionName}: ${result.toolResult.slice(0, 80)}`, step, duration });\n\n if (this.config.onAfterStep) await this.config.onAfterStep(this.history);\n\n // Check for done\n if (actionName === 'done') {\n try {\n const doneResult = JSON.parse(result.toolResult);\n this.setStatus('completed');\n return { success: doneResult.success, data: doneResult.text || result.toolResult, history: this.history };\n } catch {\n this.setStatus('completed');\n return { success: true, data: result.toolResult, history: this.history };\n }\n }\n\n if (stepDelay > 0) {\n await new Promise((r) => setTimeout(r, stepDelay * 1000));\n }\n }\n\n this.setStatus('error');\n return { success: false, data: `Reached maximum steps (${maxSteps})`, history: this.history };\n }\n}\n\nfunction assembleUserPrompt(\n task: string,\n pageContent: string,\n state: { url: string; title: string; viewportWidth: number; viewportHeight: number; pageHeight: number; scrollPercent: number; pixelsAbove: number; pixelsBelow: number },\n history: HistoricalEvent[],\n step: number,\n maxSteps: number,\n): string {\n let prompt = `# Task\\n${task}\\n\\n`;\n\n // Browser state header\n prompt += `# Current Page\\n`;\n prompt += `URL: ${state.url}\\n`;\n prompt += `Title: ${state.title}\\n`;\n prompt += `Viewport: ${state.viewportWidth}x${state.viewportHeight} | Page height: ${state.pageHeight}px\\n`;\n prompt += `Scroll: ${state.scrollPercent}%`;\n if (state.pixelsAbove > 50) prompt += ` | ${state.pixelsAbove}px above`;\n if (state.pixelsBelow > 50) prompt += ` | ${state.pixelsBelow}px below`;\n prompt += `\\nStep: ${step}/${maxSteps}\\n\\n`;\n\n prompt += `# Browser State\\n${pageContent}\\n\\n`;\n\n if (history.length > 0) {\n prompt += `# History\\n`;\n const recent = history.slice(-10);\n for (const event of recent) {\n if (event.type === 'step') {\n const s = event as AgentStepEvent;\n prompt += `<step_${s.step}>\\n`;\n if (s.reflection) {\n prompt += ` eval: ${s.reflection.evaluation_previous_goal}\\n`;\n prompt += ` memory: ${s.reflection.memory}\\n`;\n prompt += ` goal: ${s.reflection.next_goal}\\n`;\n }\n prompt += ` action: ${s.action.name}(${JSON.stringify(s.action.args)})\\n`;\n prompt += ` result: ${s.output.slice(0, 200)}\\n`;\n prompt += `</step_${s.step}>\\n`;\n } else if (event.type === 'observation') {\n prompt += `<sys>${(event as ObservationEvent).message}</sys>\\n`;\n }\n }\n }\n\n return prompt;\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createClickTool(page: IPage): AgentTool {\n return {\n description: 'Click on an interactive element by its index number from the page content.',\n inputSchema: z.object({\n index: z.number().describe('The index of the element to click'),\n }),\n execute: async (args) => {\n await page.click(args.index);\n return `Clicked element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createTypeTool(page: IPage): AgentTool {\n return {\n description: 'Type text into an input field identified by its index number.',\n inputSchema: z.object({\n index: z.number().describe('The index of the input element'),\n text: z.string().describe('The text to type'),\n }),\n execute: async (args) => {\n await page.typeText(args.index, args.text);\n return `Typed \"${args.text}\" into element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createScrollTool(page: IPage): AgentTool {\n return {\n description: 'Scroll the page in a given direction. Use to reveal more content.',\n inputSchema: z.object({\n direction: z.enum(['up', 'down', 'left', 'right']).describe('Scroll direction'),\n amount: z.number().optional().describe('Pixels to scroll (default 500)'),\n }),\n execute: async (args) => {\n await page.scroll(args.direction, args.amount);\n return `Scrolled ${args.direction}${args.amount ? ` ${args.amount}px` : ''}`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createSelectTool(page: IPage): AgentTool {\n return {\n description: 'Select an option from a dropdown/select element by its index.',\n inputSchema: z.object({\n index: z.number().describe('The index of the select element'),\n value: z.string().describe('The option text or value to select'),\n }),\n execute: async (args) => {\n await page.selectOption(args.index, args.value);\n return `Selected \"${args.value}\" in element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\n\nexport function createWaitTool(): AgentTool {\n return {\n description: 'Wait for a specified number of seconds before continuing.',\n inputSchema: z.object({\n seconds: z.number().min(0.1).max(30).describe('Seconds to wait'),\n }),\n execute: async (args) => {\n await new Promise((r) => setTimeout(r, args.seconds * 1000));\n return `Waited ${args.seconds} seconds`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\n\nexport function createDoneTool(): AgentTool {\n return {\n description: 'Signal that the task is complete. Call this when you have finished the task or cannot proceed further.',\n inputSchema: z.object({\n success: z.boolean().describe('Whether the task was completed successfully'),\n text: z.string().describe('Summary of the result or explanation of failure'),\n }),\n execute: async (args) => {\n return JSON.stringify({ done: true, success: args.success, text: args.text });\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport { createInterface } from 'node:readline';\n\nexport function createAskUserTool(): AgentTool {\n return {\n description: 'Ask the user a question when you need clarification or input to proceed.',\n inputSchema: z.object({\n question: z.string().describe('The question to ask the user'),\n }),\n execute: async (args) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise<string>((resolve) => {\n rl.question(`\\n🤖 Agent asks: ${args.question}\\n> `, (answer) => {\n rl.close();\n resolve(`User answered: ${answer}`);\n });\n });\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createExecuteJsTool(page: IPage): AgentTool {\n return {\n description: 'Execute JavaScript code on the current page. Returns the result.',\n inputSchema: z.object({\n code: z.string().describe('JavaScript code to execute on the page'),\n }),\n execute: async (args) => {\n const result = await page.evaluate(args.code);\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n },\n };\n}\n","import type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\nimport { createClickTool } from './click.js';\nimport { createTypeTool } from './type.js';\nimport { createScrollTool } from './scroll.js';\nimport { createSelectTool } from './select.js';\nimport { createWaitTool } from './wait.js';\nimport { createDoneTool } from './done.js';\nimport { createAskUserTool } from './ask-user.js';\nimport { createExecuteJsTool } from './execute-js.js';\n\nexport function createDefaultTools(page: IPage): Record<string, AgentTool> {\n return {\n click_element_by_index: createClickTool(page),\n input_text: createTypeTool(page),\n scroll: createScrollTool(page),\n select_dropdown_option: createSelectTool(page),\n wait: createWaitTool(),\n done: createDoneTool(),\n ask_user: createAskUserTool(),\n execute_javascript: createExecuteJsTool(page),\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../types/agent.js';\nimport type { MacroTool } from '../llm/client.js';\nimport { normalizeResponse } from './auto-fixer.js';\n\nexport function packMacroTool(\n tools: Record<string, AgentTool>\n): MacroTool {\n // Build the action union schema\n const actionSchemas: z.ZodTypeAny[] = [];\n const toolNames: string[] = [];\n\n for (const [name, tool] of Object.entries(tools)) {\n toolNames.push(name);\n actionSchemas.push(\n z.object({ [name]: tool.inputSchema }).describe(tool.description)\n );\n }\n\n const actionSchema = actionSchemas.length === 1\n ? actionSchemas[0]\n : z.union(actionSchemas as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]);\n\n const macroSchema = z.object({\n evaluation_previous_goal: z.string().optional().describe('Evaluate whether the previous goal was achieved'),\n memory: z.string().optional().describe('Important information to remember for future steps'),\n next_goal: z.string().optional().describe('The next immediate goal to achieve'),\n action: actionSchema.describe('The action to take'),\n });\n\n return {\n name: 'AgentOutput',\n description: 'The agent\\'s output containing reflection and action. Must be called every step.',\n schema: macroSchema,\n execute: async (args: Record<string, unknown>) => {\n // Normalize messy LLM output\n const normalized = normalizeResponse(args, 'AgentOutput', toolNames, tools);\n const action = normalized.action as Record<string, unknown>;\n\n // Find the tool to execute\n const [toolName, toolInput] = Object.entries(action)[0];\n const tool = tools[toolName];\n\n if (!tool) {\n return `Error: Unknown tool \"${toolName}\". Available: ${toolNames.join(', ')}`;\n }\n\n try {\n const result = await tool.execute(toolInput as any);\n return result;\n } catch (err) {\n return `Error executing ${toolName}: ${err}`;\n }\n },\n };\n}\n","import type { z } from 'zod';\nimport type { AgentTool } from '../types/agent.js';\n\n/**\n * Normalize messy LLM responses into valid MacroTool output.\n * Uses tool schemas for validation instead of hardcoded tool names.\n */\nexport function normalizeResponse(\n raw: Record<string, unknown>,\n toolName: string,\n availableActions: string[],\n toolSchemas?: Record<string, AgentTool>,\n): Record<string, unknown> {\n let result = { ...raw };\n\n // Fix 1: Nested function wrapper — unwrap {type: 'function', function: {arguments}}\n if (result.type === 'function' && result.function) {\n const fn = result.function as Record<string, unknown>;\n if (typeof fn.arguments === 'string') {\n try { result = JSON.parse(fn.arguments); } catch {}\n } else if (typeof fn.arguments === 'object') {\n result = fn.arguments as Record<string, unknown>;\n }\n }\n\n // Fix 2: Double-stringified arguments\n for (const [key, value] of Object.entries(result)) {\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === 'object' && parsed !== null) {\n result[key] = parsed;\n }\n } catch {}\n }\n }\n\n // Fix 3: If no action field, try to infer one\n if (!result.action) {\n for (const actionName of availableActions) {\n if (actionName in result) {\n result = {\n ...result,\n action: { [actionName]: result[actionName] },\n };\n delete result[actionName];\n break;\n }\n }\n }\n\n // Fix 4: Still no action — fallback to wait\n if (!result.action) {\n result.action = { wait: { seconds: 1 } };\n }\n\n // Fix 5: Action is a string instead of object\n if (typeof result.action === 'string') {\n if (availableActions.includes(result.action)) {\n result.action = { [result.action]: {} };\n } else {\n result.action = { wait: { seconds: 1 } };\n }\n }\n\n // Fix 6: Schema-based validation & primitive coercion\n const action = result.action as Record<string, unknown>;\n for (const [name, input] of Object.entries(action)) {\n if (typeof input !== 'object' || input === null) {\n // Use schema to determine expected shape\n if (toolSchemas && toolSchemas[name]) {\n const schema = toolSchemas[name].inputSchema;\n const coerced = coercePrimitiveToSchema(input, schema);\n if (coerced !== null) {\n action[name] = coerced;\n continue;\n }\n }\n\n // Fallback: hardcoded coercion for known patterns\n if (typeof input === 'number') {\n action[name] = { index: input };\n } else if (typeof input === 'string') {\n action[name] = { text: input };\n } else {\n action[name] = {};\n }\n }\n\n // Fix 7: Validate action args against schema if available\n if (toolSchemas && toolSchemas[name] && typeof action[name] === 'object') {\n const schema = toolSchemas[name].inputSchema;\n const validation = schema.safeParse(action[name]);\n if (!validation.success) {\n // Try to fix common issues: wrong field names, missing required fields\n const fixed = attemptSchemaFix(action[name] as Record<string, unknown>, schema, validation.error);\n if (fixed) {\n action[name] = fixed;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Coerce a primitive value into an object matching a Zod schema.\n * Inspects the schema to find a single required field and wraps the value.\n */\nfunction coercePrimitiveToSchema(value: unknown, schema: z.ZodType): Record<string, unknown> | null {\n try {\n const def = (schema as any)._def;\n if (def?.typeName !== 'ZodObject') return null;\n\n const shape = def.shape();\n const keys = Object.keys(shape);\n\n // Single required field — wrap the primitive\n const requiredKeys = keys.filter((k) => {\n const fieldDef = (shape[k] as any)?._def;\n return fieldDef?.typeName !== 'ZodOptional';\n });\n\n if (requiredKeys.length === 1) {\n return { [requiredKeys[0]]: value };\n }\n\n // Multiple fields but value is a number — likely an index field\n const indexField = keys.find((k) => /index|idx|num|number/i.test(k));\n if (indexField && typeof value === 'number') {\n return { [indexField]: value };\n }\n\n // Value is a string — likely a text field\n const textField = keys.find((k) => /text|value|query|code|question|url/i.test(k));\n if (textField && typeof value === 'string') {\n return { [textField]: value };\n }\n } catch {}\n\n return null;\n}\n\n/**\n * Attempt to fix validation errors by mapping common mistakes.\n */\nfunction attemptSchemaFix(\n input: Record<string, unknown>,\n schema: z.ZodType,\n error: z.ZodError,\n): Record<string, unknown> | null {\n try {\n const def = (schema as any)._def;\n if (def?.typeName !== 'ZodObject') return null;\n\n const shape = def.shape();\n const expectedKeys = Object.keys(shape);\n const inputKeys = Object.keys(input);\n const fixed = { ...input };\n\n // Fix: wrong key names — try to map by position or type match\n for (const issue of error.issues) {\n if (issue.code === 'invalid_type' && issue.path.length === 1) {\n const key = String(issue.path[0]);\n const val = input[key];\n // Try type coercion\n if (issue.expected === 'number' && typeof val === 'string') {\n const num = Number(val);\n if (!isNaN(num)) fixed[key] = num;\n } else if (issue.expected === 'string' && typeof val === 'number') {\n fixed[key] = String(val);\n } else if (issue.expected === 'boolean' && typeof val === 'string') {\n fixed[key] = val === 'true';\n }\n }\n\n if (issue.code === 'unrecognized_keys') {\n // Remove unrecognized keys\n for (const k of (issue as any).keys || []) {\n delete fixed[k];\n }\n }\n }\n\n // Re-validate\n const result = schema.safeParse(fixed);\n if (result.success) return fixed;\n } catch {}\n\n return null;\n}\n\nexport function safeJsonParse(str: string): unknown {\n try {\n return JSON.parse(str);\n } catch {\n return str;\n }\n}\n\nexport function extractJsonFromString(str: string): unknown | null {\n const start = str.indexOf('{');\n const end = str.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) return null;\n try {\n return JSON.parse(str.slice(start, end + 1));\n } catch {\n return null;\n }\n}\n","/**\n * Domain Guard — restrict which websites LobsterCLI can operate on.\n *\n * Three modes:\n * - No config: works on all websites (default)\n * - allowDomains: whitelist — ONLY these sites work\n * - blockDomains: blacklist — everything EXCEPT these sites works\n *\n * Usage (library):\n * import { DomainGuard } from 'lobster-cli'\n * const guard = new DomainGuard({ allowDomains: ['bloomberg.com', 'yahoo.com'] })\n * guard.check('https://bloomberg.com/markets') // → ok\n * guard.check('https://reddit.com') // → throws\n *\n * Usage (config):\n * lobster config set domains.allow \"bloomberg.com,yahoo.com\"\n * lobster config set domains.blockMessage \"This tool only works on finance sites.\"\n */\n\nexport interface DomainGuardConfig {\n /** Whitelist — only these domains are allowed. Empty = allow all. */\n allowDomains?: string[];\n /** Blacklist — these domains are blocked. Ignored if allowDomains is set. */\n blockDomains?: string[];\n /** Custom message shown when a domain is blocked. */\n blockMessage?: string;\n /** Allow subdomains to match (e.g., \"yahoo.com\" matches \"finance.yahoo.com\"). Default: true */\n matchSubdomains?: boolean;\n}\n\nconst DEFAULT_BLOCK_MESSAGE = 'This domain is not allowed by the current configuration.';\n\nexport class DomainGuard {\n private allow: string[];\n private block: string[];\n private message: string;\n private matchSubs: boolean;\n\n constructor(config: DomainGuardConfig = {}) {\n this.allow = (config.allowDomains || []).map(d => d.toLowerCase().replace(/^www\\./, ''));\n this.block = (config.blockDomains || []).map(d => d.toLowerCase().replace(/^www\\./, ''));\n this.message = config.blockMessage || DEFAULT_BLOCK_MESSAGE;\n this.matchSubs = config.matchSubdomains ?? true;\n }\n\n /**\n * Check if a URL is allowed. Returns true if allowed, throws if blocked.\n */\n check(url: string): true {\n // No restrictions configured — allow everything\n if (this.allow.length === 0 && this.block.length === 0) return true;\n\n const domain = this.extractDomain(url);\n if (!domain) return true; // Can't parse = allow (for local files, etc.)\n\n // Whitelist mode: only allowed domains pass\n if (this.allow.length > 0) {\n if (!this.matches(domain, this.allow)) {\n throw new DomainBlockedError(domain, this.message);\n }\n return true;\n }\n\n // Blacklist mode: blocked domains fail\n if (this.block.length > 0) {\n if (this.matches(domain, this.block)) {\n throw new DomainBlockedError(domain, this.message);\n }\n return true;\n }\n\n return true;\n }\n\n /**\n * Check without throwing — returns { allowed, domain, message }.\n */\n test(url: string): { allowed: boolean; domain: string; message?: string } {\n const domain = this.extractDomain(url);\n if (!domain) return { allowed: true, domain: '' };\n\n try {\n this.check(url);\n return { allowed: true, domain };\n } catch (err) {\n if (err instanceof DomainBlockedError) {\n return { allowed: false, domain, message: err.message };\n }\n return { allowed: true, domain };\n }\n }\n\n /**\n * Check if domain matches any pattern in the list.\n */\n private matches(domain: string, patterns: string[]): boolean {\n for (const pattern of patterns) {\n if (domain === pattern) return true;\n if (this.matchSubs && domain.endsWith('.' + pattern)) return true;\n }\n return false;\n }\n\n /**\n * Extract domain from URL, stripping www. prefix.\n */\n private extractDomain(url: string): string {\n try {\n const parsed = new URL(url.startsWith('http') ? url : 'https://' + url);\n return parsed.hostname.toLowerCase().replace(/^www\\./, '');\n } catch {\n return '';\n }\n }\n\n /**\n * Whether any restrictions are active.\n */\n get isRestricted(): boolean {\n return this.allow.length > 0 || this.block.length > 0;\n }\n\n /**\n * Get list of allowed domains (empty = all allowed).\n */\n get allowedDomains(): string[] {\n return [...this.allow];\n }\n\n /**\n * Get list of blocked domains.\n */\n get blockedDomains(): string[] {\n return [...this.block];\n }\n}\n\nexport class DomainBlockedError extends Error {\n public readonly domain: string;\n\n constructor(domain: string, message: string) {\n super(message);\n this.name = 'DomainBlockedError';\n this.domain = domain;\n }\n}\n","import Table from 'cli-table3';\n\nexport function renderTable(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const table = new Table({\n head: cols,\n style: { head: ['cyan'] },\n wordWrap: true,\n });\n\n for (const row of data) {\n table.push(cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val);\n }));\n }\n\n return table.toString();\n}\n","export function renderJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n","export function renderMarkdown(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [];\n\n lines.push('| ' + cols.join(' | ') + ' |');\n lines.push('| ' + cols.map(() => '---').join(' | ') + ' |');\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val).replace(/\\|/g, '\\\\|');\n });\n lines.push('| ' + vals.join(' | ') + ' |');\n }\n\n return lines.join('\\n');\n}\n","export function renderCsv(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [cols.join(',')];\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n const str = String(val);\n return str.includes(',') || str.includes('\"') || str.includes('\\n')\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n });\n lines.push(vals.join(','));\n }\n\n return lines.join('\\n');\n}\n","import yaml from 'js-yaml';\n\nexport function renderYaml(data: unknown): string {\n return yaml.dump(data, { indent: 2, lineWidth: 120 });\n}\n","import type { OutputFormat } from '../types/router.js';\nimport { renderTable } from './table.js';\nimport { renderJson } from './json.js';\nimport { renderMarkdown } from './markdown.js';\nimport { renderCsv } from './csv.js';\nimport { renderYaml } from './yaml.js';\n\nexport function render(data: unknown, format: OutputFormat, columns?: string[]): string {\n switch (format) {\n case 'table': return renderTable(data, columns);\n case 'json': return renderJson(data);\n case 'markdown': return renderMarkdown(data, columns);\n case 'csv': return renderCsv(data, columns);\n case 'yaml': return renderYaml(data);\n default: return renderJson(data);\n }\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC1BxB,IAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6JhC,SAAS,2BAA2B,cAAsB,KAAa;AAC5E,SAAO,wBAAwB,QAAQ,6BAA6B,wBAAwB,WAAW,GAAG;AAC5G;;;AC9JO,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACE7B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["args","result","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","el","nodes","Strategy","writeFileSync","mkdirSync","existsSync","join","existsSync","mkdirSync","writeFileSync","join","yaml","readFileSync","join","z","z","z","z","z","z","z","z","z","z","readFileSync","join","yaml"]}
1
+ {"version":3,"sources":["../src/browser/pdf.ts","../src/brain/index.ts","../src/llm/errors.ts","../src/llm/openai-client.ts","../src/llm/utils.ts","../src/llm/client.ts","../src/browser/manager.ts","../src/utils/logger.ts","../src/browser/profiles.ts","../src/config/index.ts","../src/config/schema.ts","../src/browser/chrome-attach.ts","../src/browser/stealth.ts","../src/browser/dom/flat-tree.ts","../src/browser/dom/snapshot.ts","../src/browser/dom/compact-snapshot.ts","../src/browser/dom/semantic-tree.ts","../src/browser/dom/markdown.ts","../src/browser/dom/form-state.ts","../src/browser/dom/interactive.ts","../src/browser/interceptor.ts","../src/browser/semantic-find.ts","../src/browser/page-adapter.ts","../src/browser/lightpanda.ts","../src/pipeline/registry.ts","../src/pipeline/executor.ts","../src/pipeline/template.ts","../src/types/adapter.ts","../src/adapter/registry.ts","../src/discover/explore.ts","../src/discover/synthesize.ts","../src/cascade/index.ts","../src/router/decision.ts","../src/agent/core.ts","../src/agent/tools/click.ts","../src/agent/tools/type.ts","../src/agent/tools/scroll.ts","../src/agent/tools/select.ts","../src/agent/tools/wait.ts","../src/agent/tools/done.ts","../src/agent/tools/ask-user.ts","../src/agent/tools/execute-js.ts","../src/agent/tools/index.ts","../src/agent/macro-tool.ts","../src/agent/auto-fixer.ts","../src/domain-guard.ts","../src/output/table.ts","../src/output/json.ts","../src/output/markdown.ts","../src/output/csv.ts","../src/output/yaml.ts","../src/output/index.ts"],"sourcesContent":["/**\n * PDF extraction module — downloads and converts PDFs to structured text/markdown.\n *\n * Works for both CLI and extension:\n * - CLI: lobster fetch https://arxiv.org/pdf/2602.16800\n * - Extension: detects PDF URL, extracts text before sending to LLM\n *\n * Handles:\n * - Remote PDFs (HTTP/HTTPS URLs)\n * - Local PDF files (file paths)\n * - All pages (no page limit)\n * - Text extraction with page boundaries\n * - Markdown conversion (headings, paragraphs, lists)\n * - Metadata extraction (title, author, pages, creation date)\n */\n\nimport { readFileSync } from 'node:fs';\n\n// Dynamic import for pdf-parse (CommonJS module)\nlet pdfParseFn: ((buffer: Buffer) => Promise<{\n numpages: number;\n numrender: number;\n info: Record<string, unknown>;\n metadata: unknown;\n text: string;\n version: string;\n}>) | null = null;\n\nasync function getPdfParser() {\n if (!pdfParseFn) {\n const mod = await import('pdf-parse');\n const PDFParseClass = (mod as any).PDFParse;\n if (PDFParseClass && typeof PDFParseClass === 'function') {\n // It's a class — wrap it so caller can use it as a function\n pdfParseFn = async (buffer: Buffer) => {\n const parser = new PDFParseClass(buffer);\n return parser.parse ? await parser.parse() : parser;\n };\n } else {\n pdfParseFn = (mod as any).default || mod;\n }\n }\n return pdfParseFn!;\n}\n\nexport interface PdfMetadata {\n title: string;\n author: string;\n pages: number;\n creator: string;\n producer: string;\n creationDate: string;\n}\n\nexport interface PdfExtractResult {\n metadata: PdfMetadata;\n text: string;\n markdown: string;\n pages: string[];\n wordCount: number;\n charCount: number;\n}\n\n/**\n * Detect if a URL or path points to a PDF.\n */\nexport function isPdfUrl(urlOrPath: string): boolean {\n const lower = urlOrPath.toLowerCase();\n\n // Direct .pdf extension\n if (lower.endsWith('.pdf')) return true;\n\n // Common PDF URL patterns\n if (/\\/pdf\\//.test(lower)) return true;\n\n // arXiv pattern: /abs/ can have PDF link, /pdf/ is always PDF\n if (/arxiv\\.org\\/pdf\\//.test(lower)) return true;\n\n // Content-disposition or query params\n if (/[?&]format=pdf/i.test(lower)) return true;\n if (/[?&]type=pdf/i.test(lower)) return true;\n\n return false;\n}\n\n/**\n * Detect PDF from HTTP response headers.\n */\nexport function isPdfResponse(contentType: string): boolean {\n return contentType.includes('application/pdf');\n}\n\n/**\n * Download a PDF from a URL and return the buffer.\n */\nasync function downloadPdf(url: string): Promise<Buffer> {\n const response = await fetch(url, {\n headers: {\n 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Accept': 'application/pdf,*/*',\n },\n redirect: 'follow',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to download PDF: ${response.status} ${response.statusText}`);\n }\n\n // Verify it's actually a PDF\n const contentType = response.headers.get('content-type') || '';\n if (!contentType.includes('pdf') && !isPdfUrl(url)) {\n // Might still be a PDF — check magic bytes after download\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n}\n\n/**\n * Read a local PDF file.\n */\nfunction readLocalPdf(filePath: string): Buffer {\n return readFileSync(filePath);\n}\n\n/**\n * Convert raw extracted text into clean Markdown.\n *\n * Strategy:\n * 1. Split into lines\n * 2. Detect headings (short lines, all caps, or numbered sections)\n * 3. Detect lists (lines starting with -, •, *, numbered)\n * 4. Detect references section\n * 5. Merge paragraph lines\n * 6. Clean up whitespace\n */\nfunction textToMarkdown(text: string, metadata: PdfMetadata): string {\n const lines = text.split('\\n');\n const mdLines: string[] = [];\n\n // Add title\n if (metadata.title && metadata.title !== 'untitled') {\n mdLines.push(`# ${metadata.title}`);\n mdLines.push('');\n if (metadata.author) {\n mdLines.push(`**Authors:** ${metadata.author}`);\n mdLines.push('');\n }\n mdLines.push('---');\n mdLines.push('');\n }\n\n let inReferences = false;\n let prevWasBlank = false;\n let paragraphBuffer: string[] = [];\n\n function flushParagraph() {\n if (paragraphBuffer.length > 0) {\n mdLines.push(paragraphBuffer.join(' '));\n mdLines.push('');\n paragraphBuffer = [];\n }\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n // Skip empty lines\n if (!line) {\n if (!prevWasBlank) {\n flushParagraph();\n }\n prevWasBlank = true;\n continue;\n }\n prevWasBlank = false;\n\n // Detect section headings\n // Pattern 1: Numbered sections like \"1. Introduction\", \"2.1 Methods\"\n const numberedHeading = line.match(/^(\\d+\\.?\\d*\\.?\\d*)\\s+([A-Z][A-Za-z\\s:&-]+)$/);\n if (numberedHeading && line.length < 80) {\n flushParagraph();\n const depth = numberedHeading[1].split('.').filter(Boolean).length;\n const prefix = depth <= 1 ? '##' : depth === 2 ? '###' : '####';\n mdLines.push(`${prefix} ${line}`);\n mdLines.push('');\n continue;\n }\n\n // Pattern 2: ALL CAPS headings\n if (line === line.toUpperCase() && line.length > 3 && line.length < 60 && /^[A-Z\\s:&-]+$/.test(line)) {\n flushParagraph();\n mdLines.push(`## ${line.charAt(0) + line.slice(1).toLowerCase()}`);\n mdLines.push('');\n continue;\n }\n\n // Pattern 3: \"Abstract\" or other known headings\n const knownHeadings = /^(Abstract|Introduction|Conclusion|Discussion|Results|Methods|Methodology|Background|Related Work|Acknowledgments|Acknowledgements|References|Bibliography|Appendix)/i;\n if (knownHeadings.test(line) && line.length < 40) {\n flushParagraph();\n if (/^(References|Bibliography)/i.test(line)) {\n inReferences = true;\n }\n mdLines.push(`## ${line}`);\n mdLines.push('');\n continue;\n }\n\n // Detect list items\n if (/^[-•∙◦▪]/.test(line)) {\n flushParagraph();\n mdLines.push(`- ${line.replace(/^[-•∙◦▪]\\s*/, '')}`);\n continue;\n }\n\n // Detect numbered list items (but not section headings)\n if (/^\\(\\d+\\)|^[a-z]\\)/.test(line)) {\n flushParagraph();\n mdLines.push(`- ${line}`);\n continue;\n }\n\n // References section — format each reference\n if (inReferences && /^\\[?\\d+\\]?\\.?\\s/.test(line)) {\n flushParagraph();\n mdLines.push(`- ${line}`);\n continue;\n }\n\n // Regular text — add to paragraph buffer\n // If line ends with hyphen (word break), join without space\n if (line.endsWith('-') && i + 1 < lines.length) {\n paragraphBuffer.push(line.slice(0, -1));\n } else {\n paragraphBuffer.push(line);\n }\n }\n\n flushParagraph();\n\n return mdLines.join('\\n').replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Extract text and metadata from a PDF buffer.\n */\nasync function extractFromBuffer(buffer: Buffer): Promise<PdfExtractResult> {\n const parse = await getPdfParser();\n const result = await parse(buffer);\n\n const info = result.info || {};\n\n const metadata: PdfMetadata = {\n title: (info.Title as string) || 'untitled',\n author: (info.Author as string) || '',\n pages: result.numpages,\n creator: (info.Creator as string) || '',\n producer: (info.Producer as string) || '',\n creationDate: (info.CreationDate as string) || '',\n };\n\n const text = result.text || '';\n\n // Split by page markers if available, otherwise split evenly\n // pdf-parse separates pages with form-feed or double newlines\n const pageTexts = text.split(/\\f/).filter(Boolean);\n const pages = pageTexts.length === result.numpages\n ? pageTexts\n : [text]; // Couldn't split by pages reliably\n\n const markdown = textToMarkdown(text, metadata);\n\n const words = text.split(/\\s+/).filter(Boolean);\n\n return {\n metadata,\n text,\n markdown,\n pages: pages.map(p => p.trim()),\n wordCount: words.length,\n charCount: text.length,\n };\n}\n\n/**\n * Main entry point — extract from URL or file path.\n */\nexport async function extractPdf(urlOrPath: string): Promise<PdfExtractResult> {\n let buffer: Buffer;\n\n if (urlOrPath.startsWith('http://') || urlOrPath.startsWith('https://')) {\n buffer = await downloadPdf(urlOrPath);\n } else {\n buffer = readLocalPdf(urlOrPath);\n }\n\n // Verify PDF magic bytes\n if (buffer[0] !== 0x25 || buffer[1] !== 0x50 || buffer[2] !== 0x44 || buffer[3] !== 0x46) {\n throw new Error('Not a valid PDF file (invalid magic bytes)');\n }\n\n return extractFromBuffer(buffer);\n}\n\n/**\n * Quick check + extract — for use in fetch command.\n * Returns null if not a PDF, or the extract result if it is.\n */\nexport async function tryExtractPdf(url: string): Promise<PdfExtractResult | null> {\n // First check URL pattern\n if (isPdfUrl(url)) {\n return extractPdf(url);\n }\n\n // If URL doesn't look like PDF, do a HEAD request to check content-type\n try {\n const head = await fetch(url, { method: 'HEAD', redirect: 'follow' });\n const contentType = head.headers.get('content-type') || '';\n if (isPdfResponse(contentType)) {\n return extractPdf(url);\n }\n } catch {\n // HEAD failed, not a PDF\n }\n\n return null;\n}\n","/**\n * Brain — Intent classifier for LobsterCLI.\n *\n * Analyzes a user's question and decides what data sources are needed\n * to answer it. Uses a cheap/fast LLM call for classification,\n * with heuristic fallback when no LLM is available.\n *\n * Works in both CLI and extension contexts.\n */\n\nexport interface BrainDecision {\n /** Needs to SEE the page (images, layout, colors, visual content) */\n screenshot: boolean;\n /** Needs page text content (articles, paragraphs, written content) */\n markdown: boolean;\n /** Asking about forms, inputs, fields */\n forms: boolean;\n /** Asking about API calls, network requests */\n network: boolean;\n /** Brief description of what the user wants */\n intent: string;\n /** How the decision was made */\n source: 'llm' | 'heuristic';\n}\n\nconst CLASSIFIER_PROMPT = `You are an intent classifier for a web automation tool. Given a user's question about a webpage, decide what data sources are needed to answer it.\n\nRespond ONLY with a JSON object:\n{\n \"screenshot\": true/false,\n \"markdown\": true/false,\n \"forms\": true/false,\n \"network\": true/false,\n \"intent\": \"brief 5-word description\"\n}\n\nRules:\n- screenshot=true ONLY when the answer requires SEEING the page (images, visual layout, colors, charts, what something looks like)\n- markdown=true for ANY question about text content, meaning, topics, summaries\n- forms=true ONLY when specifically asking about form fields or inputs\n- network=true ONLY when asking about APIs, requests, or data fetching\n- Most questions need only markdown=true`;\n\n/**\n * Classify intent using LLM (requires a callable LLM function)\n */\nexport async function classifyIntent(\n prompt: string,\n pageTitle: string,\n llmCall?: (systemPrompt: string, userPrompt: string) => Promise<string>,\n): Promise<BrainDecision> {\n // If we have an LLM function, use it\n if (llmCall) {\n try {\n const systemPrompt = CLASSIFIER_PROMPT + `\\nCurrent page: \"${pageTitle}\"`;\n const response = await llmCall(systemPrompt, prompt);\n\n const jsonMatch = response.match(/\\{[\\s\\S]*?\\}/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n screenshot: !!parsed.screenshot,\n markdown: parsed.markdown !== false,\n forms: !!parsed.forms,\n network: !!parsed.network,\n intent: parsed.intent || '',\n source: 'llm',\n };\n }\n } catch {\n // Fall through to heuristic\n }\n }\n\n return heuristicClassify(prompt);\n}\n\n/**\n * Heuristic classification — no LLM needed, instant, free.\n */\nexport function heuristicClassify(prompt: string): BrainDecision {\n const lower = prompt.toLowerCase();\n\n const screenshot = /look|see|visual|image|screenshot|screen|what('s| is) (on|showing|displayed|visible)|describe.*layout|picture|colour|color|design|ui |logo|icon|chart|graph|photo|video|banner|appear/i.test(lower);\n\n const forms = /form|input|field|submit|login|sign.?in|password|checkbox|dropdown|select|textarea|search.?box|fill/i.test(lower);\n\n const network = /api|network|request|fetch|xhr|endpoint|call.*server|data.*load/i.test(lower);\n\n return {\n screenshot,\n markdown: true,\n forms,\n network,\n intent: 'heuristic classification',\n source: 'heuristic',\n };\n}\n","export enum InvokeErrorType {\n NETWORK_ERROR = 'NETWORK_ERROR',\n AUTH_ERROR = 'AUTH_ERROR',\n RATE_LIMIT = 'RATE_LIMIT',\n SERVER_ERROR = 'SERVER_ERROR',\n CONTEXT_LENGTH = 'CONTEXT_LENGTH',\n CONTENT_FILTER = 'CONTENT_FILTER',\n NO_TOOL_CALL = 'NO_TOOL_CALL',\n INVALID_TOOL_ARGS = 'INVALID_TOOL_ARGS',\n TOOL_EXECUTION_ERROR = 'TOOL_EXECUTION_ERROR',\n UNKNOWN = 'UNKNOWN',\n}\n\nexport class InvokeError extends Error {\n type: InvokeErrorType;\n retryable: boolean;\n rawError?: unknown;\n rawResponse?: unknown;\n\n constructor(type: InvokeErrorType, message: string, opts?: { retryable?: boolean; rawError?: unknown; rawResponse?: unknown }) {\n super(message);\n this.name = 'InvokeError';\n this.type = type;\n this.retryable = opts?.retryable ?? isRetryable(type);\n this.rawError = opts?.rawError;\n this.rawResponse = opts?.rawResponse;\n }\n}\n\nfunction isRetryable(type: InvokeErrorType): boolean {\n switch (type) {\n case InvokeErrorType.NETWORK_ERROR:\n case InvokeErrorType.RATE_LIMIT:\n case InvokeErrorType.SERVER_ERROR:\n case InvokeErrorType.NO_TOOL_CALL:\n case InvokeErrorType.INVALID_TOOL_ARGS:\n case InvokeErrorType.TOOL_EXECUTION_ERROR:\n case InvokeErrorType.UNKNOWN:\n return true;\n case InvokeErrorType.AUTH_ERROR:\n case InvokeErrorType.CONTEXT_LENGTH:\n case InvokeErrorType.CONTENT_FILTER:\n return false;\n }\n}\n","import type { Message, ToolCall } from '../types/llm.js';\nimport type { LLMTool } from '../types/llm.js';\nimport { InvokeError, InvokeErrorType } from './errors.js';\nimport type { LLMProvider } from '../config/schema.js';\n\nexport interface OpenAIClientConfig {\n baseURL: string;\n model: string;\n apiKey?: string;\n temperature?: number;\n provider?: LLMProvider;\n}\n\nexport class OpenAIClient {\n private config: OpenAIClientConfig;\n\n constructor(config: OpenAIClientConfig) {\n this.config = config;\n }\n\n /**\n * Build auth headers based on the provider.\n * - OpenAI/Gemini/Ollama: Bearer token\n * - Anthropic: x-api-key header + anthropic-version\n */\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (!this.config.apiKey) return headers;\n\n if (this.config.provider === 'anthropic') {\n headers['x-api-key'] = this.config.apiKey;\n headers['anthropic-version'] = '2023-06-01';\n } else {\n headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n }\n\n return headers;\n }\n\n /**\n * Build the request body based on provider.\n * Anthropic Messages API is different from OpenAI chat completions.\n */\n private buildBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n if (this.config.provider === 'anthropic') {\n return this.buildAnthropicBody(messages, tools, opts);\n }\n\n // OpenAI-compatible format (OpenAI, Gemini, Ollama all use this)\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (tools && tools.length > 0) {\n body.tools = tools;\n body.parallel_tool_calls = false;\n if (opts?.toolChoice) {\n body.tool_choice = typeof opts.toolChoice === 'string'\n ? opts.toolChoice\n : opts.toolChoice;\n }\n }\n\n return { url: `${this.config.baseURL}/chat/completions`, body };\n }\n\n /**\n * Build Anthropic Messages API request.\n * Converts OpenAI-style messages/tools to Anthropic format.\n */\n private buildAnthropicBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n // Extract system message\n let system: string | undefined;\n const anthropicMessages: Record<string, unknown>[] = [];\n\n for (const msg of messages) {\n if (msg.role === 'system') {\n system = msg.content as string;\n } else {\n anthropicMessages.push({\n role: msg.role === 'assistant' ? 'assistant' : 'user',\n content: msg.content,\n });\n }\n }\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages: anthropicMessages,\n max_tokens: 4096,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (system) body.system = system;\n\n // Convert OpenAI tools format to Anthropic tools format\n if (tools && tools.length > 0) {\n body.tools = tools.map((t) => {\n const fn = (t as any).function;\n return {\n name: fn.name,\n description: fn.description,\n input_schema: fn.parameters,\n };\n });\n\n if (opts?.toolChoice) {\n if (typeof opts.toolChoice === 'string') {\n body.tool_choice = opts.toolChoice === 'required'\n ? { type: 'any' }\n : { type: opts.toolChoice };\n } else {\n body.tool_choice = { type: 'tool', name: opts.toolChoice.function.name };\n }\n }\n }\n\n return { url: `${this.config.baseURL}/messages`, body };\n }\n\n /**\n * Parse Anthropic response into our unified format.\n */\n private parseAnthropicResponse(json: Record<string, unknown>): {\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n } {\n const content = json.content as any[];\n if (!content || !Array.isArray(content)) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No content in Anthropic response', { rawResponse: json });\n }\n\n let textContent: string | undefined;\n const toolCalls: ToolCall[] = [];\n\n for (const block of content) {\n if (block.type === 'text') {\n textContent = block.text;\n } else if (block.type === 'tool_use') {\n toolCalls.push({\n id: block.id,\n type: 'function',\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n });\n }\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n content: textContent,\n usage: usage ? {\n promptTokens: usage.input_tokens ?? 0,\n completionTokens: usage.output_tokens ?? 0,\n totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),\n } : undefined,\n };\n }\n\n async chatCompletion(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } }\n ): Promise<{\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n }> {\n const { url, body } = this.buildBody(messages, tools, opts);\n const headers = this.buildHeaders();\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n } catch (err) {\n throw new InvokeError(InvokeErrorType.NETWORK_ERROR, `Network error: ${err}`, { rawError: err });\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n if (response.status === 401) {\n throw new InvokeError(InvokeErrorType.AUTH_ERROR, `Authentication failed: ${text}`, { retryable: false, rawResponse: text });\n }\n if (response.status === 429) {\n throw new InvokeError(InvokeErrorType.RATE_LIMIT, `Rate limited: ${text}`, { rawResponse: text });\n }\n if (response.status >= 500) {\n throw new InvokeError(InvokeErrorType.SERVER_ERROR, `Server error ${response.status}: ${text}`, { rawResponse: text });\n }\n throw new InvokeError(InvokeErrorType.UNKNOWN, `HTTP ${response.status}: ${text}`, { rawResponse: text });\n }\n\n const json = await response.json() as Record<string, unknown>;\n\n // Route to provider-specific parser\n if (this.config.provider === 'anthropic') {\n return this.parseAnthropicResponse(json);\n }\n\n // OpenAI-compatible response parsing (OpenAI, Gemini, Ollama)\n const choice = (json.choices as any[])?.[0];\n if (!choice) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No choices in response', { rawResponse: json });\n }\n\n const message = choice.message;\n const finishReason = choice.finish_reason;\n\n if (finishReason === 'content_filter') {\n throw new InvokeError(InvokeErrorType.CONTENT_FILTER, 'Content filtered', { retryable: false, rawResponse: json });\n }\n\n if (finishReason === 'length') {\n throw new InvokeError(InvokeErrorType.CONTEXT_LENGTH, 'Context length exceeded', { retryable: false, rawResponse: json });\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: message.tool_calls as ToolCall[] | undefined,\n content: message.content as string | undefined,\n usage: usage ? {\n promptTokens: usage.prompt_tokens ?? 0,\n completionTokens: usage.completion_tokens ?? 0,\n totalTokens: usage.total_tokens ?? 0,\n } : undefined,\n };\n }\n\n /**\n * Simple vision call — send a screenshot + text prompt, get text back.\n * Used by PDF Doctor for targeted issue resolution.\n */\n async chatWithVision(prompt: string, screenshotBase64: string): Promise<string> {\n const headers = this.buildHeaders();\n\n if (this.config.provider === 'anthropic') {\n // Anthropic vision format\n const body = {\n model: this.config.model,\n max_tokens: 1024,\n temperature: 0.1,\n messages: [{\n role: 'user',\n content: [\n {\n type: 'image',\n source: {\n type: 'base64',\n media_type: 'image/jpeg',\n data: screenshotBase64,\n },\n },\n { type: 'text', text: prompt },\n ],\n }],\n };\n\n const resp = await fetch(`${this.config.baseURL}/messages`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) throw new Error(`Anthropic vision error: ${resp.status}`);\n const json = await resp.json() as Record<string, unknown>;\n const content = json.content as any[];\n return content?.[0]?.text || '';\n }\n\n // OpenAI-compatible vision format (OpenAI, Gemini, Ollama)\n const body = {\n model: this.config.model,\n max_tokens: 1024,\n temperature: 0.1,\n messages: [{\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: {\n url: `data:image/jpeg;base64,${screenshotBase64}`,\n },\n },\n { type: 'text', text: prompt },\n ],\n }],\n };\n\n const resp = await fetch(`${this.config.baseURL}/chat/completions`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) throw new Error(`Vision API error: ${resp.status}`);\n const json = await resp.json() as Record<string, unknown>;\n const choice = (json.choices as any[])?.[0];\n return choice?.message?.content || '';\n }\n}\n","import type { z } from 'zod';\nimport type { LLMTool } from '../types/llm.js';\n\nexport function zodToJsonSchema(schema: z.ZodType): Record<string, unknown> {\n // Simplified Zod-to-JSON-Schema converter for common types\n if ('_def' in schema) {\n const def = (schema as any)._def;\n const typeName = def.typeName;\n\n if (typeName === 'ZodObject') {\n const shape = def.shape();\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = zodToJsonSchema(value as z.ZodType);\n if (!((value as any)._def?.typeName === 'ZodOptional')) {\n required.push(key);\n }\n }\n const result: Record<string, unknown> = { type: 'object', properties };\n if (required.length > 0) result.required = required;\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodString') {\n const result: Record<string, unknown> = { type: 'string' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodNumber') {\n const result: Record<string, unknown> = { type: 'number' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodBoolean') {\n const result: Record<string, unknown> = { type: 'boolean' };\n if (def.description) result.description = def.description;\n return result;\n }\n\n if (typeName === 'ZodEnum') {\n return { type: 'string', enum: def.values, ...(def.description ? { description: def.description } : {}) };\n }\n\n if (typeName === 'ZodArray') {\n return { type: 'array', items: zodToJsonSchema(def.type), ...(def.description ? { description: def.description } : {}) };\n }\n\n if (typeName === 'ZodOptional') {\n return zodToJsonSchema(def.innerType);\n }\n\n if (typeName === 'ZodDefault') {\n const inner = zodToJsonSchema(def.innerType);\n return { ...inner, default: def.defaultValue() };\n }\n\n if (typeName === 'ZodUnion') {\n return { oneOf: def.options.map((opt: z.ZodType) => zodToJsonSchema(opt)) };\n }\n\n if (typeName === 'ZodRecord') {\n return { type: 'object', additionalProperties: zodToJsonSchema(def.valueType) };\n }\n\n if (typeName === 'ZodLiteral') {\n return { const: def.value };\n }\n\n if (typeName === 'ZodAny') {\n return {};\n }\n }\n\n return { type: 'string' };\n}\n\nexport function zodToOpenAITool(name: string, description: string, schema: z.ZodType): LLMTool {\n return {\n type: 'function',\n function: {\n name,\n description,\n parameters: zodToJsonSchema(schema),\n },\n };\n}\n","import type { z } from 'zod';\nimport type { Message, InvokeResult, LLMTool } from '../types/llm.js';\nimport type { LLMConfig } from '../types/llm.js';\nimport { OpenAIClient } from './openai-client.js';\nimport { InvokeError, InvokeErrorType } from './errors.js';\nimport { zodToOpenAITool } from './utils.js';\n\nexport interface MacroTool {\n name: string;\n description: string;\n schema: z.ZodType;\n execute: (args: Record<string, unknown>) => Promise<string>;\n}\n\nexport class LLM {\n private client: OpenAIClient;\n private config: LLMConfig;\n\n constructor(config: LLMConfig) {\n this.config = config;\n this.client = new OpenAIClient({\n baseURL: config.baseURL,\n model: config.model,\n apiKey: config.apiKey,\n temperature: config.temperature,\n provider: config.provider as any,\n });\n }\n\n async invoke(\n messages: Message[],\n tool: MacroTool,\n abortSignal?: AbortSignal\n ): Promise<InvokeResult> {\n const openaiTool = zodToOpenAITool(tool.name, tool.description, tool.schema);\n\n return this.withRetry(async () => {\n if (abortSignal?.aborted) throw new Error('Aborted');\n\n const response = await this.client.chatCompletion(\n messages,\n [openaiTool],\n { toolChoice: { type: 'function', function: { name: tool.name } } }\n );\n\n // Extract tool call\n const toolCall = response.toolCalls?.[0];\n if (!toolCall) {\n // Try to extract from content (some models put JSON in content)\n if (response.content) {\n const extracted = extractJsonFromString(response.content);\n if (extracted) {\n const args = typeof extracted === 'string' ? JSON.parse(extracted) : extracted;\n const result = await tool.execute(args);\n return {\n toolCall: { name: tool.name, args },\n toolResult: result,\n usage: response.usage,\n };\n }\n }\n throw new InvokeError(InvokeErrorType.NO_TOOL_CALL, 'No tool call in response');\n }\n\n let args: Record<string, unknown>;\n try {\n args = JSON.parse(toolCall.function.arguments);\n } catch {\n // Try double-parse (some models double-stringify)\n try {\n args = JSON.parse(JSON.parse(toolCall.function.arguments));\n } catch {\n throw new InvokeError(InvokeErrorType.INVALID_TOOL_ARGS, `Invalid JSON in tool args: ${toolCall.function.arguments}`);\n }\n }\n\n let result: string;\n try {\n result = await tool.execute(args);\n } catch (err) {\n throw new InvokeError(InvokeErrorType.TOOL_EXECUTION_ERROR, `Tool execution failed: ${err}`, { rawError: err });\n }\n\n return {\n toolCall: { name: tool.name, args },\n toolResult: result,\n usage: response.usage,\n };\n });\n }\n\n private async withRetry<T>(fn: () => Promise<T>): Promise<T> {\n const maxRetries = this.config.maxRetries ?? 3;\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (err instanceof InvokeError && !err.retryable) throw err;\n if (err instanceof Error && err.name === 'AbortError') throw err;\n if (attempt < maxRetries) {\n await new Promise((r) => setTimeout(r, 100 * (attempt + 1)));\n }\n }\n }\n\n throw lastError;\n }\n}\n\nfunction extractJsonFromString(str: string): unknown | null {\n const start = str.indexOf('{');\n const end = str.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) return null;\n try {\n return JSON.parse(str.slice(start, end + 1));\n } catch {\n return null;\n }\n}\n","import puppeteer, { type Browser, type Page } from 'puppeteer-core';\nimport { existsSync } from 'node:fs';\nimport { log } from '../utils/logger.js';\nimport { getProfileDataDir } from './profiles.js';\nimport { resolveAttachTarget } from './chrome-attach.js';\nimport { injectStealth, STEALTH_ARGS } from './stealth.js';\n\nexport interface BrowserManagerConfig {\n executablePath?: string;\n headless?: boolean;\n cdpEndpoint?: string;\n connectTimeout?: number;\n profile?: string;\n attach?: boolean | string;\n stealth?: boolean;\n}\n\nexport class BrowserManager {\n private browser: Browser | null = null;\n private config: BrowserManagerConfig;\n private isAttached = false;\n\n constructor(config: BrowserManagerConfig = {}) {\n this.config = config;\n }\n\n async connect(): Promise<Browser> {\n if (this.browser?.connected) return this.browser;\n\n // Priority 1: Attach to running Chrome\n if (this.config.attach) {\n const wsEndpoint = await resolveAttachTarget(this.config.attach);\n log.info(`Attaching to Chrome: ${wsEndpoint}`);\n this.browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint });\n this.isAttached = true;\n return this.browser;\n }\n\n // Priority 2: Connect to CDP endpoint\n if (this.config.cdpEndpoint) {\n log.debug(`Connecting to CDP endpoint: ${this.config.cdpEndpoint}`);\n this.browser = await puppeteer.connect({\n browserWSEndpoint: this.config.cdpEndpoint,\n });\n this.isAttached = true;\n return this.browser;\n }\n\n // Priority 3: Launch new Chrome\n const executablePath = this.config.executablePath || findChrome();\n if (!executablePath) {\n throw new Error(\n 'Chrome/Chromium not found. Set LOBSTER_BROWSER_PATH or config browser.executablePath'\n );\n }\n\n // Build launch args\n const args = [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-dev-shm-usage',\n '--disable-gpu',\n ];\n\n // Stealth args\n if (this.config.stealth) {\n args.push(...STEALTH_ARGS);\n }\n\n // Profile — set user data directory\n let userDataDir: string | undefined;\n if (this.config.profile) {\n userDataDir = getProfileDataDir(this.config.profile);\n log.info(`Using profile \"${this.config.profile}\" → ${userDataDir}`);\n }\n\n log.debug(`Launching Chrome: ${executablePath}`);\n this.browser = await puppeteer.launch({\n executablePath,\n headless: this.config.headless ?? true,\n userDataDir,\n args,\n });\n\n this.isAttached = false;\n return this.browser;\n }\n\n async newPage(): Promise<Page> {\n const browser = await this.connect();\n const page = await browser.newPage();\n\n // Inject stealth scripts before any navigation\n if (this.config.stealth) {\n await injectStealth(page);\n log.debug('Stealth mode enabled');\n }\n\n return page;\n }\n\n async close(): Promise<void> {\n if (this.browser) {\n if (this.isAttached) {\n // Don't close user's browser — just disconnect\n this.browser.disconnect();\n log.debug('Disconnected from Chrome (attached mode)');\n } else {\n await this.browser.close().catch(() => {});\n }\n this.browser = null;\n }\n }\n}\n\nfunction findChrome(): string | undefined {\n const paths =\n process.platform === 'darwin'\n ? [\n '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n '/Applications/Chromium.app/Contents/MacOS/Chromium',\n '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n ]\n : process.platform === 'win32'\n ? [\n 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n 'C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe',\n ]\n : [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium-browser',\n '/usr/bin/chromium',\n '/snap/bin/chromium',\n ];\n\n return paths.find((p) => existsSync(p));\n}\n","import chalk from 'chalk';\n\nexport const log = {\n info: (msg: string) => console.log(chalk.blue('ℹ'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg),\n debug: (msg: string) => {\n if (process.env.LOBSTER_DEBUG) console.log(chalk.gray('⋯'), msg);\n },\n step: (n: number, msg: string) => console.log(chalk.cyan(`[${n}]`), msg),\n dim: (msg: string) => console.log(chalk.dim(msg)),\n};\n","/**\n * Persistent Profiles — store Chrome user data dirs so cookies,\n * auth, and extensions survive across sessions.\n *\n * Inspired by PinchTab's profile management, built from scratch.\n *\n * Storage: ~/.lobster/profiles/<name>/\n * Metadata: ~/.lobster/profiles/<name>/.lobster-meta.json\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, rmSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getConfigDir } from '../config/index.js';\nimport { log } from '../utils/logger.js';\n\nexport interface ProfileMeta {\n name: string;\n createdAt: string;\n lastUsed: string;\n sizeMB?: number;\n}\n\nconst PROFILES_DIR = () => join(getConfigDir(), 'profiles');\nconst META_FILE = '.lobster-meta.json';\n\n// Name validation: safe across Windows/Mac/Linux, no path traversal\nconst VALID_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;\nconst RESERVED_NAMES = new Set([\n 'default', 'system', 'con', 'prn', 'aux', 'nul',\n 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9',\n 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9',\n]);\n\n// Directories to delete on cache reset (keep cookies, extensions, local storage)\nconst CACHE_DIRS = [\n 'Cache', 'Code Cache', 'GPUCache', 'GrShaderCache', 'ShaderCache',\n 'Service Worker', 'Sessions', 'Session Storage', 'blob_storage',\n];\n\nfunction ensureProfilesDir(): void {\n const dir = PROFILES_DIR();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nfunction validateName(name: string): void {\n if (!VALID_NAME.test(name)) {\n throw new Error(`Invalid profile name \"${name}\". Use only letters, numbers, hyphens, underscores (max 64 chars).`);\n }\n if (RESERVED_NAMES.has(name.toLowerCase())) {\n throw new Error(`\"${name}\" is a reserved name. Choose a different profile name.`);\n }\n}\n\nfunction getProfileDir(name: string): string {\n return join(PROFILES_DIR(), name);\n}\n\nfunction readMeta(profileDir: string): ProfileMeta | null {\n const metaPath = join(profileDir, META_FILE);\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(profileDir: string, meta: ProfileMeta): void {\n writeFileSync(join(profileDir, META_FILE), JSON.stringify(meta, null, 2));\n}\n\nfunction getDirSizeMB(dirPath: string): number {\n let total = 0;\n try {\n const entries = readdirSync(dirPath, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isFile()) {\n total += statSync(fullPath).size;\n } else if (entry.isDirectory() && entry.name !== '.lobster-meta.json') {\n total += getDirSizeMB(fullPath) * 1024 * 1024; // recursive returns MB\n }\n }\n } catch {}\n return Math.round((total / (1024 * 1024)) * 10) / 10;\n}\n\n/**\n * Create a new profile.\n */\nexport function createProfile(name: string): ProfileMeta {\n validateName(name);\n ensureProfilesDir();\n\n const dir = getProfileDir(name);\n if (existsSync(dir)) {\n throw new Error(`Profile \"${name}\" already exists.`);\n }\n\n mkdirSync(dir, { recursive: true });\n\n const meta: ProfileMeta = {\n name,\n createdAt: new Date().toISOString(),\n lastUsed: new Date().toISOString(),\n };\n\n writeMeta(dir, meta);\n log.success(`Profile \"${name}\" created at ${dir}`);\n return meta;\n}\n\n/**\n * List all profiles.\n */\nexport function listProfiles(): ProfileMeta[] {\n ensureProfilesDir();\n const dir = PROFILES_DIR();\n const profiles: ProfileMeta[] = [];\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const profileDir = join(dir, entry.name);\n const meta = readMeta(profileDir);\n if (meta) {\n meta.sizeMB = getDirSizeMB(profileDir);\n profiles.push(meta);\n } else {\n // Directory exists but no meta — create meta\n profiles.push({\n name: entry.name,\n createdAt: 'unknown',\n lastUsed: 'unknown',\n sizeMB: getDirSizeMB(profileDir),\n });\n }\n }\n } catch {}\n\n return profiles.sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Remove a profile and all its data.\n */\nexport function removeProfile(name: string): void {\n const dir = getProfileDir(name);\n if (!existsSync(dir)) {\n throw new Error(`Profile \"${name}\" does not exist.`);\n }\n\n rmSync(dir, { recursive: true, force: true });\n log.success(`Profile \"${name}\" deleted.`);\n}\n\n/**\n * Get the Chrome user data directory for a profile.\n * Updates lastUsed timestamp.\n */\nexport function getProfileDataDir(name: string): string {\n validateName(name);\n const dir = getProfileDir(name);\n\n if (!existsSync(dir)) {\n // Auto-create if doesn't exist\n createProfile(name);\n } else {\n // Update lastUsed\n const meta = readMeta(dir) || { name, createdAt: 'unknown', lastUsed: '' };\n meta.lastUsed = new Date().toISOString();\n writeMeta(dir, meta);\n }\n\n return dir;\n}\n\n/**\n * Reset cache directories but keep cookies, extensions, and local storage.\n */\nexport function resetProfileCache(name: string): void {\n const dir = getProfileDir(name);\n if (!existsSync(dir)) {\n throw new Error(`Profile \"${name}\" does not exist.`);\n }\n\n let cleaned = 0;\n for (const cacheDir of CACHE_DIRS) {\n // Check both root and Default/ subdirectory\n for (const base of [dir, join(dir, 'Default')]) {\n const target = join(base, cacheDir);\n if (existsSync(target)) {\n rmSync(target, { recursive: true, force: true });\n cleaned++;\n }\n }\n }\n\n log.success(`Profile \"${name}\" cache reset (${cleaned} directories cleaned).`);\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport yaml from 'js-yaml';\nimport { configSchema, type LobsterConfig } from './schema.js';\nimport { DEFAULT_CONFIG } from './defaults.js';\n\nexport type { LobsterConfig };\n\nconst CONFIG_DIR = join(homedir(), '.lobster');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.yaml');\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): LobsterConfig {\n ensureConfigDir();\n\n let fileConfig: Record<string, unknown> = {};\n if (existsSync(CONFIG_FILE)) {\n const raw = readFileSync(CONFIG_FILE, 'utf-8');\n fileConfig = (yaml.load(raw) as Record<string, unknown>) || {};\n }\n\n // Env var overrides\n const envOverrides: Record<string, unknown> = {};\n if (process.env.LOBSTER_API_KEY) {\n envOverrides.llm = { ...(fileConfig.llm as Record<string, unknown> || {}), apiKey: process.env.LOBSTER_API_KEY };\n }\n if (process.env.LOBSTER_MODEL) {\n envOverrides.llm = { ...(envOverrides.llm as Record<string, unknown> || fileConfig.llm as Record<string, unknown> || {}), model: process.env.LOBSTER_MODEL };\n }\n if (process.env.LOBSTER_BASE_URL) {\n envOverrides.llm = { ...(envOverrides.llm as Record<string, unknown> || fileConfig.llm as Record<string, unknown> || {}), baseURL: process.env.LOBSTER_BASE_URL };\n }\n if (process.env.LOBSTER_CDP_ENDPOINT) {\n envOverrides.browser = { ...(fileConfig.browser as Record<string, unknown> || {}), cdpEndpoint: process.env.LOBSTER_CDP_ENDPOINT };\n }\n if (process.env.LOBSTER_BROWSER_PATH) {\n envOverrides.browser = { ...(envOverrides.browser as Record<string, unknown> || fileConfig.browser as Record<string, unknown> || {}), executablePath: process.env.LOBSTER_BROWSER_PATH };\n }\n\n const merged = { ...fileConfig, ...envOverrides };\n return configSchema.parse(merged);\n}\n\nexport function saveConfig(config: Partial<LobsterConfig>): void {\n ensureConfigDir();\n const existing = loadConfig();\n const merged = deepMerge(existing, config);\n writeFileSync(CONFIG_FILE, yaml.dump(merged, { indent: 2 }), 'utf-8');\n}\n\nexport function setConfigValue(keyPath: string, value: string): void {\n const parts = keyPath.split('.');\n const obj: Record<string, unknown> = {};\n let current: Record<string, unknown> = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n // Try to parse as number or boolean\n let parsed: unknown = value;\n if (value === 'true') parsed = true;\n else if (value === 'false') parsed = false;\n else if (!isNaN(Number(value)) && value !== '') parsed = Number(value);\n\n current[parts[parts.length - 1]] = parsed;\n saveConfig(obj as Partial<LobsterConfig>);\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result = { ...target };\n for (const key of Object.keys(source)) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) &&\n target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {\n result[key] = deepMerge(target[key] as Record<string, unknown>, source[key] as Record<string, unknown>);\n } else {\n result[key] = source[key];\n }\n }\n return result;\n}\n","import { z } from 'zod';\n\nexport const LLM_PROVIDERS = {\n openai: {\n name: 'OpenAI',\n baseURL: 'https://api.openai.com/v1',\n defaultModel: 'gpt-4o',\n keyPrefix: 'sk-',\n keyEnvHint: 'https://platform.openai.com/api-keys',\n models: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1', 'o1-mini', 'o3-mini'],\n },\n anthropic: {\n name: 'Anthropic',\n baseURL: 'https://api.anthropic.com/v1',\n defaultModel: 'claude-sonnet-4-20250514',\n keyPrefix: 'sk-ant-',\n keyEnvHint: 'https://console.anthropic.com/settings/keys',\n models: ['claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-haiku-4-5-20251001'],\n },\n gemini: {\n name: 'Google Gemini',\n baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',\n defaultModel: 'gemini-2.5-flash',\n keyPrefix: 'AI',\n keyEnvHint: 'https://aistudio.google.com/apikey',\n models: ['gemini-2.5-flash', 'gemini-2.5-flash-lite', 'gemini-2.5-pro', 'gemini-3-flash-preview'],\n },\n ollama: {\n name: 'Ollama (local, free)',\n baseURL: 'http://localhost:11434/v1',\n defaultModel: 'llama3.1',\n keyPrefix: '',\n keyEnvHint: 'No API key needed — install from https://ollama.ai',\n models: ['llama3.1', 'llama3.2', 'mistral', 'codestral', 'qwen2.5', 'deepseek-r1'],\n },\n} as const;\n\nexport type LLMProvider = keyof typeof LLM_PROVIDERS;\n\nexport const configSchema = z.object({\n llm: z.object({\n provider: z.enum(['openai', 'anthropic', 'gemini', 'ollama']).default('openai'),\n baseURL: z.string().default('https://api.openai.com/v1'),\n model: z.string().default('gpt-4o'),\n apiKey: z.string().default(''),\n temperature: z.number().min(0).max(2).default(0.1),\n maxRetries: z.number().int().min(0).default(3),\n }).default({}),\n browser: z.object({\n executablePath: z.string().default(''),\n headless: z.boolean().default(true),\n connectTimeout: z.number().default(30),\n commandTimeout: z.number().default(60),\n cdpEndpoint: z.string().default(''),\n profile: z.string().default(''),\n stealth: z.boolean().default(false),\n }).default({}),\n agent: z.object({\n maxSteps: z.number().int().default(40),\n stepDelay: z.number().default(0.4),\n }).default({}),\n domains: z.object({\n allow: z.array(z.string()).default([]),\n block: z.array(z.string()).default([]),\n blockMessage: z.string().default(''),\n }).default({}),\n output: z.object({\n defaultFormat: z.enum(['table', 'json', 'yaml', 'markdown', 'csv']).default('table'),\n color: z.boolean().default(true),\n }).default({}),\n});\n\nexport type LobsterConfig = z.infer<typeof configSchema>;\n","/**\n * Chrome Attach — discover and connect to a running Chrome instance.\n *\n * Probes common debug ports for Chrome's /json/version endpoint\n * and returns the WebSocket debugger URL for Puppeteer.connect().\n *\n * Inspired by PinchTab's attach mode, built from scratch.\n */\n\nimport http from 'node:http';\nimport { log } from '../utils/logger.js';\n\nexport interface ChromeDiscoveryResult {\n wsEndpoint: string;\n port: number;\n version: string;\n browser: string;\n}\n\nconst DEFAULT_PORTS = [9222, 9229, 9333, 9515];\nconst PROBE_TIMEOUT = 1500; // ms\n\n/**\n * Probe a single port for Chrome's DevTools endpoint.\n */\nfunction probePort(port: number): Promise<ChromeDiscoveryResult | null> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${port}/json/version`, {\n timeout: PROBE_TIMEOUT,\n }, (res) => {\n let data = '';\n res.on('data', (chunk: string) => { data += chunk; });\n res.on('end', () => {\n try {\n const info = JSON.parse(data);\n if (info.webSocketDebuggerUrl) {\n resolve({\n wsEndpoint: info.webSocketDebuggerUrl,\n port,\n version: info['Protocol-Version'] || '',\n browser: info.Browser || '',\n });\n } else {\n resolve(null);\n }\n } catch {\n resolve(null);\n }\n });\n });\n\n req.on('error', () => resolve(null));\n req.on('timeout', () => { req.destroy(); resolve(null); });\n });\n}\n\n/**\n * Discover a running Chrome instance by probing common debug ports.\n * Returns the first responding instance, or null if none found.\n */\nexport async function discoverChrome(ports?: number[]): Promise<ChromeDiscoveryResult | null> {\n const portsToCheck = ports || DEFAULT_PORTS;\n log.debug(`Scanning ports for Chrome: ${portsToCheck.join(', ')}`);\n\n // Probe all ports in parallel for speed\n const results = await Promise.all(portsToCheck.map(probePort));\n const found = results.find(Boolean) || null;\n\n if (found) {\n log.info(`Found Chrome on port ${found.port}: ${found.browser}`);\n } else {\n log.debug('No running Chrome instance found on debug ports.');\n }\n\n return found;\n}\n\n/**\n * Get WebSocket debugger URL from a specific port.\n */\nexport async function getWebSocketDebuggerUrl(port: number): Promise<string | null> {\n const result = await probePort(port);\n return result?.wsEndpoint || null;\n}\n\n/**\n * Parse an attach target — could be:\n * - \"true\" / true → auto-discover\n * - \"ws://...\" → explicit WebSocket URL\n * - \"9222\" → specific port number\n */\nexport async function resolveAttachTarget(target: boolean | string): Promise<string> {\n if (target === true || target === 'true') {\n const result = await discoverChrome();\n if (!result) {\n throw new Error(\n 'No running Chrome found. Start Chrome with:\\n' +\n ' google-chrome --remote-debugging-port=9222\\n' +\n ' # or on Mac:\\n' +\n ' /Applications/Google\\\\ Chrome.app/Contents/MacOS/Google\\\\ Chrome --remote-debugging-port=9222'\n );\n }\n return result.wsEndpoint;\n }\n\n if (typeof target === 'string') {\n // Explicit WebSocket URL\n if (target.startsWith('ws://') || target.startsWith('wss://')) {\n return target;\n }\n\n // Port number\n const port = parseInt(target, 10);\n if (!isNaN(port) && port > 0 && port < 65536) {\n const url = await getWebSocketDebuggerUrl(port);\n if (!url) {\n throw new Error(`No Chrome found on port ${port}. Make sure Chrome is running with --remote-debugging-port=${port}`);\n }\n return url;\n }\n\n throw new Error(`Invalid attach target: \"${target}\". Use \"true\" for auto-discover, a port number, or a ws:// URL.`);\n }\n\n throw new Error('Invalid attach target.');\n}\n","/**\n * Stealth Mode — anti-bot detection scripts.\n *\n * Injected via page.evaluateOnNewDocument() so it runs before\n * any page JavaScript, on every navigation.\n *\n * Inspired by PinchTab's 3-tier stealth system, built from scratch.\n * This is a comprehensive single-tier implementation covering the\n * most critical detection vectors.\n */\n\nimport type { Page } from 'puppeteer-core';\n\n/**\n * Comprehensive stealth script that evades common bot detection.\n */\nexport const STEALTH_SCRIPT = `\n(() => {\n // ── 1. navigator.webdriver removal ──\n // Most important: this is the #1 detection vector\n Object.defineProperty(navigator, 'webdriver', {\n get: () => undefined,\n configurable: true,\n });\n\n // Also delete from prototype\n delete Object.getPrototypeOf(navigator).webdriver;\n\n // ── 2. CDP marker removal ──\n // Chrome DevTools Protocol injects cdc_* properties on window\n for (const key of Object.keys(window)) {\n if (/^cdc_|^__webdriver|^__selenium|^__driver/.test(key)) {\n try { delete window[key]; } catch {}\n }\n }\n\n // ── 3. Chrome runtime spoofing ──\n // Real Chrome has window.chrome with runtime, loadTimes, csi\n if (!window.chrome) {\n window.chrome = {};\n }\n if (!window.chrome.runtime) {\n window.chrome.runtime = {\n connect: function() {},\n sendMessage: function() {},\n onMessage: { addListener: function() {} },\n id: undefined,\n };\n }\n if (!window.chrome.loadTimes) {\n window.chrome.loadTimes = function() {\n return {\n commitLoadTime: Date.now() / 1000 - 0.5,\n connectionInfo: 'h2',\n finishDocumentLoadTime: Date.now() / 1000 - 0.1,\n finishLoadTime: Date.now() / 1000 - 0.05,\n firstPaintAfterLoadTime: 0,\n firstPaintTime: Date.now() / 1000 - 0.3,\n navigationType: 'Other',\n npnNegotiatedProtocol: 'h2',\n requestTime: Date.now() / 1000 - 1,\n startLoadTime: Date.now() / 1000 - 0.8,\n wasAlternateProtocolAvailable: false,\n wasFetchedViaSpdy: true,\n wasNpnNegotiated: true,\n };\n };\n }\n if (!window.chrome.csi) {\n window.chrome.csi = function() {\n return {\n onloadT: Date.now(),\n startE: Date.now() - 500,\n pageT: 500,\n tran: 15,\n };\n };\n }\n\n // ── 4. Plugin array spoofing ──\n // Headless Chrome reports empty plugins; real Chrome has at least 2\n const fakePlugins = [\n { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format', length: 1 },\n { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '', length: 1 },\n { name: 'Native Client', filename: 'internal-nacl-plugin', description: '', length: 2 },\n ];\n\n Object.defineProperty(navigator, 'plugins', {\n get: () => {\n const arr = fakePlugins.map(p => {\n const plugin = { ...p, item: (i) => plugin, namedItem: (n) => plugin };\n return plugin;\n });\n arr.item = (i) => arr[i];\n arr.namedItem = (n) => arr.find(p => p.name === n);\n arr.refresh = () => {};\n return arr;\n },\n });\n\n // ── 5. Languages ──\n Object.defineProperty(navigator, 'languages', {\n get: () => ['en-US', 'en'],\n });\n Object.defineProperty(navigator, 'language', {\n get: () => 'en-US',\n });\n\n // ── 6. Platform consistency ──\n // Ensure platform matches user agent\n const platform = navigator.userAgent.includes('Mac') ? 'MacIntel' :\n navigator.userAgent.includes('Win') ? 'Win32' :\n navigator.userAgent.includes('Linux') ? 'Linux x86_64' : navigator.platform;\n Object.defineProperty(navigator, 'platform', { get: () => platform });\n\n // ── 7. Hardware concurrency & device memory ──\n // Headless often reports unusual values\n if (navigator.hardwareConcurrency < 2) {\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });\n }\n if (!navigator.deviceMemory || navigator.deviceMemory < 2) {\n Object.defineProperty(navigator, 'deviceMemory', { get: () => 8 });\n }\n\n // ── 8. WebGL vendor/renderer spoofing ──\n // Headless reports \"Google SwiftShader\" which is a dead giveaway\n const origGetParameter = WebGLRenderingContext.prototype.getParameter;\n WebGLRenderingContext.prototype.getParameter = function(param) {\n // UNMASKED_VENDOR_WEBGL\n if (param === 0x9245) return 'Intel Inc.';\n // UNMASKED_RENDERER_WEBGL\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return origGetParameter.call(this, param);\n };\n\n // Also for WebGL2\n if (typeof WebGL2RenderingContext !== 'undefined') {\n const origGetParameter2 = WebGL2RenderingContext.prototype.getParameter;\n WebGL2RenderingContext.prototype.getParameter = function(param) {\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return origGetParameter2.call(this, param);\n };\n }\n\n // ── 9. Canvas fingerprint noise ──\n // Adds subtle deterministic noise to canvas output based on domain\n const seed = location.hostname.split('').reduce((a, c) => a + c.charCodeAt(0), 0);\n const origToDataURL = HTMLCanvasElement.prototype.toDataURL;\n HTMLCanvasElement.prototype.toDataURL = function(type) {\n const ctx = this.getContext('2d');\n if (ctx && this.width > 0 && this.height > 0) {\n try {\n const imageData = ctx.getImageData(0, 0, 1, 1);\n // Flip a single pixel with seeded noise\n imageData.data[0] = (imageData.data[0] + seed) % 256;\n ctx.putImageData(imageData, 0, 0);\n } catch {}\n }\n return origToDataURL.apply(this, arguments);\n };\n\n // ── 10. Permissions API ──\n // Headless returns 'denied' for notifications; real Chrome returns 'prompt'\n const origQuery = navigator.permissions?.query?.bind(navigator.permissions);\n if (origQuery) {\n navigator.permissions.query = function(descriptor) {\n if (descriptor.name === 'notifications') {\n return Promise.resolve({ state: Notification.permission || 'prompt', onchange: null });\n }\n return origQuery(descriptor);\n };\n }\n\n // ── 11. Notification constructor ──\n if (!window.Notification) {\n window.Notification = function() {};\n window.Notification.permission = 'default';\n window.Notification.requestPermission = () => Promise.resolve('default');\n }\n\n // ── 12. Connection type ──\n if (navigator.connection) {\n Object.defineProperty(navigator.connection, 'rtt', { get: () => 50 });\n }\n})()\n`;\n\n/**\n * Inject stealth script into a Puppeteer page.\n * Must be called before first navigation for full effectiveness.\n */\nexport async function injectStealth(page: Page): Promise<void> {\n await page.evaluateOnNewDocument(STEALTH_SCRIPT);\n}\n\n/**\n * Chrome launch args for stealth mode.\n */\nexport const STEALTH_ARGS = [\n '--disable-blink-features=AutomationControlled',\n '--disable-features=IsolateOrigins,site-per-process',\n '--disable-infobars',\n '--window-size=1920,1080',\n];\n","/**\n * Script that runs inside the browser to extract a flat DOM tree\n * with indexed interactive elements — the format the AI agent uses.\n *\n * Based on Page Agent's DOM extraction approach.\n */\nexport const FLAT_TREE_SCRIPT = `\n(() => {\n const INTERACTIVE_TAGS = new Set([\n 'a', 'button', 'input', 'select', 'textarea', 'details', 'summary',\n 'label', 'option', 'fieldset', 'legend',\n ]);\n\n const INTERACTIVE_ROLES = new Set([\n 'button', 'link', 'textbox', 'checkbox', 'radio', 'combobox',\n 'listbox', 'menu', 'menuitem', 'tab', 'switch', 'slider',\n 'searchbox', 'spinbutton', 'option', 'menuitemcheckbox', 'menuitemradio',\n ]);\n\n const ATTR_WHITELIST = [\n 'type', 'role', 'aria-label', 'aria-expanded', 'aria-selected',\n 'aria-checked', 'aria-disabled', 'placeholder', 'title', 'href',\n 'value', 'name', 'alt', 'src',\n ];\n\n let highlightIndex = 0;\n const nodes = {};\n const selectorMap = {};\n\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0) return false;\n const style = getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n return true;\n }\n\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) return true;\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.getAttribute('contenteditable') === 'true') return true;\n if (el.getAttribute('tabindex') !== null && parseInt(el.getAttribute('tabindex')) >= 0) return true;\n if (el.onclick || el.getAttribute('onclick')) return true;\n return false;\n }\n\n function getAttributes(el) {\n const attrs = {};\n for (const attr of ATTR_WHITELIST) {\n const val = el.getAttribute(attr);\n if (val !== null && val !== '') attrs[attr] = val;\n }\n return attrs;\n }\n\n function getScrollable(el) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n const overflowX = style.overflowX;\n const isScrollableY = (overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight;\n const isScrollableX = (overflowX === 'auto' || overflowX === 'scroll') && el.scrollWidth > el.clientWidth;\n if (!isScrollableY && !isScrollableX) return null;\n return {\n left: el.scrollLeft,\n top: el.scrollTop,\n right: el.scrollWidth - el.clientWidth - el.scrollLeft,\n bottom: el.scrollHeight - el.clientHeight - el.scrollTop,\n };\n }\n\n function walk(el, parentId) {\n if (!el || el.nodeType === 8) return; // skip comments\n\n if (el.nodeType === 3) { // text node\n const text = el.textContent.trim();\n if (!text) return;\n const id = 'text_' + Math.random().toString(36).slice(2, 8);\n nodes[id] = { id, tagName: '#text', text, parentId };\n if (parentId && nodes[parentId]) {\n nodes[parentId].children = nodes[parentId].children || [];\n nodes[parentId].children.push(id);\n }\n return;\n }\n\n if (el.nodeType !== 1) return; // only elements\n\n const tag = el.tagName.toLowerCase();\n if (['script', 'style', 'noscript', 'svg', 'path'].includes(tag)) return;\n if (!isVisible(el)) return;\n\n const id = tag + '_' + Math.random().toString(36).slice(2, 8);\n const interactive = isInteractive(el);\n const node = {\n id,\n tagName: tag,\n attributes: getAttributes(el),\n parentId,\n children: [],\n isInteractive: interactive,\n };\n\n if (interactive) {\n node.highlightIndex = highlightIndex;\n selectorMap[highlightIndex] = id;\n highlightIndex++;\n }\n\n const scrollable = getScrollable(el);\n if (scrollable) node.scrollable = scrollable;\n\n const text = [];\n for (const child of el.childNodes) {\n if (child.nodeType === 3 && child.textContent.trim()) {\n text.push(child.textContent.trim());\n }\n }\n if (text.length > 0) node.text = text.join(' ').slice(0, 200);\n\n nodes[id] = node;\n\n if (parentId && nodes[parentId]) {\n nodes[parentId].children.push(id);\n }\n\n for (const child of el.children) {\n walk(child, id);\n }\n }\n\n const rootId = 'root';\n nodes[rootId] = { id: rootId, tagName: 'body', children: [], attributes: {} };\n for (const child of document.body.children) {\n walk(child, rootId);\n }\n\n return { rootId, map: nodes, selectorMap };\n})()\n`;\n\n/**\n * Convert a FlatDomTree into the indexed text format that the LLM agent reads.\n * Example output:\n * [0]<button type=submit>Search</>\n * [1]<input type=text placeholder=\"Enter query\" />\n */\nexport function flatTreeToString(tree: { rootId: string; map: Record<string, any> }): string {\n const lines: string[] = [];\n\n function walk(nodeId: string, depth: number) {\n const node = tree.map[nodeId];\n if (!node) return;\n\n const indent = '\\t'.repeat(depth);\n\n if (node.tagName === '#text') {\n if (node.text) lines.push(`${indent}${node.text}`);\n return;\n }\n\n const attrs = node.attributes || {};\n const attrStr = Object.entries(attrs)\n .map(([k, v]) => (v === '' ? k : `${k}=\"${v}\"`))\n .join(' ');\n\n const prefix = node.highlightIndex !== undefined ? `[${node.highlightIndex}]` : '';\n const scrollInfo = node.scrollable\n ? ` |scroll: ${Math.round(node.scrollable.top)}px up, ${Math.round(node.scrollable.bottom)}px down|`\n : '';\n\n const text = node.text || '';\n const tag = node.tagName;\n\n if (prefix || text || node.children?.length > 0) {\n const opening = `${indent}${prefix}<${tag}${attrStr ? ' ' + attrStr : ''}${scrollInfo}>`;\n\n if (!node.children?.length || (node.children.length === 0 && text)) {\n lines.push(`${opening}${text}</>`);\n } else {\n lines.push(`${opening}${text}`);\n for (const childId of node.children || []) {\n walk(childId, depth + 1);\n }\n }\n } else {\n for (const childId of node.children || []) {\n walk(childId, depth);\n }\n }\n }\n\n walk(tree.rootId, 0);\n return lines.join('\\n');\n}\n","/**\n * Advanced DOM snapshot script — runs inside the browser.\n * Multi-stage pruning pipeline producing LLM-optimized output.\n *\n * Stages:\n * 1. Walk DOM, collect visibility + layout + interactivity signals\n * 2. Prune invisible, zero-area, non-content elements\n * 3. SVG & decoration collapse\n * 4. Shadow DOM traversal\n * 5. Same-origin iframe extraction\n * 6. Bounding-box parent-child dedup (link/button wrapping)\n * 7. Paint-order occlusion detection (overlay/modal coverage)\n * 8. Attribute whitelist filtering\n * 9. Ad/tracker filtering\n * 10. Scroll position info\n * 11. data-ref annotation for targeting\n * 12. Token-efficient serialization with interactive indices\n */\n/**\n * Build snapshot script with optional previous hashes for diff marking.\n * Elements new since last snapshot get a `*` prefix on their index.\n */\nexport function buildSnapshotScript(previousHashes?: string[]): string {\n return SNAPSHOT_SCRIPT_FN(previousHashes || []);\n}\n\nfunction SNAPSHOT_SCRIPT_FN(prevHashes: string[]): string {\n return `\n(() => {\n let idx = 0;\n const __prevHashes = new Set(${JSON.stringify(prevHashes)});\n const __currentHashes = [];\n`;\n}\n\nexport const SNAPSHOT_SCRIPT = `\n(() => {\n let idx = 0;\n const __prevHashes = (window.__lobster_prev_hashes) ? new Set(window.__lobster_prev_hashes) : null;\n const __currentHashes = [];\n\n const SKIP_TAGS = new Set([\n 'script','style','noscript','svg','path','meta','link','head',\n 'template','slot','colgroup','col',\n ]);\n\n const INTERACTIVE_TAGS = new Set([\n 'a','button','input','select','textarea','details','summary','label',\n ]);\n\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n\n const ATTR_WHITELIST = [\n 'type','role','aria-label','aria-expanded','aria-selected','aria-checked',\n 'aria-disabled','aria-haspopup','aria-pressed','placeholder','title',\n 'href','value','name','alt','src','action','method','for',\n 'data-testid','data-id','contenteditable','tabindex',\n ];\n\n const AD_PATTERNS = /ad[-_]?banner|ad[-_]?container|google[-_]?ad|doubleclick|adsbygoogle|sponsored|^ad$/i;\n\n // ── Stage 1: Visibility check ──\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0 && el.tagName !== 'INPUT') return false;\n const s = getComputedStyle(el);\n if (s.display === 'none') return false;\n if (s.visibility === 'hidden' || s.visibility === 'collapse') return false;\n if (s.opacity === '0') return false;\n if (s.clipPath === 'inset(100%)') return false;\n // Check for offscreen positioning\n const rect = el.getBoundingClientRect();\n if (rect.right < 0 || rect.bottom < 0) return false;\n return true;\n }\n\n // ── Stage 2: Interactive detection ──\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) {\n // Skip disabled elements\n if (el.disabled) return false;\n // Skip hidden inputs\n if (tag === 'input' && el.type === 'hidden') return false;\n return true;\n }\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.contentEditable === 'true') return true;\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) return true;\n if (el.onclick) return true;\n return false;\n }\n\n // ── Stage 8: Attribute filtering ──\n function getAttrs(el) {\n const parts = [];\n for (const name of ATTR_WHITELIST) {\n let v = el.getAttribute(name);\n if (v === null || v === '') continue;\n // Truncate long values\n if (v.length > 80) v = v.slice(0, 77) + '...';\n // Skip href=\"javascript:...\"\n if (name === 'href' && v.startsWith('javascript:')) continue;\n parts.push(name + '=' + v);\n }\n return parts.length ? ' ' + parts.join(' ') : '';\n }\n\n // ── Stage 9: Ad filtering ──\n function isAd(el) {\n const id = el.id || '';\n const cls = el.className || '';\n if (typeof cls === 'string' && AD_PATTERNS.test(cls)) return true;\n if (AD_PATTERNS.test(id)) return true;\n if (el.tagName === 'IFRAME' && AD_PATTERNS.test(el.src || '')) return true;\n return false;\n }\n\n // ── Stage 10: Scroll info ──\n function getScrollInfo(el) {\n const s = getComputedStyle(el);\n const overflowY = s.overflowY;\n const overflowX = s.overflowX;\n const scrollableY = (overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight;\n const scrollableX = (overflowX === 'auto' || overflowX === 'scroll') && el.scrollWidth > el.clientWidth;\n if (!scrollableY && !scrollableX) return '';\n\n const parts = [];\n if (scrollableY) {\n const up = Math.round(el.scrollTop);\n const down = Math.round(el.scrollHeight - el.clientHeight - el.scrollTop);\n if (up > 0) parts.push(up + 'px up');\n if (down > 0) parts.push(down + 'px down');\n }\n if (scrollableX) {\n const left = Math.round(el.scrollLeft);\n const right = Math.round(el.scrollWidth - el.clientWidth - el.scrollLeft);\n if (left > 0) parts.push(left + 'px left');\n if (right > 0) parts.push(right + 'px right');\n }\n return parts.length ? ' |scroll: ' + parts.join(', ') + '|' : '';\n }\n\n // ── Stage 6: Bounding-box dedup ──\n // If a parent and child are both interactive and have ~same bounding box,\n // skip the parent (e.g., <a><button>Click</button></a>)\n function isWrappingInteractive(el) {\n if (!isInteractive(el)) return false;\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return false;\n for (const child of el.children) {\n if (!isInteractive(child)) continue;\n const cr = child.getBoundingClientRect();\n const overlapX = Math.min(rect.right, cr.right) - Math.max(rect.left, cr.left);\n const overlapY = Math.min(rect.bottom, cr.bottom) - Math.max(rect.top, cr.top);\n const overlapArea = Math.max(0, overlapX) * Math.max(0, overlapY);\n const parentArea = rect.width * rect.height;\n if (parentArea > 0 && overlapArea / parentArea > 0.85) return true;\n }\n return false;\n }\n\n // ── Stage 7: Occlusion detection ──\n function isOccluded(el) {\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return false;\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n const topEl = document.elementFromPoint(cx, cy);\n if (!topEl) return false;\n if (topEl === el || el.contains(topEl) || topEl.contains(el)) return false;\n // Check z-index — if top element is a modal/overlay, mark as occluded\n const topZ = parseInt(getComputedStyle(topEl).zIndex) || 0;\n const elZ = parseInt(getComputedStyle(el).zIndex) || 0;\n return topZ > elZ + 10;\n }\n\n // ── Stage 5: Iframe content extraction ──\n function getIframeContent(iframe, depth, maxDepth) {\n try {\n const doc = iframe.contentDocument;\n if (!doc || !doc.body) return '';\n return '\\\\n' + walkNode(doc.body, depth, maxDepth);\n } catch { return ''; }\n }\n\n // ── Stage 4: Shadow DOM traversal ──\n function getShadowContent(el, depth, maxDepth) {\n if (!el.shadowRoot) return '';\n let out = '';\n for (const child of el.shadowRoot.childNodes) {\n out += walkNode(child, depth, maxDepth);\n }\n return out;\n }\n\n // ── Input value hint ──\n function getInputHint(el) {\n const tag = el.tagName.toLowerCase();\n if (tag === 'input') {\n const type = el.type || 'text';\n const val = el.value || '';\n const checked = el.checked;\n if (type === 'checkbox' || type === 'radio') {\n return checked ? ' [checked]' : ' [unchecked]';\n }\n if (val) return ' value=\"' + val.slice(0, 50) + '\"';\n }\n if (tag === 'textarea' && el.value) {\n return ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n if (tag === 'select' && el.selectedOptions?.length) {\n return ' selected=\"' + el.selectedOptions[0].text.slice(0, 40) + '\"';\n }\n return '';\n }\n\n const MAX_DEPTH = 25;\n const MAX_TEXT = 150;\n\n function walkNode(node, depth, maxDepth) {\n if (depth > maxDepth) return '';\n if (!node) return '';\n\n // Text node\n if (node.nodeType === 3) {\n const t = node.textContent.trim();\n if (!t) return '';\n const text = t.length > MAX_TEXT ? t.slice(0, MAX_TEXT) + '...' : t;\n return ' '.repeat(depth) + text + '\\\\n';\n }\n\n // Comment node — skip\n if (node.nodeType === 8) return '';\n\n // Only element nodes from here\n if (node.nodeType !== 1) return '';\n\n const el = node;\n const tag = el.tagName.toLowerCase();\n\n // ── Stage 3: Skip tags ──\n if (SKIP_TAGS.has(tag)) return '';\n\n // ── Stage 2: Visibility ──\n if (!isVisible(el)) return '';\n\n // ── Stage 9: Ad filtering ──\n if (isAd(el)) return '';\n\n // ── Stage 6: Bbox dedup — skip wrapping interactive parent ──\n const skipSelf = isWrappingInteractive(el);\n\n const indent = ' '.repeat(depth);\n const inter = !skipSelf && isInteractive(el);\n let prefix = '';\n if (inter) {\n const thisIdx = idx++;\n // Hash: tag + text + key attributes for diff tracking\n const hashText = tag + ':' + (el.textContent || '').trim().slice(0, 40) + ':' + (el.getAttribute('href') || '') + ':' + (el.getAttribute('aria-label') || '');\n __currentHashes.push(hashText);\n const isNew = __prevHashes && __prevHashes.size > 0 && !__prevHashes.has(hashText);\n prefix = isNew ? '*[' + thisIdx + ']' : '[' + thisIdx + ']';\n }\n\n // ── Stage 11: Annotate with data-ref ──\n if (inter) {\n try { el.dataset.ref = String(idx - 1); } catch {}\n }\n\n // ── Stage 7: Occlusion check for interactive elements ──\n if (inter && isOccluded(el)) {\n // Still include but mark as occluded\n // (agent needs to know element exists but may need to scroll/close modal)\n }\n\n const a = getAttrs(el);\n const scrollInfo = getScrollInfo(el);\n const inputHint = inter ? getInputHint(el) : '';\n\n // Leaf text extraction\n let leafText = '';\n if (el.childNodes.length === 1 && el.childNodes[0].nodeType === 3) {\n const t = el.childNodes[0].textContent.trim();\n if (t) leafText = t.length > MAX_TEXT ? t.slice(0, MAX_TEXT) + '...' : t;\n }\n\n // ── Stage 5: Iframe ──\n if (tag === 'iframe') {\n const iframeContent = getIframeContent(el, depth + 1, maxDepth);\n if (iframeContent) {\n return indent + prefix + '<iframe' + a + '>\\\\n' + iframeContent;\n }\n return '';\n }\n\n // Build output\n let out = '';\n\n if (skipSelf) {\n // Skip self but render children\n for (const c of el.childNodes) out += walkNode(c, depth, maxDepth);\n out += getShadowContent(el, depth, maxDepth);\n return out;\n }\n\n if (inter || leafText || el.children.length === 0) {\n if (leafText) {\n out = indent + prefix + '<' + tag + a + scrollInfo + inputHint + '>' + leafText + '</' + tag + '>\\\\n';\n } else {\n out = indent + prefix + '<' + tag + a + scrollInfo + inputHint + '>\\\\n';\n for (const c of el.childNodes) out += walkNode(c, depth + 1, maxDepth);\n out += getShadowContent(el, depth + 1, maxDepth);\n }\n } else {\n // Non-interactive container — flatten depth if no useful info\n if (scrollInfo) {\n out = indent + '<' + tag + scrollInfo + '>\\\\n';\n for (const c of el.childNodes) out += walkNode(c, depth + 1, maxDepth);\n out += getShadowContent(el, depth + 1, maxDepth);\n } else {\n for (const c of el.childNodes) out += walkNode(c, depth, maxDepth);\n out += getShadowContent(el, depth, maxDepth);\n }\n }\n\n return out;\n }\n\n // ── Page-level scroll info header ──\n const scrollY = window.scrollY;\n const scrollMax = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPct = scrollMax > 0 ? Math.round((scrollY / scrollMax) * 100) : 0;\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const pageH = document.documentElement.scrollHeight;\n\n let header = '';\n header += 'viewport: ' + vpW + 'x' + vpH + ' | page_height: ' + pageH + 'px';\n header += ' | scroll: ' + scrollPct + '%';\n if (scrollY > 50) header += ' (' + Math.round(scrollY) + 'px from top)';\n if (scrollMax - scrollY > 50) header += ' (' + Math.round(scrollMax - scrollY) + 'px more below)';\n header += '\\\\n---\\\\n';\n\n // Store current hashes for next diff comparison\n window.__lobster_prev_hashes = __currentHashes;\n\n return header + walkNode(document.body, 0, MAX_DEPTH);\n})()\n`;\n","/**\n * Compact Snapshot — token-efficient DOM snapshot (~800 tokens).\n *\n * Only emits interactive elements + landmark section headers.\n * Format: [0] button \"Sign In\" (one line per element)\n *\n * Inspired by PinchTab's token-counting approach, built from scratch.\n */\n\nexport const COMPACT_SNAPSHOT_SCRIPT = `\n(() => {\n const TOKEN_BUDGET = 800;\n const CHARS_PER_TOKEN = 4;\n\n const INTERACTIVE_TAGS = new Set([\n 'a','button','input','select','textarea','details','summary','label',\n ]);\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n const LANDMARK_TAGS = new Map([\n ['nav', 'Navigation'],\n ['main', 'Main Content'],\n ['header', 'Header'],\n ['footer', 'Footer'],\n ['aside', 'Sidebar'],\n ['form', 'Form'],\n ]);\n const LANDMARK_ROLES = new Map([\n ['navigation', 'Navigation'],\n ['main', 'Main Content'],\n ['banner', 'Header'],\n ['contentinfo', 'Footer'],\n ['complementary', 'Sidebar'],\n ['search', 'Search'],\n ['dialog', 'Dialog'],\n ]);\n\n function isVisible(el) {\n if (el.offsetWidth === 0 && el.offsetHeight === 0 && el.tagName !== 'INPUT') return false;\n const s = getComputedStyle(el);\n return s.display !== 'none' && s.visibility !== 'hidden' && s.opacity !== '0';\n }\n\n function isInteractive(el) {\n const tag = el.tagName.toLowerCase();\n if (INTERACTIVE_TAGS.has(tag)) {\n if (el.disabled) return false;\n if (tag === 'input' && el.type === 'hidden') return false;\n return true;\n }\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (el.contentEditable === 'true') return true;\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) return true;\n return false;\n }\n\n function getRole(el) {\n const role = el.getAttribute('role');\n if (role) return role;\n const tag = el.tagName.toLowerCase();\n if (tag === 'a') return 'link';\n if (tag === 'button' || tag === 'summary') return 'button';\n if (tag === 'input') return el.type || 'text';\n if (tag === 'select') return 'select';\n if (tag === 'textarea') return 'textarea';\n if (tag === 'label') return 'label';\n return tag;\n }\n\n function getName(el) {\n return (\n el.getAttribute('aria-label') ||\n el.getAttribute('alt') ||\n el.getAttribute('title') ||\n el.getAttribute('placeholder') ||\n (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button') ? el.value : '') ||\n (el.id ? document.querySelector('label[for=\"' + el.id + '\"]')?.textContent?.trim() : '') ||\n (el.children.length <= 2 ? el.textContent?.trim() : '') ||\n ''\n ).slice(0, 60);\n }\n\n function getValue(el) {\n const tag = el.tagName.toLowerCase();\n if (tag === 'input') {\n const type = el.type || 'text';\n if (type === 'checkbox' || type === 'radio') return el.checked ? 'checked' : 'unchecked';\n if (type === 'password') return el.value ? '****' : '';\n return el.value ? el.value.slice(0, 30) : '';\n }\n if (tag === 'textarea') return el.value ? el.value.slice(0, 30) : '';\n if (tag === 'select' && el.selectedOptions?.length) return el.selectedOptions[0].text.slice(0, 30);\n return '';\n }\n\n // Collect elements\n let idx = 0;\n let charsUsed = 0;\n const lines = [];\n let lastLandmark = '';\n\n // Page header\n const scrollY = window.scrollY;\n const scrollMax = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPct = scrollMax > 0 ? Math.round((scrollY / scrollMax) * 100) : 0;\n const header = 'url: ' + location.href + ' | scroll: ' + scrollPct + '%';\n lines.push(header);\n charsUsed += header.length;\n\n // Walk DOM\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n if (!isVisible(node)) continue;\n\n const tag = node.tagName.toLowerCase();\n if (['script','style','noscript','svg','path','meta','link','head','template'].includes(tag)) continue;\n\n // Check for landmark\n const role = node.getAttribute('role');\n const landmark = LANDMARK_TAGS.get(tag) || (role ? LANDMARK_ROLES.get(role) : null);\n if (landmark && landmark !== lastLandmark) {\n const sectionLine = '--- ' + landmark + ' ---';\n if (charsUsed + sectionLine.length > TOKEN_BUDGET * CHARS_PER_TOKEN) break;\n lines.push(sectionLine);\n charsUsed += sectionLine.length;\n lastLandmark = landmark;\n }\n\n // Only emit interactive elements\n if (!isInteractive(node)) continue;\n\n const elRole = getRole(node);\n const name = getName(node);\n const value = getValue(node);\n\n // Build compact line\n let line = '[' + idx + '] ' + elRole;\n if (name) line += ' \"' + name.replace(/\"/g, \"'\") + '\"';\n if (value) line += ' val=\"' + value.replace(/\"/g, \"'\") + '\"';\n\n // Check token budget\n if (charsUsed + line.length > TOKEN_BUDGET * CHARS_PER_TOKEN) {\n lines.push('... (' + (document.querySelectorAll('a,button,input,select,textarea,[role]').length - idx) + ' more elements)');\n break;\n }\n\n // Annotate element with ref for clicking\n try { node.dataset.ref = String(idx); } catch {}\n\n lines.push(line);\n charsUsed += line.length;\n idx++;\n }\n\n return lines.join('\\\\n');\n})()\n`;\n\n/**\n * Build compact snapshot script with custom token budget.\n */\nexport function buildCompactSnapshotScript(tokenBudget: number = 800): string {\n return COMPACT_SNAPSHOT_SCRIPT.replace('const TOKEN_BUDGET = 800;', `const TOKEN_BUDGET = ${tokenBudget};`);\n}\n","/**\n * Semantic tree — W3C accessible name algorithm, XPath, listener detection.\n *\n * Based on Lightpanda's SemanticTree.zig approach:\n * - Accessible name: aria-labelledby → aria-label → alt → title → placeholder → text content\n * - XPath generation for element location\n * - Interactive classification: native, aria, contenteditable, listener, focusable\n * - Disabled state with fieldset inheritance\n * - Input value, option, checked state extraction\n */\nexport const SEMANTIC_TREE_SCRIPT = `\n(() => {\n const SKIP = new Set(['script','style','noscript','svg','head','meta','link','template']);\n\n const ROLE_MAP = {\n a: 'link', button: 'button', input: 'textbox', select: 'combobox',\n textarea: 'textbox', h1: 'heading', h2: 'heading', h3: 'heading',\n h4: 'heading', h5: 'heading', h6: 'heading', nav: 'navigation',\n main: 'main', header: 'banner', footer: 'contentinfo', aside: 'complementary',\n form: 'form', table: 'table', img: 'img', ul: 'list', ol: 'list', li: 'listitem',\n section: 'region', article: 'article', dialog: 'dialog', details: 'group',\n summary: 'button', progress: 'progressbar', meter: 'meter', output: 'status',\n label: 'label', legend: 'legend', fieldset: 'group', option: 'option',\n tr: 'row', td: 'cell', th: 'columnheader', caption: 'caption',\n };\n\n const INTERACTIVE_ROLES = new Set([\n 'button','link','textbox','checkbox','radio','combobox','listbox',\n 'menu','menuitem','tab','switch','slider','searchbox','spinbutton',\n 'option','menuitemcheckbox','menuitemradio','treeitem',\n ]);\n\n // ── W3C Accessible Name Algorithm (simplified) ──\n function getAccessibleName(el) {\n // 1. aria-labelledby (highest priority)\n const labelledBy = el.getAttribute('aria-labelledby');\n if (labelledBy) {\n const ids = labelledBy.split(/\\\\s+/);\n const parts = ids.map(id => {\n const ref = document.getElementById(id);\n return ref ? ref.textContent.trim() : '';\n }).filter(Boolean);\n if (parts.length > 0) return parts.join(' ').slice(0, 120);\n }\n\n // 2. aria-label\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return ariaLabel.slice(0, 120);\n\n // 3. alt (for images)\n const alt = el.getAttribute('alt');\n if (alt) return alt.slice(0, 120);\n\n // 4. title\n const title = el.getAttribute('title');\n if (title) return title.slice(0, 120);\n\n // 5. placeholder (for inputs)\n const placeholder = el.getAttribute('placeholder');\n if (placeholder) return placeholder.slice(0, 120);\n\n // 6. value (for buttons)\n if (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button')) {\n const val = el.getAttribute('value');\n if (val) return val.slice(0, 120);\n }\n\n // 7. Associated label\n if (el.id) {\n const label = document.querySelector('label[for=\"' + el.id + '\"]');\n if (label) return label.textContent.trim().slice(0, 120);\n }\n\n // 8. Direct text content (only for leaf-ish elements)\n if (el.children.length <= 2) {\n const text = el.textContent.trim();\n if (text && text.length < 120) return text;\n }\n\n return '';\n }\n\n // ── XPath generation ──\n function getXPath(el) {\n const parts = [];\n let current = el;\n while (current && current.nodeType === 1) {\n let index = 1;\n let sibling = current.previousElementSibling;\n while (sibling) {\n if (sibling.tagName === current.tagName) index++;\n sibling = sibling.previousElementSibling;\n }\n const tag = current.tagName.toLowerCase();\n parts.unshift(tag + '[' + index + ']');\n current = current.parentElement;\n }\n return '/' + parts.join('/');\n }\n\n // ── Interactivity classification ──\n function classifyInteractivity(el) {\n const types = [];\n const tag = el.tagName.toLowerCase();\n\n // Native\n if (['a','button','input','select','textarea','details','summary'].includes(tag)) {\n if (tag === 'a' && !el.href) {} // anchor without href is not interactive\n else if (tag === 'input' && el.type === 'hidden') {} // hidden inputs\n else types.push('native');\n }\n\n // ARIA role\n const role = el.getAttribute('role');\n if (role && INTERACTIVE_ROLES.has(role)) types.push('aria');\n\n // Contenteditable\n if (el.contentEditable === 'true') types.push('contenteditable');\n\n // Focusable\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) types.push('focusable');\n\n // Event listeners (check onclick and common inline handlers)\n if (el.onclick || el.onmousedown || el.onkeydown || el.onkeypress ||\n el.getAttribute('onclick') || el.getAttribute('onmousedown')) {\n types.push('listener');\n }\n\n return types;\n }\n\n // ── Disabled state with fieldset inheritance ──\n function isDisabled(el) {\n if (el.disabled) return true;\n // Check fieldset disabled inheritance\n let parent = el.parentElement;\n while (parent) {\n if (parent.tagName === 'FIELDSET' && parent.disabled) {\n // Exception: elements inside the first legend child are NOT disabled\n const firstLegend = parent.querySelector(':scope > legend');\n if (firstLegend && firstLegend.contains(el)) return false;\n return true;\n }\n parent = parent.parentElement;\n }\n return false;\n }\n\n // ── Walk the DOM ──\n function walk(el, depth, maxDepth) {\n if (!el || depth > maxDepth) return '';\n\n if (el.nodeType === 3) {\n const t = el.textContent.trim();\n return t ? ' '.repeat(depth) + 'text \"' + t.slice(0, 100) + '\"\\\\n' : '';\n }\n\n if (el.nodeType !== 1) return '';\n const tag = el.tagName.toLowerCase();\n if (SKIP.has(tag)) return '';\n\n const style = getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden') return '';\n\n const indent = ' '.repeat(depth);\n const role = el.getAttribute('role') || ROLE_MAP[tag] || '';\n const name = getAccessibleName(el);\n const interTypes = classifyInteractivity(el);\n const interactive = interTypes.length > 0;\n const disabled = interactive && isDisabled(el);\n\n let line = indent;\n line += role || tag;\n\n if (name) line += ' \"' + name.slice(0, 80) + '\"';\n\n if (interactive) {\n line += ' [' + interTypes.join(',') + ']';\n if (disabled) line += ' {disabled}';\n line += ' xpath=' + getXPath(el);\n }\n\n // Input state\n if (tag === 'input') {\n const type = el.type || 'text';\n line += ' type=' + type;\n if (type === 'checkbox' || type === 'radio') {\n line += el.checked ? ' [checked]' : ' [unchecked]';\n } else if (el.value) {\n line += ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n }\n if (tag === 'textarea' && el.value) {\n line += ' value=\"' + el.value.slice(0, 50) + '\"';\n }\n if (tag === 'select') {\n const opts = Array.from(el.options || []).map(o => ({\n text: o.text.slice(0, 30),\n value: o.value,\n selected: o.selected,\n }));\n const selected = opts.find(o => o.selected);\n if (selected) line += ' selected=\"' + selected.text + '\"';\n if (opts.length <= 10) {\n line += ' options=[' + opts.map(o => o.text).join('|') + ']';\n }\n }\n\n line += '\\\\n';\n\n let out = line;\n for (const c of el.childNodes) {\n out += walk(c, depth + 1, maxDepth);\n }\n\n // Shadow DOM\n if (el.shadowRoot) {\n for (const c of el.shadowRoot.childNodes) {\n out += walk(c, depth + 1, maxDepth);\n }\n }\n\n return out;\n }\n\n return walk(document.body, 0, 20);\n})()\n`;\n","/**\n * DOM-to-Markdown converter — runs inside the browser.\n *\n * Full-featured conversion based on Lightpanda's markdown.zig:\n * - Table support with header separator rows\n * - URL resolution (relative → absolute)\n * - Nested ordered/unordered lists with proper indentation\n * - Character escaping for Markdown special chars\n * - Strikethrough, code blocks, blockquotes\n * - Smart anchor handling (inline vs block)\n * - Whitespace collapsing\n */\nexport const MARKDOWN_SCRIPT = `\n(() => {\n const SKIP = new Set(['script','style','noscript','svg','head','template']);\n const baseUrl = location.href;\n\n // Resolve relative URLs to absolute\n function resolveUrl(href) {\n if (!href || href.startsWith('javascript:') || href.startsWith('#')) return href;\n try { return new URL(href, baseUrl).href; } catch { return href; }\n }\n\n // Escape Markdown special chars in text\n function escapeText(text) {\n return text\n .replace(/\\\\\\\\/g, '\\\\\\\\\\\\\\\\')\n .replace(/([*_~\\`\\\\[\\\\]|])/g, '\\\\\\\\$1');\n }\n\n // State tracking\n let listDepth = 0;\n let orderedCounters = [];\n let inPre = false;\n let inTable = false;\n\n function listIndent() { return ' '.repeat(listDepth); }\n\n function walk(el) {\n if (!el) return '';\n\n // Text node\n if (el.nodeType === 3) {\n const text = el.textContent || '';\n if (inPre) return text;\n // Collapse whitespace\n const collapsed = text.replace(/\\\\s+/g, ' ');\n return collapsed === ' ' && !el.previousSibling && !el.nextSibling ? '' : collapsed;\n }\n\n if (el.nodeType !== 1) return '';\n const tag = el.tagName.toLowerCase();\n if (SKIP.has(tag)) return '';\n\n // Visibility check\n try {\n const s = getComputedStyle(el);\n if (s.display === 'none' || s.visibility === 'hidden') return '';\n } catch {}\n\n // Get children content\n function childContent() {\n let out = '';\n for (const c of el.childNodes) out += walk(c);\n return out;\n }\n\n switch (tag) {\n // ── Headings ──\n case 'h1': return '\\\\n\\\\n# ' + childContent().trim() + '\\\\n\\\\n';\n case 'h2': return '\\\\n\\\\n## ' + childContent().trim() + '\\\\n\\\\n';\n case 'h3': return '\\\\n\\\\n### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h4': return '\\\\n\\\\n#### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h5': return '\\\\n\\\\n##### ' + childContent().trim() + '\\\\n\\\\n';\n case 'h6': return '\\\\n\\\\n###### ' + childContent().trim() + '\\\\n\\\\n';\n\n // ── Block elements ──\n case 'p': return '\\\\n\\\\n' + childContent().trim() + '\\\\n\\\\n';\n case 'br': return '\\\\n';\n case 'hr': return '\\\\n\\\\n---\\\\n\\\\n';\n\n // ── Inline formatting ──\n case 'strong': case 'b': {\n const inner = childContent().trim();\n return inner ? '**' + inner + '**' : '';\n }\n case 'em': case 'i': {\n const inner = childContent().trim();\n return inner ? '*' + inner + '*' : '';\n }\n case 's': case 'del': case 'strike': {\n const inner = childContent().trim();\n return inner ? '~~' + inner + '~~' : '';\n }\n case 'code': {\n if (inPre) return childContent();\n const inner = childContent();\n return inner ? '\\\\x60' + inner + '\\\\x60' : '';\n }\n\n // ── Code blocks ──\n case 'pre': {\n inPre = true;\n const inner = childContent();\n inPre = false;\n const lang = el.querySelector('code')?.className?.match(/language-(\\\\w+)/)?.[1] || '';\n return '\\\\n\\\\n\\\\x60\\\\x60\\\\x60' + lang + '\\\\n' + inner.trim() + '\\\\n\\\\x60\\\\x60\\\\x60\\\\n\\\\n';\n }\n\n // ── Links ──\n case 'a': {\n const href = resolveUrl(el.getAttribute('href') || '');\n const inner = childContent().trim();\n const name = inner || el.getAttribute('aria-label') || el.getAttribute('title') || '';\n if (!name) return '';\n if (!href || href === '#' || href.startsWith('javascript:')) return name;\n return '[' + name + '](' + href + ')';\n }\n\n // ── Images ──\n case 'img': {\n const alt = el.getAttribute('alt') || '';\n const src = resolveUrl(el.getAttribute('src') || '');\n return src ? '![' + alt + '](' + src + ')' : '';\n }\n\n // ── Lists ──\n case 'ul': {\n listDepth++;\n orderedCounters.push(0);\n const inner = childContent();\n listDepth--;\n orderedCounters.pop();\n return '\\\\n' + inner;\n }\n case 'ol': {\n listDepth++;\n orderedCounters.push(0);\n const inner = childContent();\n listDepth--;\n orderedCounters.pop();\n return '\\\\n' + inner;\n }\n case 'li': {\n const parent = el.parentElement?.tagName?.toLowerCase();\n const isOrdered = parent === 'ol';\n const inner = childContent().trim();\n if (!inner) return '';\n if (isOrdered) {\n const counter = orderedCounters.length > 0\n ? ++orderedCounters[orderedCounters.length - 1] : 1;\n return listIndent() + counter + '. ' + inner + '\\\\n';\n }\n return listIndent() + '- ' + inner + '\\\\n';\n }\n\n // ── Blockquote ──\n case 'blockquote': {\n const inner = childContent().trim();\n if (!inner) return '';\n return '\\\\n\\\\n' + inner.split('\\\\n').map(line => '> ' + line).join('\\\\n') + '\\\\n\\\\n';\n }\n\n // ── Tables ──\n case 'table': {\n inTable = true;\n let out = '\\\\n\\\\n';\n const rows = el.querySelectorAll('tr');\n let headerDone = false;\n\n for (let i = 0; i < rows.length; i++) {\n const cells = rows[i].querySelectorAll('th, td');\n const isHeader = rows[i].querySelector('th') !== null;\n const cellTexts = [];\n for (const cell of cells) {\n let cellText = '';\n for (const c of cell.childNodes) cellText += walk(c);\n cellTexts.push(cellText.trim().replace(/\\\\|/g, '\\\\\\\\|').replace(/\\\\n/g, ' '));\n }\n\n out += '| ' + cellTexts.join(' | ') + ' |\\\\n';\n\n if (isHeader && !headerDone) {\n out += '| ' + cellTexts.map(() => '---').join(' | ') + ' |\\\\n';\n headerDone = true;\n }\n\n // First data row without headers — synthesize separator\n if (i === 0 && !isHeader && !headerDone) {\n out += '| ' + cellTexts.map(() => '---').join(' | ') + ' |\\\\n';\n headerDone = true;\n }\n }\n\n inTable = false;\n return out + '\\\\n';\n }\n case 'thead': case 'tbody': case 'tfoot':\n return childContent();\n case 'tr': case 'td': case 'th':\n // Handled by table walker above; fallback for orphaned elements\n return childContent();\n\n // ── Definition lists ──\n case 'dl': return '\\\\n\\\\n' + childContent() + '\\\\n\\\\n';\n case 'dt': return '\\\\n**' + childContent().trim() + '**\\\\n';\n case 'dd': return ': ' + childContent().trim() + '\\\\n';\n\n // ── Figure ──\n case 'figure': return '\\\\n\\\\n' + childContent().trim() + '\\\\n\\\\n';\n case 'figcaption': return '\\\\n*' + childContent().trim() + '*\\\\n';\n\n // ── Details/Summary ──\n case 'details': return '\\\\n\\\\n' + childContent() + '\\\\n\\\\n';\n case 'summary': return '**' + childContent().trim() + '**\\\\n\\\\n';\n\n // ── Generic blocks ──\n case 'div': case 'section': case 'article': case 'main': case 'aside':\n case 'header': case 'footer': case 'nav':\n return '\\\\n' + childContent() + '\\\\n';\n\n case 'span': case 'small': case 'sub': case 'sup': case 'abbr':\n case 'time': case 'mark': case 'cite': case 'q':\n return childContent();\n\n default:\n return childContent();\n }\n }\n\n const raw = walk(document.body);\n // Clean up: collapse 3+ newlines to 2, trim\n return raw.replace(/\\\\n{3,}/g, '\\\\n\\\\n').replace(/^\\\\n+|\\\\n+$/g, '').trim();\n})()\n`;\n","/**\n * Form state extraction — runs inside the browser.\n *\n * Extracts all form fields (including orphan fields not in <form> tags),\n * their types, labels, values, required/disabled state.\n *\n * Based on OpenCLI's getFormStateJs() pattern.\n */\nexport const FORM_STATE_SCRIPT = `\n(() => {\n function extractField(el) {\n const tag = el.tagName.toLowerCase();\n const type = (el.getAttribute('type') || tag).toLowerCase();\n\n // Skip non-user-facing inputs\n if (['hidden', 'submit', 'button', 'reset', 'image'].includes(type)) return null;\n\n const name = el.name || el.id || '';\n\n // Find label via multiple strategies\n const label =\n el.getAttribute('aria-label') ||\n (el.id ? document.querySelector('label[for=\"' + el.id + '\"]')?.textContent?.trim() : null) ||\n el.closest('label')?.textContent?.trim() ||\n el.placeholder ||\n '';\n\n // Extract value based on type\n let value;\n if (tag === 'select') {\n const selected = el.options[el.selectedIndex];\n value = selected ? selected.textContent.trim() : '';\n } else if (type === 'checkbox' || type === 'radio') {\n value = el.checked;\n } else if (type === 'password') {\n value = el.value ? '••••' : '';\n } else if (el.isContentEditable) {\n value = el.textContent?.trim()?.slice(0, 200) || '';\n } else {\n value = el.value || '';\n }\n\n return {\n tag,\n type,\n name,\n label: label.slice(0, 80),\n value: typeof value === 'string' ? value.slice(0, 200) : value,\n required: !!el.required,\n disabled: !!el.disabled,\n ref: el.dataset?.ref || null,\n };\n }\n\n const result = { forms: [], orphanFields: [] };\n\n // Collect forms\n for (const form of document.forms) {\n const fields = [];\n for (const el of form.elements) {\n const field = extractField(el);\n if (field) fields.push(field);\n }\n result.forms.push({\n id: form.id || '',\n name: form.name || '',\n action: form.action || '',\n method: (form.method || 'get').toUpperCase(),\n fields,\n });\n }\n\n // Collect orphan fields (not in a <form>)\n const allInputs = document.querySelectorAll(\n 'input, textarea, select, [contenteditable=\"true\"]'\n );\n for (const el of allInputs) {\n if (!el.form) {\n const field = extractField(el);\n if (field) result.orphanFields.push(field);\n }\n }\n\n return result;\n})()\n`;\n","/**\n * Interactive element classification — identifies what's clickable/editable.\n * Based on Lightpanda's InteractivityType approach.\n */\nexport const INTERACTIVE_ELEMENTS_SCRIPT = `\n(() => {\n const results = [];\n\n function classify(el) {\n const tag = el.tagName.toLowerCase();\n const role = el.getAttribute('role');\n const types = [];\n\n // Native interactive\n if (['a', 'button', 'input', 'select', 'textarea', 'details', 'summary'].includes(tag)) {\n types.push('native');\n }\n\n // ARIA role interactive\n if (role && ['button', 'link', 'textbox', 'checkbox', 'radio', 'combobox', 'tab', 'switch', 'menuitem', 'slider'].includes(role)) {\n types.push('aria');\n }\n\n // Contenteditable\n if (el.contentEditable === 'true') types.push('contenteditable');\n\n // Focusable\n if (el.tabIndex >= 0 && el.getAttribute('tabindex') !== null) types.push('focusable');\n\n // Has click listener (approximate)\n if (el.onclick) types.push('listener');\n\n return types;\n }\n\n let idx = 0;\n const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let node;\n while (node = walker.nextNode()) {\n const types = classify(node);\n if (types.length === 0) continue;\n\n const style = getComputedStyle(node);\n if (style.display === 'none' || style.visibility === 'hidden') continue;\n\n const rect = node.getBoundingClientRect();\n results.push({\n index: idx++,\n tag: node.tagName.toLowerCase(),\n role: node.getAttribute('role') || '',\n text: (node.textContent || '').trim().slice(0, 100),\n types,\n ariaLabel: node.getAttribute('aria-label') || '',\n rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n });\n }\n\n return results;\n})()\n`;\n","/**\n * Network interceptor script — patches fetch and XHR to capture responses.\n * Based on OpenCLI's interception approach.\n */\nexport function buildInterceptorScript(pattern: string): string {\n return `\n(() => {\n if (window.__lobster_interceptor__) return;\n window.__lobster_interceptor__ = { requests: [] };\n const store = window.__lobster_interceptor__;\n const pattern = ${JSON.stringify(pattern)};\n\n // Patch fetch\n const origFetch = window.fetch;\n window.fetch = async function(...args) {\n const url = typeof args[0] === 'string' ? args[0] : args[0]?.url || '';\n const resp = await origFetch.apply(this, args);\n if (url.includes(pattern)) {\n const clone = resp.clone();\n try {\n const body = await clone.json();\n store.requests.push({ url, method: 'GET', status: resp.status, body, timestamp: Date.now() });\n } catch {}\n }\n return resp;\n };\n\n // Patch XHR\n const origOpen = XMLHttpRequest.prototype.open;\n const origSend = XMLHttpRequest.prototype.send;\n XMLHttpRequest.prototype.open = function(method, url, ...rest) {\n this.__url = url;\n this.__method = method;\n return origOpen.call(this, method, url, ...rest);\n };\n XMLHttpRequest.prototype.send = function(...args) {\n this.addEventListener('load', function() {\n if (this.__url && this.__url.includes(pattern)) {\n try {\n const body = JSON.parse(this.responseText);\n store.requests.push({ url: this.__url, method: this.__method, status: this.status, body, timestamp: Date.now() });\n } catch {}\n }\n });\n return origSend.apply(this, args);\n };\n})()\n`;\n}\n\nexport const GET_INTERCEPTED_SCRIPT = `\n(() => {\n const store = window.__lobster_interceptor__;\n if (!store) return [];\n const reqs = [...store.requests];\n store.requests = [];\n return reqs;\n})()\n`;\n","/**\n * Semantic Element Finding — match elements by natural language.\n *\n * Uses Jaccard similarity with synonym expansion, role boost,\n * and prefix matching. Zero external dependencies — runs in Node.\n *\n * Inspired by PinchTab's hybrid lexical+embedding matcher, built from scratch.\n */\n\nexport interface FindMatch {\n ref: number;\n score: number;\n text: string;\n role: string;\n tag: string;\n}\n\nexport interface FindOptions {\n maxResults?: number; // default 5\n minScore?: number; // default 0.3\n}\n\ninterface InteractiveElement {\n index: number;\n tag: string;\n role: string;\n text: string;\n types: string[];\n ariaLabel: string;\n}\n\n// ── Synonym table ──\nconst SYNONYMS: Record<string, string[]> = {\n btn: ['button'],\n button: ['btn', 'submit', 'click'],\n submit: ['go', 'send', 'ok', 'confirm', 'done', 'button'],\n search: ['find', 'lookup', 'query', 'filter'],\n login: ['signin', 'sign-in', 'log-in', 'authenticate'],\n signup: ['register', 'create-account', 'sign-up', 'join'],\n logout: ['signout', 'sign-out', 'log-out'],\n close: ['dismiss', 'x', 'cancel', 'exit'],\n menu: ['nav', 'navigation', 'hamburger', 'sidebar'],\n nav: ['navigation', 'menu', 'navbar'],\n input: ['field', 'textbox', 'text', 'entry'],\n email: ['mail', 'e-mail'],\n password: ['pass', 'pwd', 'secret'],\n next: ['continue', 'forward', 'proceed'],\n back: ['previous', 'return', 'go-back'],\n save: ['store', 'keep', 'persist'],\n delete: ['remove', 'trash', 'discard', 'destroy'],\n edit: ['modify', 'change', 'update'],\n add: ['create', 'new', 'plus', 'insert'],\n settings: ['preferences', 'config', 'options', 'gear'],\n profile: ['account', 'user', 'avatar'],\n home: ['main', 'dashboard', 'start'],\n link: ['anchor', 'href', 'url'],\n select: ['dropdown', 'combo', 'picker', 'choose'],\n checkbox: ['check', 'toggle', 'tick'],\n upload: ['attach', 'file', 'browse'],\n download: ['save', 'export'],\n};\n\n// ── Role keywords that boost score ──\nconst ROLE_KEYWORDS = new Set([\n 'button', 'link', 'input', 'textbox', 'checkbox', 'radio',\n 'select', 'dropdown', 'tab', 'menu', 'menuitem', 'switch',\n 'slider', 'combobox', 'searchbox', 'option',\n]);\n\n/**\n * Tokenize a string into lowercase words.\n */\nfunction tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, ' ')\n .split(/[\\s-]+/)\n .filter((t) => t.length > 0);\n}\n\n/**\n * Expand tokens with synonyms.\n */\nfunction expandSynonyms(tokens: string[]): Set<string> {\n const expanded = new Set(tokens);\n for (const token of tokens) {\n const syns = SYNONYMS[token];\n if (syns) {\n for (const syn of syns) expanded.add(syn);\n }\n }\n return expanded;\n}\n\n/**\n * Build frequency map.\n */\nfunction freqMap(tokens: string[]): Map<string, number> {\n const map = new Map<string, number>();\n for (const t of tokens) {\n map.set(t, (map.get(t) || 0) + 1);\n }\n return map;\n}\n\n/**\n * Jaccard similarity with frequency weighting.\n */\nfunction jaccardScore(queryTokens: string[], descTokens: string[]): number {\n const qFreq = freqMap(queryTokens);\n const dFreq = freqMap(descTokens);\n\n let intersection = 0;\n let union = 0;\n\n const allTokens = new Set([...qFreq.keys(), ...dFreq.keys()]);\n for (const token of allTokens) {\n const qCount = qFreq.get(token) || 0;\n const dCount = dFreq.get(token) || 0;\n intersection += Math.min(qCount, dCount);\n union += Math.max(qCount, dCount);\n }\n\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Prefix matching score — handles abbreviations.\n * \"btn\" matches \"button\" partially.\n */\nfunction prefixScore(queryTokens: string[], descTokens: string[]): number {\n if (queryTokens.length === 0 || descTokens.length === 0) return 0;\n\n let matches = 0;\n for (const qt of queryTokens) {\n if (qt.length < 3) continue;\n for (const dt of descTokens) {\n if (dt.startsWith(qt) || qt.startsWith(dt)) {\n matches += 0.5;\n break;\n }\n }\n }\n\n return Math.min(matches / queryTokens.length, 0.3);\n}\n\n/**\n * Role keyword boost — if query mentions a role and element matches.\n */\nfunction roleBoost(queryTokens: string[], elementRole: string): number {\n const roleLower = elementRole.toLowerCase();\n for (const qt of queryTokens) {\n if (ROLE_KEYWORDS.has(qt) && roleLower.includes(qt)) {\n return 0.2;\n }\n }\n return 0;\n}\n\n/**\n * Score a single element against the query.\n */\nfunction scoreElement(\n queryTokens: string[],\n queryExpanded: Set<string>,\n element: InteractiveElement,\n): number {\n // Build description from all element text sources\n const descParts = [\n element.text,\n element.role,\n element.tag,\n element.ariaLabel,\n ].filter(Boolean);\n const descText = descParts.join(' ');\n const descTokens = tokenize(descText);\n\n if (descTokens.length === 0) return 0;\n\n // Expand description tokens too\n const descExpanded = expandSynonyms(descTokens);\n\n // 1. Jaccard similarity on expanded token sets\n const expandedQueryTokens = [...queryExpanded];\n const expandedDescTokens = [...descExpanded];\n const jaccard = jaccardScore(expandedQueryTokens, expandedDescTokens);\n\n // 2. Prefix matching\n const prefix = prefixScore(queryTokens, descTokens);\n\n // 3. Role keyword boost\n const role = roleBoost(queryTokens, element.role || element.tag);\n\n // 4. Exact substring match bonus\n const queryStr = queryTokens.join(' ');\n const descStr = descTokens.join(' ');\n const exactBonus = descStr.includes(queryStr) ? 0.3 : 0;\n\n return Math.min(jaccard + prefix + role + exactBonus, 1.0);\n}\n\n/**\n * Find elements matching a natural language query.\n *\n * @param elements - Interactive elements from INTERACTIVE_ELEMENTS_SCRIPT\n * @param query - Natural language description (e.g., \"login button\")\n * @param options - maxResults (default 5), minScore (default 0.3)\n */\nexport function semanticFind(\n elements: InteractiveElement[],\n query: string,\n options?: FindOptions,\n): FindMatch[] {\n const maxResults = options?.maxResults ?? 5;\n const minScore = options?.minScore ?? 0.3;\n\n const queryTokens = tokenize(query);\n if (queryTokens.length === 0) return [];\n\n const queryExpanded = expandSynonyms(queryTokens);\n\n const scored: FindMatch[] = [];\n\n for (const el of elements) {\n const score = scoreElement(queryTokens, queryExpanded, el);\n if (score >= minScore) {\n scored.push({\n ref: el.index,\n score: Math.round(score * 100) / 100,\n text: (el.text || el.ariaLabel || '').slice(0, 60),\n role: el.role || el.tag,\n tag: el.tag,\n });\n }\n }\n\n scored.sort((a, b) => b.score - a.score);\n return scored.slice(0, maxResults);\n}\n","import type { Page } from 'puppeteer-core';\nimport type {\n IPage, WaitCondition, Cookie, NetworkEntry, TabInfo,\n SnapshotOptions, SemanticTreeOptions, FlatDomTree, BrowserState, FormState,\n FindMatch, FindOptions,\n} from '../types/page.js';\nimport { FLAT_TREE_SCRIPT, flatTreeToString } from './dom/flat-tree.js';\nimport { SNAPSHOT_SCRIPT } from './dom/snapshot.js';\nimport { COMPACT_SNAPSHOT_SCRIPT } from './dom/compact-snapshot.js';\nimport { SEMANTIC_TREE_SCRIPT } from './dom/semantic-tree.js';\nimport { MARKDOWN_SCRIPT } from './dom/markdown.js';\nimport { FORM_STATE_SCRIPT } from './dom/form-state.js';\nimport { INTERACTIVE_ELEMENTS_SCRIPT } from './dom/interactive.js';\nimport { buildInterceptorScript, GET_INTERCEPTED_SCRIPT } from './interceptor.js';\nimport { semanticFind } from './semantic-find.js';\n\nexport class PuppeteerPage implements IPage {\n private page: Page;\n\n constructor(page: Page) {\n this.page = page;\n }\n\n get raw(): Page { return this.page; }\n\n async goto(url: string, options?: { waitUntil?: WaitCondition; timeout?: number }): Promise<void> {\n await this.page.goto(url, {\n waitUntil: (options?.waitUntil as any) || 'networkidle2',\n timeout: options?.timeout || 30000,\n });\n }\n\n async goBack(): Promise<void> {\n await this.page.goBack({ waitUntil: 'networkidle2' });\n }\n\n async url(): Promise<string> {\n return this.page.url();\n }\n\n async title(): Promise<string> {\n return this.page.title();\n }\n\n async evaluate<T = unknown>(js: string): Promise<T> {\n return this.page.evaluate(js) as Promise<T>;\n }\n\n async snapshot(opts?: SnapshotOptions): Promise<string> {\n if (opts?.compact) {\n return this.page.evaluate(COMPACT_SNAPSHOT_SCRIPT) as Promise<string>;\n }\n return this.page.evaluate(SNAPSHOT_SCRIPT) as Promise<string>;\n }\n\n async semanticTree(_opts?: SemanticTreeOptions): Promise<string> {\n return this.page.evaluate(SEMANTIC_TREE_SCRIPT) as Promise<string>;\n }\n\n async flatTree(): Promise<FlatDomTree> {\n const raw = await this.page.evaluate(FLAT_TREE_SCRIPT);\n return raw as FlatDomTree;\n }\n\n async markdown(): Promise<string> {\n return this.page.evaluate(MARKDOWN_SCRIPT) as Promise<string>;\n }\n\n async browserState(): Promise<BrowserState> {\n const state = await this.page.evaluate(`\n (() => {\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n const vpW = window.innerWidth;\n const vpH = window.innerHeight;\n const pageW = document.documentElement.scrollWidth;\n const pageH = document.documentElement.scrollHeight;\n const maxScrollY = pageH - vpH;\n return {\n url: location.href,\n title: document.title,\n viewportWidth: vpW,\n viewportHeight: vpH,\n pageWidth: pageW,\n pageHeight: pageH,\n scrollX: scrollX,\n scrollY: scrollY,\n scrollPercent: maxScrollY > 0 ? Math.round((scrollY / maxScrollY) * 100) : 0,\n pixelsAbove: Math.round(scrollY),\n pixelsBelow: Math.round(Math.max(0, maxScrollY - scrollY)),\n };\n })()\n `) as BrowserState;\n return state;\n }\n\n async formState(): Promise<FormState> {\n return this.page.evaluate(FORM_STATE_SCRIPT) as Promise<FormState>;\n }\n\n async click(ref: string | number): Promise<void> {\n if (typeof ref === 'number') {\n await this.page.evaluate((idx) => {\n const el = document.querySelector('[data-ref=\"' + idx + '\"]') as HTMLElement;\n if (!el) throw new Error('Element with index ' + idx + ' not found');\n\n // Blur previously focused element\n const prev = document.activeElement as HTMLElement | null;\n if (prev && prev !== el && prev !== document.body) {\n prev.blur();\n prev.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, cancelable: true }));\n prev.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false, cancelable: true }));\n }\n\n // Scroll into view\n if (typeof (el as any).scrollIntoViewIfNeeded === 'function') {\n (el as any).scrollIntoViewIfNeeded();\n } else {\n el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' });\n }\n\n // Full mouse event sequence — required for React, analytics, custom handlers\n el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));\n el.focus();\n el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true }));\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));\n }, ref);\n // Wait for click processing (animations, state updates)\n await new Promise((r) => setTimeout(r, 200));\n } else {\n await this.page.click(ref);\n }\n }\n\n async typeText(ref: string | number, text: string): Promise<void> {\n if (typeof ref === 'number') {\n // First click the element (triggers full event sequence + focus)\n await this.click(ref);\n\n await this.page.evaluate((idx, txt) => {\n const el = document.querySelector('[data-ref=\"' + idx + '\"]') as HTMLElement;\n if (!el) throw new Error('Element with index ' + idx + ' not found');\n\n const isInput = el.tagName === 'INPUT' || el.tagName === 'TEXTAREA';\n const isContentEditable = el.isContentEditable;\n\n if (isContentEditable) {\n // ── Contenteditable: Plan A — synthetic InputEvents ──\n // Works for: React contenteditable, Quill\n // Clear existing content\n if (el.dispatchEvent(new InputEvent('beforeinput', {\n bubbles: true, cancelable: true, inputType: 'deleteContent',\n }))) {\n el.innerText = '';\n el.dispatchEvent(new InputEvent('input', {\n bubbles: true, inputType: 'deleteContent',\n }));\n }\n\n // Insert new text\n if (el.dispatchEvent(new InputEvent('beforeinput', {\n bubbles: true, cancelable: true, inputType: 'insertText', data: txt,\n }))) {\n el.innerText = txt;\n el.dispatchEvent(new InputEvent('input', {\n bubbles: true, inputType: 'insertText', data: txt,\n }));\n }\n\n // Verify Plan A worked\n const planAOk = el.innerText.trim() === txt.trim();\n\n if (!planAOk) {\n // ── Plan B — execCommand fallback ──\n // Works for: Slate.js, some rich-text editors\n el.focus();\n const doc = el.ownerDocument;\n const sel = (doc.defaultView || window).getSelection();\n const range = doc.createRange();\n range.selectNodeContents(el);\n sel?.removeAllRanges();\n sel?.addRange(range);\n doc.execCommand('delete', false);\n doc.execCommand('insertText', false, txt);\n }\n\n el.dispatchEvent(new Event('change', { bubbles: true }));\n el.blur();\n\n } else if (isInput) {\n // ── Input/Textarea: use native value setter to bypass React/Vue ──\n const inputEl = el as HTMLInputElement | HTMLTextAreaElement;\n const proto = Object.getPrototypeOf(inputEl);\n const descriptor =\n Object.getOwnPropertyDescriptor(proto, 'value') ||\n Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value') ||\n Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n\n if (descriptor?.set) {\n descriptor.set.call(inputEl, txt);\n } else {\n inputEl.value = txt;\n }\n\n inputEl.dispatchEvent(new Event('input', { bubbles: true }));\n inputEl.dispatchEvent(new Event('change', { bubbles: true }));\n } else {\n // Fallback: try setting value anyway\n (el as any).value = txt;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }, ref, text);\n } else {\n // CSS selector path — click to focus, then use keyboard\n await this.page.click(ref, { count: 3 });\n await this.page.keyboard.type(text);\n }\n }\n\n async pressKey(key: string): Promise<void> {\n await this.page.keyboard.press(key as any);\n }\n\n async selectOption(ref: string | number, value: string): Promise<void> {\n const selector = typeof ref === 'number' ? '[data-ref=\"' + ref + '\"]' : ref;\n await this.page.select(selector, value);\n }\n\n async scroll(direction: 'up' | 'down' | 'left' | 'right', amount?: number): Promise<void> {\n const distance = amount || 500;\n const isVertical = direction === 'up' || direction === 'down';\n const positive = direction === 'down' || direction === 'right';\n const delta = positive ? distance : -distance;\n\n await this.page.evaluate((dy, dx, isVert) => {\n // Helper: check if element is a valid scroll container\n const canScroll = (el) => {\n if (!el) return false;\n const s = getComputedStyle(el);\n if (isVert) {\n return /(auto|scroll|overlay)/.test(s.overflowY) &&\n el.scrollHeight > el.clientHeight &&\n el.clientHeight >= window.innerHeight * 0.3;\n } else {\n return /(auto|scroll|overlay)/.test(s.overflowX) &&\n el.scrollWidth > el.clientWidth &&\n el.clientWidth >= window.innerWidth * 0.3;\n }\n };\n\n // Walk from active element up to find a scrollable container\n let el = document.activeElement;\n while (el && !canScroll(el) && el !== document.body) {\n el = el.parentElement;\n }\n\n // If no scrollable ancestor, search the DOM\n if (!canScroll(el)) {\n el = Array.from(document.querySelectorAll('*')).find(canScroll) || null;\n }\n\n const isPageLevel = !el || el === document.body ||\n el === document.documentElement || el === document.scrollingElement;\n\n if (isPageLevel) {\n // Page-level scroll\n if (isVert) {\n window.scrollBy(0, dy);\n } else {\n window.scrollBy(dx, 0);\n }\n } else {\n // Container scroll\n if (isVert) {\n el.scrollBy({ top: dy, behavior: 'smooth' });\n } else {\n el.scrollBy({ left: dx, behavior: 'smooth' });\n }\n }\n }, isVertical ? delta : 0, isVertical ? 0 : delta, isVertical);\n\n // Wait for smooth scroll to settle\n await new Promise((r) => setTimeout(r, 150));\n }\n\n async scrollToElement(ref: string | number): Promise<void> {\n const selector = typeof ref === 'number' ? '[data-ref=\"' + ref + '\"]' : ref;\n await this.page.evaluate((sel) => {\n const el = document.querySelector(sel);\n if (!el) return;\n if (typeof (el as any).scrollIntoViewIfNeeded === 'function') {\n (el as any).scrollIntoViewIfNeeded();\n } else {\n el.scrollIntoView({ behavior: 'auto', block: 'center', inline: 'nearest' });\n }\n }, selector);\n }\n\n async getCookies(opts?: { domain?: string }): Promise<Cookie[]> {\n const cookies = await this.page.cookies();\n const filtered = opts?.domain\n ? cookies.filter((c) => c.domain.includes(opts.domain!))\n : cookies;\n return filtered.map((c) => ({\n name: c.name,\n value: c.value,\n domain: c.domain,\n path: c.path,\n expires: c.expires,\n httpOnly: c.httpOnly,\n secure: c.secure,\n sameSite: c.sameSite as Cookie['sameSite'],\n }));\n }\n\n async wait(options: number | { text?: string; time?: number; timeout?: number }): Promise<void> {\n if (typeof options === 'number') {\n await new Promise((r) => setTimeout(r, options * 1000));\n return;\n }\n if (options.time) {\n await new Promise((r) => setTimeout(r, options.time! * 1000));\n }\n if (options.text) {\n await this.page.waitForFunction(\n (t) => document.body.innerText.includes(t),\n { timeout: options.timeout || 30000 },\n options.text\n );\n }\n }\n\n async networkRequests(includeStatic?: boolean): Promise<NetworkEntry[]> {\n // Use Performance API to extract network requests from the browser\n const entries = await this.page.evaluate(`\n (() => {\n const entries = performance.getEntriesByType('resource');\n const staticTypes = new Set(['img', 'font', 'css', 'script', 'link']);\n const includeStatic = ${!!includeStatic};\n\n return entries\n .filter(e => includeStatic || !staticTypes.has(e.initiatorType))\n .map(e => ({\n url: e.name,\n method: 'GET',\n status: 200,\n type: e.initiatorType || 'other',\n size: e.transferSize || e.encodedBodySize || 0,\n duration: Math.round(e.duration),\n }));\n })()\n `) as NetworkEntry[];\n return entries || [];\n }\n\n async installInterceptor(pattern: string): Promise<void> {\n await this.page.evaluate(buildInterceptorScript(pattern));\n }\n\n async getInterceptedRequests(): Promise<unknown[]> {\n return this.page.evaluate(GET_INTERCEPTED_SCRIPT) as Promise<unknown[]>;\n }\n\n async screenshot(opts?: { format?: 'png' | 'jpeg'; fullPage?: boolean }): Promise<Buffer> {\n const result = await this.page.screenshot({\n type: opts?.format || 'png',\n fullPage: opts?.fullPage ?? false,\n });\n return Buffer.from(result);\n }\n\n async tabs(): Promise<TabInfo[]> {\n const browser = this.page.browser();\n const pages = await browser.pages();\n return pages.map((p, i) => ({\n id: i,\n url: p.url(),\n title: '',\n active: p === this.page,\n }));\n }\n\n async find(query: string, options?: FindOptions): Promise<FindMatch[]> {\n const elements = await this.page.evaluate(INTERACTIVE_ELEMENTS_SCRIPT) as any[];\n return semanticFind(elements, query, options);\n }\n\n async close(): Promise<void> {\n await this.page.close();\n }\n}\n","/**\n * LobsterEngine — In-house lightweight HTML parser + content extractor.\n *\n * No Chrome, no external binary. Pure Node.js.\n * Fetches HTML via HTTP, parses into a DOM tree, extracts content\n * as markdown, text, links, or structured snapshot.\n *\n * Inspired by Lightpanda's approach but 100% our code.\n * Works for server-rendered pages. For JS-heavy SPAs, use Chrome engine.\n */\n\n// ── HTML Node types ──\n\nexport interface HtmlNode {\n type: 'element' | 'text' | 'comment';\n tag?: string;\n attributes?: Record<string, string>;\n children?: HtmlNode[];\n text?: string;\n selfClosing?: boolean;\n}\n\n// ── HTML Parser ──\n\nconst SELF_CLOSING = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'param', 'source', 'track', 'wbr',\n]);\n\nconst RAWTEXT_TAGS = new Set(['script', 'style', 'textarea', 'title']);\n\n/**\n * Parse HTML string into a tree of HtmlNodes.\n * Handles: tags, attributes, self-closing, rawtext, comments, entities.\n */\nexport function parseHtml(html: string): HtmlNode[] {\n const root: HtmlNode[] = [];\n const stack: { node: HtmlNode; children: HtmlNode[] }[] = [{ node: { type: 'element', tag: 'root', children: root }, children: root }];\n let pos = 0;\n\n function current() { return stack[stack.length - 1]; }\n\n function addText(text: string) {\n if (!text) return;\n const decoded = decodeEntities(text);\n if (decoded.trim() || decoded.includes('\\n')) {\n current().children.push({ type: 'text', text: decoded });\n }\n }\n\n while (pos < html.length) {\n const nextTag = html.indexOf('<', pos);\n\n if (nextTag === -1) {\n addText(html.slice(pos));\n break;\n }\n\n if (nextTag > pos) {\n addText(html.slice(pos, nextTag));\n }\n\n // Comment\n if (html.startsWith('<!--', nextTag)) {\n const endComment = html.indexOf('-->', nextTag + 4);\n pos = endComment === -1 ? html.length : endComment + 3;\n continue;\n }\n\n // Doctype\n if (html.startsWith('<!', nextTag) || html.startsWith('<?', nextTag)) {\n const endDoctype = html.indexOf('>', nextTag);\n pos = endDoctype === -1 ? html.length : endDoctype + 1;\n continue;\n }\n\n // Closing tag\n if (html[nextTag + 1] === '/') {\n const endClose = html.indexOf('>', nextTag);\n if (endClose === -1) { pos = html.length; break; }\n const closeTag = html.slice(nextTag + 2, endClose).trim().toLowerCase();\n pos = endClose + 1;\n\n // Pop stack until we find matching tag\n for (let i = stack.length - 1; i > 0; i--) {\n if (stack[i].node.tag === closeTag) {\n stack.length = i;\n break;\n }\n }\n continue;\n }\n\n // Opening tag\n const tagEnd = html.indexOf('>', nextTag);\n if (tagEnd === -1) { pos = html.length; break; }\n\n const tagContent = html.slice(nextTag + 1, tagEnd);\n const selfClose = tagContent.endsWith('/');\n const cleanContent = selfClose ? tagContent.slice(0, -1).trim() : tagContent.trim();\n\n // Parse tag name and attributes\n const spaceIdx = cleanContent.search(/[\\s/]/);\n const tagName = (spaceIdx === -1 ? cleanContent : cleanContent.slice(0, spaceIdx)).toLowerCase();\n const attrStr = spaceIdx === -1 ? '' : cleanContent.slice(spaceIdx);\n\n if (!tagName || tagName.startsWith('!')) {\n pos = tagEnd + 1;\n continue;\n }\n\n const attributes = parseAttributes(attrStr);\n const isSelfClosing = selfClose || SELF_CLOSING.has(tagName);\n\n const node: HtmlNode = {\n type: 'element',\n tag: tagName,\n attributes,\n children: isSelfClosing ? undefined : [],\n selfClosing: isSelfClosing,\n };\n\n current().children.push(node);\n pos = tagEnd + 1;\n\n if (isSelfClosing) continue;\n\n // Raw text tags (script, style) — consume until closing tag\n if (RAWTEXT_TAGS.has(tagName)) {\n const endRaw = html.toLowerCase().indexOf(`</${tagName}`, pos);\n if (endRaw !== -1) {\n const rawText = html.slice(pos, endRaw);\n if (rawText.trim()) {\n node.children!.push({ type: 'text', text: rawText });\n }\n pos = html.indexOf('>', endRaw) + 1;\n }\n continue;\n }\n\n // Push onto stack for children\n stack.push({ node, children: node.children! });\n\n // Auto-close certain tags\n if (tagName === 'p' || tagName === 'li' || tagName === 'td' || tagName === 'th' || tagName === 'dt' || tagName === 'dd') {\n // Check if parent is same tag — auto-close\n if (stack.length >= 3 && stack[stack.length - 2].node.tag === tagName) {\n stack.splice(stack.length - 2, 1);\n }\n }\n }\n\n return root;\n}\n\nfunction parseAttributes(str: string): Record<string, string> {\n const attrs: Record<string, string> = {};\n const re = /(\\w[\\w-]*)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|(\\S+)))?/g;\n let m;\n while ((m = re.exec(str)) !== null) {\n attrs[m[1].toLowerCase()] = decodeEntities(m[2] ?? m[3] ?? m[4] ?? '');\n }\n return attrs;\n}\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&apos;/g, \"'\")\n .replace(/&nbsp;/g, ' ')\n .replace(/&#(\\d+);/g, (_, n) => String.fromCharCode(parseInt(n)))\n .replace(/&#x([0-9a-fA-F]+);/g, (_, n) => String.fromCharCode(parseInt(n, 16)));\n}\n\n// ── Content Extractors ──\n\nconst SKIP_TAGS = new Set(['script', 'style', 'noscript', 'svg', 'head', 'template', 'iframe']);\nconst BLOCK_TAGS = new Set(['div', 'p', 'section', 'article', 'main', 'aside', 'blockquote', 'pre', 'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'br', 'hr', 'figure', 'figcaption', 'details', 'summary', 'dl', 'dt', 'dd', 'header', 'footer', 'nav', 'form']);\nconst HEADING_LEVELS: Record<string, string> = { h1: '#', h2: '##', h3: '###', h4: '####', h5: '#####', h6: '######' };\n\nconst INTERACTIVE_TAGS = new Set(['a', 'button', 'input', 'select', 'textarea', 'details', 'summary']);\nconst INTERACTIVE_ROLES = new Set(['button', 'link', 'textbox', 'checkbox', 'radio', 'combobox', 'tab', 'switch', 'menuitem']);\n\n/**\n * Extract plain text from parsed HTML.\n */\nexport function extractText(nodes: HtmlNode[]): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n out += node.text;\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const inner = node.children ? extractText(node.children) : '';\n if (BLOCK_TAGS.has(node.tag)) {\n out += '\\n' + inner.trim() + '\\n';\n } else {\n out += inner;\n }\n }\n return out.replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Extract Markdown from parsed HTML.\n */\nexport function extractMarkdown(nodes: HtmlNode[], baseUrl?: string): string {\n let listDepth = 0;\n let olCounter: number[] = [];\n\n function resolveUrl(href: string): string {\n if (!href || href.startsWith('javascript:') || href.startsWith('#')) return href;\n if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('//')) return href;\n if (baseUrl) {\n try { return new URL(href, baseUrl).href; } catch {}\n }\n return href;\n }\n\n function walk(nodes: HtmlNode[]): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n out += node.text?.replace(/\\s+/g, ' ') || '';\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const tag = node.tag;\n const children = node.children || [];\n const inner = walk(children).trim();\n\n // Headings\n if (HEADING_LEVELS[tag]) {\n out += `\\n\\n${HEADING_LEVELS[tag]} ${inner}\\n\\n`;\n continue;\n }\n\n switch (tag) {\n case 'p': out += `\\n\\n${inner}\\n\\n`; break;\n case 'br': out += '\\n'; break;\n case 'hr': out += '\\n\\n---\\n\\n'; break;\n case 'strong': case 'b': if (inner) out += `**${inner}**`; break;\n case 'em': case 'i': if (inner) out += `*${inner}*`; break;\n case 's': case 'del': case 'strike': if (inner) out += `~~${inner}~~`; break;\n case 'code': if (inner) out += `\\`${inner}\\``; break;\n case 'pre': {\n const lang = children.find(c => c.tag === 'code')?.attributes?.class?.match(/language-(\\w+)/)?.[1] || '';\n out += `\\n\\n\\`\\`\\`${lang}\\n${inner}\\n\\`\\`\\`\\n\\n`;\n break;\n }\n case 'a': {\n const href = resolveUrl(node.attributes?.href || '');\n const text = inner || node.attributes?.['aria-label'] || node.attributes?.title || '';\n if (!text) break;\n if (!href || href === '#' || href.startsWith('javascript:')) { out += text; break; }\n out += `[${text}](${href})`;\n break;\n }\n case 'img': {\n const alt = node.attributes?.alt || '';\n const src = resolveUrl(node.attributes?.src || '');\n if (src) out += `![${alt}](${src})`;\n break;\n }\n case 'ul': listDepth++; olCounter.push(0); out += '\\n' + walk(children); listDepth--; olCounter.pop(); break;\n case 'ol': listDepth++; olCounter.push(0); out += '\\n' + walk(children); listDepth--; olCounter.pop(); break;\n case 'li': {\n const indent = ' '.repeat(Math.max(0, listDepth - 1));\n const isOrdered = olCounter.length > 0 && olCounter[olCounter.length - 1] >= 0;\n if (isOrdered && olCounter.length > 0) olCounter[olCounter.length - 1]++;\n const counter = isOrdered && olCounter.length > 0 ? olCounter[olCounter.length - 1] : 0;\n const bullet = isOrdered ? `${counter}. ` : '- ';\n out += `${indent}${bullet}${inner}\\n`;\n break;\n }\n case 'blockquote': {\n if (inner) out += '\\n\\n' + inner.split('\\n').map(l => `> ${l}`).join('\\n') + '\\n\\n';\n break;\n }\n case 'table': {\n // Collect rows\n const rows = collectTableRows(children);\n if (rows.length > 0) {\n out += '\\n\\n';\n for (let i = 0; i < rows.length; i++) {\n out += '| ' + rows[i].join(' | ') + ' |\\n';\n if (i === 0) out += '| ' + rows[i].map(() => '---').join(' | ') + ' |\\n';\n }\n out += '\\n';\n }\n break;\n }\n case 'dt': out += `\\n**${inner}**\\n`; break;\n case 'dd': out += `: ${inner}\\n`; break;\n case 'figcaption': out += `\\n*${inner}*\\n`; break;\n case 'summary': out += `**${inner}**\\n\\n`; break;\n default:\n if (BLOCK_TAGS.has(tag)) {\n out += '\\n' + walk(children) + '\\n';\n } else {\n out += walk(children);\n }\n }\n }\n return out;\n }\n\n function collectTableRows(nodes: HtmlNode[]): string[][] {\n const rows: string[][] = [];\n for (const node of nodes) {\n if (node.tag === 'tr') {\n const cells: string[] = [];\n for (const cell of node.children || []) {\n if (cell.tag === 'td' || cell.tag === 'th') {\n cells.push(walk(cell.children || []).trim().replace(/\\|/g, '\\\\|').replace(/\\n/g, ' '));\n }\n }\n if (cells.length > 0) rows.push(cells);\n } else if (node.tag === 'thead' || node.tag === 'tbody' || node.tag === 'tfoot') {\n rows.push(...collectTableRows(node.children || []));\n }\n }\n return rows;\n }\n\n const raw = walk(nodes);\n return raw.replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Extract a snapshot with interactive element indices.\n */\nexport function extractSnapshot(nodes: HtmlNode[]): string {\n let idx = 0;\n const ATTR_WHITELIST = ['type', 'role', 'aria-label', 'placeholder', 'href', 'value', 'name', 'alt'];\n\n function isInteractive(node: HtmlNode): boolean {\n if (!node.tag) return false;\n if (INTERACTIVE_TAGS.has(node.tag)) return true;\n const role = node.attributes?.role;\n if (role && INTERACTIVE_ROLES.has(role)) return true;\n if (node.attributes?.contenteditable === 'true') return true;\n if (node.attributes?.tabindex && parseInt(node.attributes.tabindex) >= 0) return true;\n return false;\n }\n\n function getAttrs(node: HtmlNode): string {\n const parts: string[] = [];\n for (const name of ATTR_WHITELIST) {\n const v = node.attributes?.[name];\n if (v) parts.push(`${name}=${v.slice(0, 60)}`);\n }\n return parts.length ? ' ' + parts.join(' ') : '';\n }\n\n function walk(nodes: HtmlNode[], depth: number): string {\n let out = '';\n for (const node of nodes) {\n if (node.type === 'text') {\n const t = node.text?.trim();\n if (t) out += ' '.repeat(depth) + t.slice(0, 150) + '\\n';\n continue;\n }\n if (node.type !== 'element' || !node.tag) continue;\n if (SKIP_TAGS.has(node.tag)) continue;\n\n const indent = ' '.repeat(depth);\n const inter = isInteractive(node);\n const prefix = inter ? `[${idx++}]` : '';\n const attrs = getAttrs(node);\n\n // Leaf text\n const leafText = node.children?.length === 1 && node.children[0].type === 'text'\n ? (node.children[0].text?.trim().slice(0, 150) || '') : '';\n\n if (inter || leafText || !node.children?.length) {\n if (leafText) {\n out += `${indent}${prefix}<${node.tag}${attrs}>${leafText}</${node.tag}>\\n`;\n } else {\n out += `${indent}${prefix}<${node.tag}${attrs}>\\n`;\n if (node.children) out += walk(node.children, depth + 1);\n }\n } else {\n if (node.children) out += walk(node.children, depth);\n }\n }\n return out;\n }\n\n return walk(nodes, 0);\n}\n\n/**\n * Extract links from parsed HTML.\n */\nexport function extractLinks(nodes: HtmlNode[], baseUrl?: string): { text: string; href: string }[] {\n const links: { text: string; href: string }[] = [];\n\n function walk(nodes: HtmlNode[]) {\n for (const node of nodes) {\n if (node.type === 'element' && node.tag === 'a' && node.attributes?.href) {\n let href = node.attributes.href;\n if (baseUrl && !href.startsWith('http')) {\n try { href = new URL(href, baseUrl).href; } catch {}\n }\n const text = extractText(node.children || []).trim();\n if (text && href && !href.startsWith('javascript:')) {\n links.push({ text: text.slice(0, 200), href });\n }\n }\n if (node.children) walk(node.children);\n }\n }\n\n walk(nodes);\n return links;\n}\n\n// ── Main fetch function (replaces Lightpanda binary) ──\n\nexport interface LobsterFetchResult {\n url: string;\n finalUrl: string;\n status?: number;\n statusCode?: number;\n title: string;\n content: string;\n links?: { text: string; href: string }[];\n engine?: string;\n duration: number;\n}\n\n/**\n * Fetch a URL and extract content — no Chrome, no external binary.\n * Uses our in-house HTML parser.\n */\nexport async function lobsterFetch(\n url: string,\n options?: {\n dump?: 'markdown' | 'text' | 'snapshot' | 'html' | 'links';\n timeout?: number;\n headers?: Record<string, string>;\n followRedirects?: boolean;\n },\n): Promise<LobsterFetchResult> {\n const timeout = options?.timeout || 30000;\n const dump = options?.dump || 'markdown';\n\n const start = Date.now();\n\n // ── PDF detection: check URL pattern first ──\n const { isPdfUrl, isPdfResponse, extractPdf } = await import('./pdf.js');\n\n if (isPdfUrl(url)) {\n const pdfResult = await extractPdf(url);\n const duration = Date.now() - start;\n let content: string;\n switch (dump) {\n case 'markdown': content = pdfResult.markdown; break;\n case 'text': content = pdfResult.text; break;\n case 'html': content = `<pre>${pdfResult.text}</pre>`; break;\n case 'snapshot': content = `[PDF] ${pdfResult.metadata.title} (${pdfResult.metadata.pages} pages, ${pdfResult.wordCount} words)\\n\\n${pdfResult.text.slice(0, 5000)}`; break;\n case 'links': content = ''; break;\n default: content = pdfResult.markdown;\n }\n return {\n url,\n finalUrl: url,\n title: pdfResult.metadata.title,\n content,\n links: [],\n engine: 'pdf',\n duration,\n statusCode: 200,\n };\n }\n\n const resp = await fetch(url, {\n headers: {\n 'User-Agent': 'LobsterCLI/0.1 (+https://github.com/iexcalibur/lobster-cli)',\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\n 'Accept-Language': 'en-US,en;q=0.5',\n ...(options?.headers || {}),\n },\n redirect: options?.followRedirects !== false ? 'follow' : 'manual',\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!resp.ok) {\n throw new Error(`HTTP ${resp.status} ${resp.statusText}`);\n }\n\n // ── PDF detection: check content-type from response ──\n const contentType = resp.headers.get('content-type') || '';\n if (isPdfResponse(contentType)) {\n const arrayBuffer = await resp.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n // Re-import extractPdf with buffer support\n const pdfMod = await import('pdf-parse');\n const pdfParseFn = (pdfMod as any).PDFParse || (pdfMod as any).default || pdfMod;\n const pdfResult = await pdfParseFn(buffer);\n const info = pdfResult.info || {};\n const metadata = {\n title: info.Title || 'untitled',\n author: info.Author || '',\n pages: pdfResult.numpages,\n };\n const duration = Date.now() - start;\n const text = pdfResult.text || '';\n\n let content: string;\n switch (dump) {\n case 'text': content = text; break;\n case 'html': content = `<pre>${text}</pre>`; break;\n case 'snapshot': content = `[PDF] ${metadata.title} (${metadata.pages} pages)\\n\\n${text.slice(0, 5000)}`; break;\n default: content = text; // Markdown conversion would need the full module\n }\n\n return {\n url,\n finalUrl: resp.url || url,\n title: metadata.title,\n content,\n links: [],\n engine: 'pdf',\n duration,\n statusCode: 200,\n };\n }\n\n const html = await resp.text();\n const duration = Date.now() - start;\n const finalUrl = resp.url || url;\n\n // Parse\n const nodes = parseHtml(html);\n\n // Extract title\n let title = '';\n function findTitle(nodes: HtmlNode[]): void {\n for (const node of nodes) {\n if (node.tag === 'title' && node.children?.[0]?.text) {\n title = node.children[0].text.trim();\n return;\n }\n if (node.children) findTitle(node.children);\n }\n }\n findTitle(nodes);\n\n // Extract content based on dump format\n let content: string;\n let links: { text: string; href: string }[] | undefined;\n\n switch (dump) {\n case 'markdown':\n content = extractMarkdown(nodes, finalUrl);\n break;\n case 'text':\n content = extractText(nodes);\n break;\n case 'snapshot':\n content = extractSnapshot(nodes);\n break;\n case 'html':\n content = html;\n break;\n case 'links':\n links = extractLinks(nodes, finalUrl);\n content = links.map((l, i) => `${i + 1}. [${l.text}](${l.href})`).join('\\n');\n break;\n default:\n content = extractMarkdown(nodes, finalUrl);\n }\n\n return { url, finalUrl, status: resp.status, title, content, links, duration };\n}\n\n// Keep these exports for backward compatibility\nexport function isLightpandaAvailable(): boolean { return true; } // Our engine is always available\nexport function getInstallInstructions(): string { return 'Built-in — no installation needed'; }\n","import type { StepHandler } from '../types/pipeline.js';\n\nconst stepHandlers = new Map<string, StepHandler>();\n\nexport function registerStep(name: string, handler: StepHandler): void {\n stepHandlers.set(name, handler);\n}\n\nexport function getStep(name: string): StepHandler | undefined {\n return stepHandlers.get(name);\n}\n\nexport function getStepNames(): string[] {\n return [...stepHandlers.keys()];\n}\n","import type { IPage } from '../types/page.js';\nimport type { PipelineContext, PipelineStepDef } from '../types/pipeline.js';\nimport { getStep } from './registry.js';\nimport { log } from '../utils/logger.js';\n\nexport async function executePipeline(\n steps: PipelineStepDef[],\n page: IPage | null,\n args: Record<string, unknown>,\n debug = false\n): Promise<unknown> {\n const ctx: PipelineContext = { page, args, data: null, debug };\n\n for (let i = 0; i < steps.length; i++) {\n const stepDef = steps[i];\n const [stepName, params] = Object.entries(stepDef)[0];\n\n const handler = getStep(stepName);\n if (!handler) {\n throw new Error(`Unknown pipeline step: ${stepName}`);\n }\n\n if (debug) {\n log.step(i + 1, `${stepName}`);\n }\n\n ctx.data = await handler(ctx, params);\n\n if (debug && ctx.data !== undefined) {\n const preview = JSON.stringify(ctx.data)?.slice(0, 200);\n log.dim(` → ${preview}...`);\n }\n }\n\n return ctx.data;\n}\n","/**\n * Template expression engine for pipeline YAML.\n * Resolves ${{ expr }} expressions with context variables and filters.\n */\n\nconst EXPR_RE = /\\$\\{\\{\\s*(.*?)\\s*\\}\\}/g;\n\ninterface RenderContext {\n args: Record<string, unknown>;\n item?: unknown;\n data?: unknown;\n index?: number;\n}\n\nexport function renderTemplate(template: unknown, ctx: RenderContext): unknown {\n if (typeof template !== 'string') {\n if (typeof template === 'object' && template !== null) {\n if (Array.isArray(template)) return template.map((v) => renderTemplate(v, ctx));\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(template)) {\n result[k] = renderTemplate(v, ctx);\n }\n return result;\n }\n return template;\n }\n\n // Full expression: entire string is one expression — return raw value (not stringified)\n const fullMatch = template.match(/^\\$\\{\\{\\s*(.*?)\\s*\\}\\}$/);\n if (fullMatch) {\n return evaluateExpression(fullMatch[1], ctx);\n }\n\n // Partial: interpolate into string\n return template.replace(EXPR_RE, (_, expr) => {\n const val = evaluateExpression(expr, ctx);\n return val === null || val === undefined ? '' : String(val);\n });\n}\n\nfunction evaluateExpression(expr: string, ctx: RenderContext): unknown {\n // Handle pipe filters: expr | filter(arg)\n const parts = expr.split(/\\s*\\|\\s*/);\n let value = resolveValue(parts[0].trim(), ctx);\n\n for (let i = 1; i < parts.length; i++) {\n value = applyFilter(value, parts[i].trim());\n }\n\n return value;\n}\n\nfunction resolveValue(path: string, ctx: RenderContext): unknown {\n // Handle simple arithmetic: index + 1\n const arithMatch = path.match(/^(\\w[\\w.]*)\\s*([+\\-*])\\s*(\\d+)$/);\n if (arithMatch) {\n const base = Number(resolvePath(arithMatch[1], ctx));\n const op = arithMatch[2];\n const num = Number(arithMatch[3]);\n if (op === '+') return base + num;\n if (op === '-') return base - num;\n if (op === '*') return base * num;\n }\n\n // Handle logical OR: a || b\n const orMatch = path.match(/^(.+?)\\s*\\|\\|\\s*(.+)$/);\n if (orMatch) {\n const left = resolvePath(orMatch[1].trim(), ctx);\n if (left !== null && left !== undefined && left !== '' && left !== false) return left;\n // Right side: could be a string literal\n const right = orMatch[2].trim();\n if ((right.startsWith(\"'\") && right.endsWith(\"'\")) || (right.startsWith('\"') && right.endsWith('\"'))) {\n return right.slice(1, -1);\n }\n return resolvePath(right, ctx);\n }\n\n // String literal\n if ((path.startsWith(\"'\") && path.endsWith(\"'\")) || (path.startsWith('\"') && path.endsWith('\"'))) {\n return path.slice(1, -1);\n }\n\n // Number literal\n if (!isNaN(Number(path)) && path !== '') return Number(path);\n\n return resolvePath(path, ctx);\n}\n\nfunction resolvePath(path: string, ctx: RenderContext): unknown {\n // Resolve against context: args.*, item.*, data.*, index\n if (path === 'index') return ctx.index ?? 0;\n\n const parts = path.split('.');\n let root: unknown;\n\n if (parts[0] === 'args') {\n root = ctx.args;\n parts.shift();\n } else if (parts[0] === 'item') {\n root = ctx.item;\n parts.shift();\n } else if (parts[0] === 'data') {\n root = ctx.data;\n parts.shift();\n } else {\n // Try item first, then args, then data\n root = getNestedValue(ctx.item, parts);\n if (root !== undefined) return root;\n root = getNestedValue(ctx.args, parts);\n if (root !== undefined) return root;\n root = getNestedValue(ctx.data, parts);\n if (root !== undefined) return root;\n return undefined;\n }\n\n return getNestedValue(root, parts);\n}\n\nfunction getNestedValue(obj: unknown, parts: string[]): unknown {\n let current = obj;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current === 'object') {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\nfunction applyFilter(value: unknown, filter: string): unknown {\n const match = filter.match(/^(\\w+)(?:\\((.+)\\))?$/);\n if (!match) return value;\n\n const name = match[1];\n const arg = match[2]?.replace(/^['\"]|['\"]$/g, '');\n\n switch (name) {\n case 'default':\n return value === null || value === undefined || value === '' ? arg : value;\n case 'join':\n return Array.isArray(value) ? value.join(arg || ', ') : value;\n case 'upper':\n return typeof value === 'string' ? value.toUpperCase() : value;\n case 'lower':\n return typeof value === 'string' ? value.toLowerCase() : value;\n case 'trim':\n return typeof value === 'string' ? value.trim() : value;\n case 'truncate': {\n const len = parseInt(arg || '100');\n if (typeof value === 'string' && value.length > len) return value.slice(0, len) + '...';\n return value;\n }\n case 'replace': {\n if (typeof value !== 'string' || !arg) return value;\n const [from, to] = arg.split(',').map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''));\n return value.replaceAll(from, to || '');\n }\n case 'keys':\n return typeof value === 'object' && value !== null ? Object.keys(value) : [];\n case 'length':\n return Array.isArray(value) ? value.length : typeof value === 'string' ? value.length : 0;\n case 'first':\n return Array.isArray(value) ? value[0] : value;\n case 'last':\n return Array.isArray(value) ? value[value.length - 1] : value;\n case 'json':\n return JSON.stringify(value);\n case 'slugify':\n return typeof value === 'string' ? value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') : value;\n case 'sanitize':\n // Filename-safe: remove/replace dangerous chars\n return typeof value === 'string' ? value.replace(/[<>:\"/\\\\|?*\\x00-\\x1f]/g, '_').replace(/__+/g, '_').trim() : value;\n case 'ext': {\n // Extract file extension from URL/path\n if (typeof value !== 'string') return '';\n const extMatch = value.match(/\\.([a-zA-Z0-9]+)(?:\\?.*)?$/);\n return extMatch ? extMatch[1] : '';\n }\n case 'basename': {\n // Extract filename from URL/path\n if (typeof value !== 'string') return '';\n try { return new URL(value).pathname.split('/').pop() || ''; } catch {}\n return value.split('/').pop() || '';\n }\n default:\n return value;\n }\n}\n","import type { IPage } from './page.js';\n\nexport enum Strategy {\n PUBLIC = 'public',\n COOKIE = 'cookie',\n HEADER = 'header',\n INTERCEPT = 'intercept',\n UI = 'ui',\n}\n\nexport interface Arg {\n name: string;\n type?: 'string' | 'int' | 'float' | 'boolean';\n default?: unknown;\n required?: boolean;\n positional?: boolean;\n help?: string;\n choices?: string[];\n}\n\nexport interface Adapter {\n site: string;\n name: string;\n description: string;\n domain?: string;\n strategy: Strategy;\n browser: boolean;\n args: Arg[];\n columns?: string[];\n func?: (page: IPage, kwargs: Record<string, unknown>) => Promise<unknown>;\n pipeline?: Record<string, unknown>[];\n timeoutSeconds?: number;\n navigateBefore?: boolean | string;\n}\n","import type { Adapter } from '../types/adapter.js';\nimport { Strategy } from '../types/adapter.js';\n\n// Global registry — shared across module instances (critical for plugins)\nconst REGISTRY_KEY = '__lobster_registry__';\nif (!(globalThis as any)[REGISTRY_KEY]) {\n (globalThis as any)[REGISTRY_KEY] = new Map<string, Adapter>();\n}\n\nfunction getRegistry(): Map<string, Adapter> {\n return (globalThis as any)[REGISTRY_KEY];\n}\n\nexport function cli(def: Partial<Adapter> & { site: string; name: string }): Adapter {\n const adapter: Adapter = {\n site: def.site,\n name: def.name,\n description: def.description || `${def.site} ${def.name}`,\n domain: def.domain,\n strategy: def.strategy || Strategy.PUBLIC,\n browser: def.browser ?? (def.strategy !== Strategy.PUBLIC),\n args: def.args || [],\n columns: def.columns,\n func: def.func,\n pipeline: def.pipeline,\n timeoutSeconds: def.timeoutSeconds,\n navigateBefore: def.navigateBefore,\n };\n\n const fullName = `${adapter.site}/${adapter.name}`;\n getRegistry().set(fullName, adapter);\n return adapter;\n}\n\nexport function getAdapter(site: string, name: string): Adapter | undefined {\n return getRegistry().get(`${site}/${name}`);\n}\n\nexport function getAdapterBySite(site: string): Adapter[] {\n const adapters: Adapter[] = [];\n for (const [key, adapter] of getRegistry()) {\n if (key.startsWith(`${site}/`)) adapters.push(adapter);\n }\n return adapters;\n}\n\nexport function getAdapterByDomain(domain: string): Adapter[] {\n const adapters: Adapter[] = [];\n for (const adapter of getRegistry().values()) {\n if (adapter.domain && domain.includes(adapter.domain)) adapters.push(adapter);\n }\n return adapters;\n}\n\nexport function getAllAdapters(): Adapter[] {\n return [...getRegistry().values()];\n}\n\nexport function getAllSites(): string[] {\n const sites = new Set<string>();\n for (const adapter of getRegistry().values()) {\n sites.add(adapter.site);\n }\n return [...sites].sort();\n}\n\nexport { Strategy };\n","/**\n * Site exploration: navigate, capture network, analyze APIs, infer capabilities.\n *\n * Based on OpenCLI's explore module with:\n * - URL pattern normalization (/123 → /{id})\n * - Auth detection (bearer, CSRF, signature)\n * - Response body analysis (item arrays, field roles)\n * - Framework & store detection\n * - Artifact generation\n */\n\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IPage } from '../types/page.js';\nimport { log } from '../utils/logger.js';\n\n// ── Known site aliases ──\nconst SITE_ALIASES: Record<string, string> = {\n 'x.com': 'twitter', 'twitter.com': 'twitter',\n 'news.ycombinator.com': 'hackernews',\n 'old.reddit.com': 'reddit', 'www.reddit.com': 'reddit',\n 'bilibili.com': 'bilibili', 'www.bilibili.com': 'bilibili',\n 'zhihu.com': 'zhihu', 'www.zhihu.com': 'zhihu',\n};\n\n// ── Field role mapping ──\nconst FIELD_ROLES: Record<string, string[]> = {\n title: ['title', 'name', 'headline', 'subject', 'text', 'caption'],\n url: ['url', 'link', 'href', 'permalink', 'uri', 'web_url'],\n author: ['author', 'user', 'creator', 'owner', 'by', 'username', 'screen_name', 'display_name'],\n score: ['score', 'points', 'likes', 'upvotes', 'karma', 'vote_count', 'favorite_count', 'retweet_count'],\n time: ['time', 'date', 'created', 'created_at', 'timestamp', 'published', 'updated_at', 'posted_at'],\n description: ['description', 'summary', 'snippet', 'excerpt', 'body', 'content', 'selftext'],\n image: ['image', 'thumbnail', 'avatar', 'icon', 'photo', 'cover', 'poster'],\n id: ['id', 'uid', 'pid', 'mid', 'aid', 'bvid'],\n};\n\n// ── Volatile query params to ignore ──\nconst VOLATILE_PARAMS = new Set([\n '_', 't', 'ts', 'timestamp', 'nonce', 'rand', 'random',\n 'callback', 'jsonp', '_t', '__t',\n]);\n\nexport interface EndpointInfo {\n url: string;\n pattern: string;\n method: string;\n status: number;\n contentType: string;\n queryParams: string[];\n hasItems: boolean;\n itemCount: number;\n fields: string[];\n fieldRoles: Record<string, string>;\n authIndicators: string[];\n score: number;\n}\n\nexport interface ExploreResult {\n site: string;\n domain: string;\n endpoints: EndpointInfo[];\n strategy: string;\n framework?: string;\n stores?: { name: string; type: string; actions: string[] }[];\n capabilities: string[];\n artifactDir?: string;\n}\n\nexport interface ExploreOptions {\n wait?: number;\n scroll?: boolean;\n fuzz?: boolean;\n outputDir?: string;\n maxButtons?: number;\n scrollAttempts?: number;\n}\n\n/**\n * Normalize a URL path to a pattern:\n * /users/123/posts → /users/{id}/posts\n * /item/abc123def → /item/{hex}\n */\nfunction normalizeUrlPattern(urlStr: string): string {\n try {\n const u = new URL(urlStr);\n const parts = u.pathname.split('/');\n const normalized = parts.map((p) => {\n if (!p) return p;\n if (/^\\d+$/.test(p)) return '{id}';\n if (/^[a-f0-9]{8,}$/i.test(p)) return '{hex}';\n if (/^BV[a-zA-Z0-9]+$/.test(p)) return '{bvid}';\n if (/^[a-z0-9]{20,}$/i.test(p)) return '{token}';\n return p;\n });\n return u.origin + normalized.join('/');\n } catch {\n return urlStr;\n }\n}\n\n/**\n * Detect auth indicators in request headers/URL.\n */\nfunction detectAuth(url: string, headers?: Record<string, string>): string[] {\n const indicators: string[] = [];\n if (url.includes('signature') || url.includes('sign=') || url.includes('sig=')) indicators.push('signature');\n if (url.includes('token=') || url.includes('access_token=')) indicators.push('token');\n if (url.includes('api_key=') || url.includes('apikey=')) indicators.push('api_key');\n if (headers) {\n if (headers['authorization']?.startsWith('Bearer')) indicators.push('bearer');\n if (headers['x-csrf-token'] || headers['x-xsrf-token']) indicators.push('csrf');\n }\n return indicators;\n}\n\n/**\n * Analyze a JSON response body to find item arrays and extract fields.\n */\nfunction analyzeResponseBody(body: unknown): {\n hasItems: boolean;\n itemCount: number;\n fields: string[];\n fieldRoles: Record<string, string>;\n} {\n if (!body || typeof body !== 'object') {\n return { hasItems: false, itemCount: 0, fields: [], fieldRoles: {} };\n }\n\n // Find the item array — could be at root or nested\n let items: unknown[] | null = null;\n\n if (Array.isArray(body)) {\n items = body;\n } else {\n // Search common nested paths: data, results, items, list, entries, records, hits\n const obj = body as Record<string, unknown>;\n for (const key of ['data', 'results', 'items', 'list', 'entries', 'records', 'hits', 'posts', 'articles', 'stories']) {\n const val = obj[key];\n if (Array.isArray(val) && val.length > 0) {\n items = val;\n break;\n }\n // One level deeper: data.items, data.list, etc.\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n for (const subKey of ['items', 'list', 'data', 'results', 'entries']) {\n const subVal = (val as Record<string, unknown>)[subKey];\n if (Array.isArray(subVal) && subVal.length > 0) {\n items = subVal;\n break;\n }\n }\n if (items) break;\n }\n }\n }\n\n if (!items || items.length === 0) {\n return { hasItems: false, itemCount: 0, fields: [], fieldRoles: {} };\n }\n\n // Extract fields from first item\n const firstItem = items[0];\n if (!firstItem || typeof firstItem !== 'object') {\n return { hasItems: true, itemCount: items.length, fields: [], fieldRoles: {} };\n }\n\n const fields = Object.keys(firstItem as Record<string, unknown>);\n\n // Map fields to semantic roles\n const fieldRoles: Record<string, string> = {};\n for (const field of fields) {\n const lower = field.toLowerCase();\n for (const [role, patterns] of Object.entries(FIELD_ROLES)) {\n if (patterns.some((p) => lower.includes(p))) {\n fieldRoles[field] = role;\n break;\n }\n }\n }\n\n return { hasItems: true, itemCount: items.length, fields, fieldRoles };\n}\n\n/**\n * Score an endpoint for relevance.\n */\nfunction scoreEndpoint(ep: Omit<EndpointInfo, 'score'>): number {\n let score = 0;\n\n // Content type\n if (ep.contentType.includes('json')) score += 10;\n\n // Response analysis\n if (ep.hasItems) score += 5;\n if (ep.itemCount > 3) score += 3;\n if (ep.itemCount > 10) score += 2;\n if (Object.keys(ep.fieldRoles).length > 2) score += 3;\n\n // URL patterns\n if (ep.url.includes('/api/')) score += 5;\n if (ep.url.includes('/v1/') || ep.url.includes('/v2/') || ep.url.includes('/v3/')) score += 3;\n const path = new URL(ep.url).pathname.toLowerCase();\n if (/search|query|find/.test(path)) score += 4;\n if (/hot|trending|popular|top|feed|timeline/.test(path)) score += 4;\n if (/list|index|all|latest|recent/.test(path)) score += 3;\n\n // Query params\n if (ep.queryParams.some((p) => /search|keyword|query|q/.test(p))) score += 3;\n if (ep.queryParams.some((p) => /page|offset|cursor|limit|count|num/.test(p))) score += 2;\n\n // Method\n if (ep.method === 'GET') score += 2;\n\n // Auth complexity penalty\n if (ep.authIndicators.includes('signature')) score -= 2;\n\n // Penalize static assets\n if (/\\.(js|css|png|jpg|gif|svg|woff|ico)/.test(ep.url)) score -= 30;\n\n // Penalize tracking/analytics\n if (/analytics|tracking|pixel|beacon|log\\b/.test(ep.url)) score -= 20;\n\n return score;\n}\n\n/**\n * Infer capabilities from discovered endpoints.\n */\nfunction inferCapabilities(endpoints: EndpointInfo[]): string[] {\n const caps: string[] = [];\n for (const ep of endpoints) {\n const path = ep.url.toLowerCase();\n if (/search|query|find/.test(path) && !caps.includes('search')) caps.push('search');\n if (/hot|trending|popular/.test(path) && !caps.includes('hot')) caps.push('hot');\n if (/feed|timeline|home/.test(path) && !caps.includes('feed')) caps.push('feed');\n if (/detail|item\\/\\{|article\\/\\{|post\\/\\{/.test(ep.pattern) && !caps.includes('detail')) caps.push('detail');\n if (/comment|reply|discuss/.test(path) && !caps.includes('comments')) caps.push('comments');\n if (/user|profile|me\\b|account/.test(path) && !caps.includes('me')) caps.push('me');\n if (/favorite|bookmark|saved|like/.test(path) && !caps.includes('favorites')) caps.push('favorites');\n if (/history|watch|read/.test(path) && !caps.includes('history')) caps.push('history');\n }\n return caps;\n}\n\n/**\n * Smart auto-scroll with MutationObserver-based lazy-load detection.\n * Waits for new DOM nodes to appear after each scroll instead of fixed delays.\n */\nasync function smartAutoScroll(page: IPage, attempts: number): Promise<void> {\n for (let i = 0; i < attempts; i++) {\n const scrolled = await page.evaluate<boolean>(`\n (async () => {\n const lastHeight = document.body.scrollHeight;\n window.scrollTo(0, lastHeight);\n\n // Wait for new content via MutationObserver or timeout\n const result = await new Promise((resolve) => {\n let timeoutId;\n const observer = new MutationObserver(() => {\n if (document.body.scrollHeight > lastHeight) {\n clearTimeout(timeoutId);\n observer.disconnect();\n setTimeout(() => resolve(true), 100);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n timeoutId = setTimeout(() => { observer.disconnect(); resolve(false); }, 2000);\n });\n return result;\n })()\n `);\n if (!scrolled) break; // No new content loaded, stop scrolling\n }\n}\n\n/**\n * Interactive fuzzing — click buttons/tabs to trigger hidden API calls.\n * Clicks up to maxButtons interactive elements that look like data triggers.\n */\nasync function interactiveFuzz(page: IPage, maxButtons: number): Promise<void> {\n await page.evaluate(`\n (async () => {\n const clickTargets = [];\n const selectors = [\n 'button:not([disabled])',\n '[role=\"tab\"]',\n '[role=\"button\"]',\n '.tab', '.nav-link', '.dropdown-toggle',\n 'a[data-toggle]', '[data-bs-toggle]',\n ];\n\n for (const sel of selectors) {\n for (const el of document.querySelectorAll(sel)) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0 &&\n rect.top >= 0 && rect.top < window.innerHeight * 2) {\n const text = el.textContent?.trim()?.slice(0, 40) || '';\n // Skip destructive-looking buttons\n if (/delete|remove|logout|sign.?out|cancel|close/i.test(text)) continue;\n clickTargets.push(el);\n }\n }\n }\n\n // Click up to N targets with delays\n const max = Math.min(${maxButtons}, clickTargets.length);\n for (let i = 0; i < max; i++) {\n try {\n clickTargets[i].click();\n await new Promise(r => setTimeout(r, 800));\n } catch {}\n }\n })()\n `);\n await page.wait(1.5);\n}\n\n/**\n * Re-fetch JSON endpoints whose response body was missing from interception.\n * Uses an iframe to avoid CORS issues (same-origin cookies).\n */\nasync function recoverMissingBodies(\n page: IPage,\n endpoints: EndpointInfo[],\n): Promise<void> {\n const needsRecovery = endpoints.filter(\n (ep) => !ep.hasItems && ep.contentType.includes('json') && ep.score > 5,\n );\n\n if (needsRecovery.length === 0) return;\n\n const urls = needsRecovery.map((ep) => ep.url).slice(0, 8);\n\n const bodies = await page.evaluate<(unknown | null)[]>(`\n (async () => {\n const urls = ${JSON.stringify(urls)};\n const results = [];\n for (const url of urls) {\n try {\n const resp = await fetch(url, { credentials: 'include' });\n if (resp.ok) {\n const json = await resp.json();\n results.push(json);\n } else {\n results.push(null);\n }\n } catch { results.push(null); }\n }\n return results;\n })()\n `);\n\n if (!bodies) return;\n\n for (let i = 0; i < urls.length; i++) {\n if (!bodies[i]) continue;\n const ep = needsRecovery[i];\n const analysis = analyzeResponseBody(bodies[i]);\n if (analysis.hasItems) {\n ep.hasItems = analysis.hasItems;\n ep.itemCount = analysis.itemCount;\n ep.fields = analysis.fields;\n ep.fieldRoles = analysis.fieldRoles;\n ep.score = scoreEndpoint(ep);\n }\n }\n}\n\n/**\n * Write exploration artifacts to disk.\n */\nfunction writeArtifacts(dir: string, result: ExploreResult): void {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n // manifest.json — site metadata\n writeFileSync(join(dir, 'manifest.json'), JSON.stringify({\n site: result.site,\n domain: result.domain,\n framework: result.framework,\n strategy: result.strategy,\n capabilities: result.capabilities,\n endpointCount: result.endpoints.length,\n exploredAt: new Date().toISOString(),\n }, null, 2));\n\n // endpoints.json — all discovered endpoints with scores/fields\n writeFileSync(join(dir, 'endpoints.json'), JSON.stringify(\n result.endpoints.map((ep) => ({\n url: ep.url,\n pattern: ep.pattern,\n method: ep.method,\n status: ep.status,\n score: ep.score,\n hasItems: ep.hasItems,\n itemCount: ep.itemCount,\n fields: ep.fields,\n fieldRoles: ep.fieldRoles,\n queryParams: ep.queryParams,\n authIndicators: ep.authIndicators,\n })),\n null, 2,\n ));\n\n // capabilities.json — inferred CLI commands\n writeFileSync(join(dir, 'capabilities.json'), JSON.stringify(\n result.capabilities.map((cap) => {\n const matchingEndpoints = result.endpoints.filter((ep) => {\n const path = ep.url.toLowerCase();\n if (cap === 'search') return /search|query|find/.test(path);\n if (cap === 'hot') return /hot|trending|popular/.test(path);\n if (cap === 'feed') return /feed|timeline|home/.test(path);\n return false;\n });\n return {\n name: cap,\n description: `${cap} capability`,\n endpoint: matchingEndpoints[0]?.pattern || null,\n strategy: result.strategy,\n confidence: matchingEndpoints.length > 0 ? 0.8 : 0.5,\n recommendedColumns: matchingEndpoints[0]?.fields?.slice(0, 6) || [],\n };\n }),\n null, 2,\n ));\n\n // auth.json — auth indicators\n const authSummary: Record<string, string[]> = {};\n for (const ep of result.endpoints) {\n for (const ind of ep.authIndicators) {\n if (!authSummary[ind]) authSummary[ind] = [];\n authSummary[ind].push(ep.pattern);\n }\n }\n writeFileSync(join(dir, 'auth.json'), JSON.stringify(authSummary, null, 2));\n\n // stores.json — Vue/React stores if detected\n if (result.stores && result.stores.length > 0) {\n writeFileSync(join(dir, 'stores.json'), JSON.stringify(result.stores, null, 2));\n }\n\n log.success(`Artifacts written to ${dir}/`);\n}\n\nexport async function exploreSite(\n page: IPage,\n url: string,\n options?: ExploreOptions,\n): Promise<ExploreResult> {\n const parsedUrl = new URL(url);\n const domain = parsedUrl.hostname;\n const site = SITE_ALIASES[domain] || domain.replace(/^www\\./, '').split('.')[0];\n\n log.info(`Exploring ${url}...`);\n\n // Install network interceptor before navigation\n await page.installInterceptor('');\n await page.goto(url);\n await page.wait(options?.wait || 3);\n\n // Smart auto-scroll with MutationObserver lazy-load detection\n if (options?.scroll !== false) {\n log.debug('Smart auto-scrolling to trigger lazy-loaded APIs...');\n await smartAutoScroll(page, options?.scrollAttempts || 4);\n }\n\n // Interactive fuzzing — click buttons/tabs to discover hidden APIs\n if (options?.fuzz !== false) {\n log.debug('Fuzzing interactive elements...');\n await interactiveFuzz(page, options?.maxButtons || 12);\n }\n\n // Capture intercepted network requests\n const rawRequests = await page.getInterceptedRequests();\n\n // Analyze each request\n const seen = new Set<string>();\n const endpoints: EndpointInfo[] = [];\n\n for (const raw of rawRequests as any[]) {\n if (!raw?.url || !raw?.status) continue;\n if (raw.status < 200 || raw.status >= 400) continue;\n\n const pattern = normalizeUrlPattern(raw.url);\n const dedupeKey = `${raw.method || 'GET'}:${pattern}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n\n // Extract query params\n let queryParams: string[] = [];\n try {\n const u = new URL(raw.url);\n queryParams = [...u.searchParams.keys()].filter((k) => !VOLATILE_PARAMS.has(k));\n } catch {}\n\n const authIndicators = detectAuth(raw.url);\n const bodyAnalysis = analyzeResponseBody(raw.body);\n\n const ep: Omit<EndpointInfo, 'score'> = {\n url: raw.url,\n pattern,\n method: raw.method || 'GET',\n status: raw.status,\n contentType: 'json',\n queryParams,\n ...bodyAnalysis,\n authIndicators,\n };\n\n endpoints.push({ ...ep, score: scoreEndpoint(ep) });\n }\n\n // Response body recovery — re-fetch endpoints that had missing bodies\n log.debug('Recovering missing response bodies...');\n await recoverMissingBodies(page, endpoints);\n\n endpoints.sort((a, b) => b.score - a.score);\n\n // Detect framework\n const framework = await page.evaluate<string>(`\n (() => {\n const app = document.querySelector('#app');\n if (window.__NEXT_DATA__) return 'nextjs';\n if (window.__NUXT__) return 'nuxt';\n if (app && app.__vue_app__) {\n const gp = app.__vue_app__.config?.globalProperties;\n if (gp?.$pinia) return 'vue+pinia';\n if (gp?.$store) return 'vue+vuex';\n return 'vue';\n }\n if (app && app.__vue__) return 'vue2';\n if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) return 'react';\n if (document.querySelector('[data-reactroot]') || document.querySelector('#__next') || document.querySelector('#root')?.['_reactRootContainer']) return 'react';\n if (window.angular || document.querySelector('[ng-version]')) return 'angular';\n if (window.__svelte_meta) return 'svelte';\n return 'unknown';\n })()\n `).catch(() => 'unknown');\n\n // Detect stores (Pinia/Vuex) — improved detection via __vue_app__\n const stores = await page.evaluate<{ name: string; type: string; actions: string[] }[]>(`\n (() => {\n const results = [];\n const app = document.querySelector('#app');\n\n // Pinia via __vue_app__\n if (app && app.__vue_app__) {\n try {\n const pinia = app.__vue_app__.config?.globalProperties?.$pinia;\n if (pinia && pinia._s) {\n pinia._s.forEach((store, id) => {\n const actions = Object.keys(store).filter(k =>\n typeof store[k] === 'function' && !k.startsWith('$') && !k.startsWith('_')\n );\n const stateKeys = Object.keys(store).filter(k =>\n typeof store[k] !== 'function' && !k.startsWith('$') && !k.startsWith('_')\n );\n results.push({ name: id, type: 'pinia', actions: actions.slice(0, 20), stateKeys: stateKeys.slice(0, 20) });\n });\n }\n } catch {}\n\n // Vuex via __vue_app__\n try {\n const store = app.__vue_app__.config?.globalProperties?.$store;\n if (store && store._actions) {\n const actions = Object.keys(store._actions);\n results.push({ name: 'vuex', type: 'vuex', actions: actions.slice(0, 20) });\n }\n } catch {}\n }\n\n // Legacy Pinia global\n if (results.length === 0 && window.__pinia) {\n try {\n const pinia = window.__pinia;\n for (const [id, store] of pinia._s || []) {\n const actions = Object.keys(store).filter(k => typeof store[k] === 'function' && !k.startsWith('$') && !k.startsWith('_'));\n results.push({ name: id, type: 'pinia', actions: actions.slice(0, 20) });\n }\n } catch {}\n }\n\n return results;\n })()\n `).catch(() => []);\n\n // Infer strategy\n let strategy = 'public';\n if (endpoints.length > 0) {\n const topEp = endpoints[0];\n if (topEp.authIndicators.includes('signature')) strategy = 'intercept';\n else if (topEp.authIndicators.includes('bearer') || topEp.authIndicators.includes('csrf')) strategy = 'header';\n else if (endpoints.some((e) => !e.hasItems) && endpoints.some((e) => e.hasItems)) strategy = 'cookie';\n } else {\n strategy = 'cookie';\n }\n\n const capabilities = inferCapabilities(endpoints);\n\n const result: ExploreResult = {\n site,\n domain,\n endpoints: endpoints.slice(0, 30),\n strategy,\n framework,\n stores: stores.length > 0 ? stores : undefined,\n capabilities,\n };\n\n // Write artifacts to disk if outputDir specified\n const outputDir = options?.outputDir || join(process.cwd(), '.lobster', 'explore', site);\n writeArtifacts(outputDir, result);\n result.artifactDir = outputDir;\n\n return result;\n}\n","import yaml from 'js-yaml';\nimport type { ExploreResult } from './explore.js';\n\n/**\n * Generate adapter YAML from explore results.\n * Uses field role mapping to auto-detect column names.\n */\nexport function synthesizeAdapter(result: ExploreResult, goal?: string): string {\n const topEndpoints = result.endpoints.filter((e) => e.score > 0).slice(0, 3);\n if (topEndpoints.length === 0) {\n return `# No API endpoints discovered for ${result.site}\\n# Try using: lobster agent \"your task\" --url https://${result.domain}`;\n }\n\n const endpoint = topEndpoints[0];\n\n // Infer command name from goal or endpoint URL\n let name = goal || 'data';\n if (!goal) {\n const path = new URL(endpoint.url).pathname.toLowerCase();\n if (/search|query/.test(path)) name = 'search';\n else if (/hot|trending|popular/.test(path)) name = 'hot';\n else if (/feed|timeline|home/.test(path)) name = 'feed';\n else if (/top|best|rank/.test(path)) name = 'top';\n }\n\n // Build args from query params\n const args: Record<string, unknown> = {\n limit: { type: 'int', default: 20 },\n };\n for (const param of endpoint.queryParams) {\n if (/search|keyword|query|q/.test(param)) {\n args[param] = { required: true, positional: true, help: 'Search query' };\n } else if (/page|offset|cursor/.test(param)) {\n args[param] = { type: 'int', default: 1 };\n } else if (/limit|count|num|size/.test(param)) {\n // Already have limit\n }\n }\n\n // Build columns from field roles\n const columns: string[] = [];\n const mapTemplate: Record<string, string> = {};\n\n for (const [field, role] of Object.entries(endpoint.fieldRoles)) {\n if (['title', 'url', 'author', 'score', 'time', 'description'].includes(role)) {\n columns.push(role);\n mapTemplate[role] = `\\${{ item.${field} }}`;\n }\n }\n\n // Fallback columns if no roles detected\n if (columns.length === 0) {\n for (const field of endpoint.fields.slice(0, 5)) {\n columns.push(field);\n mapTemplate[field] = `\\${{ item.${field} }}`;\n }\n }\n\n // Build pipeline\n const pipeline: Record<string, unknown>[] = [];\n\n if (result.strategy === 'public' && !endpoint.authIndicators.length) {\n pipeline.push({ fetch: endpoint.url });\n } else {\n // Browser-based fetch with credentials\n pipeline.push({ navigate: `https://${result.domain}` });\n pipeline.push({\n evaluate: `(async () => { const r = await fetch(${JSON.stringify(endpoint.url)}, {credentials:'include'}); return r.json(); })()`,\n });\n }\n\n // Add select step if items are nested\n if (endpoint.hasItems && endpoint.itemCount > 0) {\n // Try to find the array path — check common patterns\n for (const path of ['data', 'results', 'items', 'list', 'data.items', 'data.list']) {\n pipeline.push({ select: path });\n break;\n }\n }\n\n if (Object.keys(mapTemplate).length > 0) {\n pipeline.push({ map: mapTemplate });\n }\n\n pipeline.push({ limit: '${{ args.limit }}' });\n\n const adapter = {\n site: result.site,\n name,\n description: `${name} from ${result.domain}`,\n domain: result.domain,\n strategy: result.strategy,\n browser: result.strategy !== 'public',\n args,\n pipeline,\n columns: columns.length > 0 ? columns : undefined,\n };\n\n return yaml.dump(adapter, { indent: 2, lineWidth: 120 });\n}\n","/**\n * Strategy Cascade: automatic strategy downgrade chain.\n *\n * Probes an API endpoint starting from the simplest strategy (PUBLIC)\n * and downgrades through tiers until one works:\n *\n * PUBLIC → COOKIE → HEADER → INTERCEPT → UI\n */\n\nimport { Strategy } from '../types/adapter.js';\nimport type { IPage } from '../types/page.js';\nimport { log } from '../utils/logger.js';\n\nconst CASCADE_ORDER: Strategy[] = [\n Strategy.PUBLIC,\n Strategy.COOKIE,\n Strategy.HEADER,\n Strategy.INTERCEPT,\n Strategy.UI,\n];\n\nexport interface ProbeResult {\n strategy: Strategy;\n success: boolean;\n statusCode?: number;\n hasData?: boolean;\n error?: string;\n responsePreview?: string;\n}\n\nexport interface CascadeResult {\n bestStrategy: Strategy;\n probes: ProbeResult[];\n confidence: number;\n}\n\n/**\n * Build JavaScript source for a fetch probe that runs inside the browser.\n * Handles credentials and CSRF token extraction.\n */\nfunction buildFetchProbeJs(url: string, opts: {\n credentials?: boolean;\n extractCsrf?: boolean;\n}): string {\n const credentialsLine = opts.credentials ? `credentials: 'include',` : '';\n const headerSetup = opts.extractCsrf\n ? `\n const cookies = document.cookie.split(';').map(c => c.trim());\n const csrf = cookies.find(c =>\n c.startsWith('ct0=') || c.startsWith('csrf_token=') ||\n c.startsWith('_csrf=') || c.startsWith('XSRF-TOKEN=')\n )?.split('=').slice(1).join('=');\n const headers = {};\n if (csrf) { headers['X-Csrf-Token'] = csrf; headers['X-XSRF-Token'] = csrf; }\n `\n : 'const headers = {};';\n\n return `\n (async () => {\n try {\n ${headerSetup}\n const resp = await fetch(${JSON.stringify(url)}, {\n ${credentialsLine}\n headers\n });\n const status = resp.status;\n if (!resp.ok) return { status, ok: false };\n const text = await resp.text();\n let hasData = false;\n try {\n const json = JSON.parse(text);\n hasData = !!json && (Array.isArray(json) ? json.length > 0 :\n typeof json === 'object' && Object.keys(json).length > 0);\n // API-level error codes (common in Chinese sites)\n if (json.code !== undefined && json.code !== 0) hasData = false;\n if (json.error || json.message === 'Unauthorized') hasData = false;\n } catch {}\n return { status, ok: true, hasData, preview: text.slice(0, 200) };\n } catch (e) { return { ok: false, error: e.message }; }\n })()\n `;\n}\n\n/**\n * Probe an endpoint with a specific strategy using in-browser JS evaluation.\n */\nexport async function probeEndpoint(\n page: IPage,\n url: string,\n strategy: Strategy,\n): Promise<ProbeResult> {\n const result: ProbeResult = { strategy, success: false };\n\n try {\n switch (strategy) {\n case Strategy.PUBLIC: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, {}));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.COOKIE: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, { credentials: true }));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.HEADER: {\n const resp = await page.evaluate<any>(buildFetchProbeJs(url, { credentials: true, extractCsrf: true }));\n result.statusCode = resp?.status;\n result.success = resp?.ok && resp?.hasData;\n result.hasData = resp?.hasData;\n result.responsePreview = resp?.preview;\n break;\n }\n\n case Strategy.INTERCEPT:\n case Strategy.UI:\n result.success = false;\n result.error = `Strategy ${strategy} requires site-specific implementation`;\n break;\n }\n } catch (err: any) {\n result.success = false;\n result.error = err.message ?? String(err);\n }\n\n return result;\n}\n\n/**\n * Run the cascade: try each strategy in order until one works.\n */\nexport async function cascadeProbe(\n page: IPage,\n url: string,\n opts: { maxStrategy?: Strategy } = {},\n): Promise<CascadeResult> {\n const maxIdx = opts.maxStrategy\n ? CASCADE_ORDER.indexOf(opts.maxStrategy)\n : CASCADE_ORDER.indexOf(Strategy.HEADER);\n\n const probes: ProbeResult[] = [];\n\n for (let i = 0; i <= Math.min(maxIdx, CASCADE_ORDER.length - 1); i++) {\n const strategy = CASCADE_ORDER[i];\n log.debug(`Probing strategy: ${strategy}`);\n const probe = await probeEndpoint(page, url, strategy);\n probes.push(probe);\n\n if (probe.success) {\n return {\n bestStrategy: strategy,\n probes,\n confidence: 1.0 - (i * 0.1),\n };\n }\n }\n\n return {\n bestStrategy: Strategy.COOKIE,\n probes,\n confidence: 0.3,\n };\n}\n\nexport function renderCascadeResult(result: CascadeResult): string {\n const lines = [\n `Strategy Cascade: ${result.bestStrategy} (${(result.confidence * 100).toFixed(0)}% confidence)`,\n ];\n for (const probe of result.probes) {\n const icon = probe.success ? '\\u2705' : '\\u274C';\n const status = probe.statusCode ? ` [${probe.statusCode}]` : '';\n const err = probe.error ? ` \\u2014 ${probe.error}` : '';\n lines.push(` ${icon} ${probe.strategy}${status}${err}`);\n }\n return lines.join('\\n');\n}\n","import { ExecutionLevel } from '../types/router.js';\nimport type { RoutingDecision, ExecutionRequest } from '../types/router.js';\nimport { getAdapter, getAdapterByDomain } from '../adapter/registry.js';\n\nexport function makeRoutingDecision(request: ExecutionRequest): RoutingDecision {\n // 1. Explicit adapter match\n if (request.site && request.command) {\n const adapter = getAdapter(request.site, request.command);\n if (adapter) {\n return {\n level: ExecutionLevel.ADAPTER,\n reason: `Matched adapter: ${request.site}/${request.command}`,\n adapter,\n };\n }\n }\n\n // 2. URL-based adapter match\n if (request.url) {\n try {\n const domain = new URL(request.url).hostname;\n const adapters = getAdapterByDomain(domain);\n if (adapters.length > 0) {\n return {\n level: ExecutionLevel.ADAPTER,\n reason: `Found adapter for domain: ${domain}`,\n adapter: adapters[0],\n };\n }\n } catch {}\n }\n\n // 3. Simple HTTP check — URL-only request with no interaction task\n if (request.url && !request.task) {\n return {\n level: ExecutionLevel.HTTP,\n reason: 'Direct URL fetch (no task specified)',\n };\n }\n\n // 4. Simple fetch detection — URL looks like an API\n if (request.url) {\n const url = request.url;\n if (url.endsWith('.json') || url.includes('/api/') || url.includes('/v1/') || url.includes('/v2/')) {\n return {\n level: ExecutionLevel.HTTP,\n reason: 'URL appears to be an API endpoint',\n };\n }\n }\n\n // 5. Task requires interaction — use agent\n if (request.task) {\n const taskLower = request.task.toLowerCase();\n const interactionWords = ['click', 'scroll', 'fill', 'type', 'login', 'sign in', 'search', 'navigate', 'find', 'extract', 'get'];\n const needsInteraction = interactionWords.some((w) => taskLower.includes(w));\n\n if (needsInteraction || request.url) {\n return {\n level: ExecutionLevel.AGENT,\n reason: 'Task requires web interaction',\n };\n }\n }\n\n // Default: agent for anything unrecognized\n return {\n level: ExecutionLevel.AGENT,\n reason: 'Defaulting to AI agent for unrecognized task',\n };\n}\n","import { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { IPage } from '../types/page.js';\nimport type {\n AgentConfig, AgentTool, ExecutionResult, HistoricalEvent,\n AgentStepEvent, ObservationEvent, AgentStatus,\n AgentEvent, AgentEventListener, AgentEventType,\n} from '../types/agent.js';\nimport { LLM } from '../llm/client.js';\nimport type { Message } from '../types/llm.js';\nimport { createDefaultTools } from './tools/index.js';\nimport { packMacroTool } from './macro-tool.js';\nimport { flatTreeToString } from '../browser/dom/flat-tree.js';\nimport { log } from '../utils/logger.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport class AgentCore {\n private page: IPage;\n private config: AgentConfig;\n private llm: LLM;\n private history: HistoricalEvent[] = [];\n private _status: AgentStatus = 'idle';\n private listeners = new Map<AgentEventType, Set<AgentEventListener>>();\n private previousElementHashes = new Set<string>();\n private totalWaitTime = 0;\n\n constructor(page: IPage, config: AgentConfig) {\n this.page = page;\n this.config = config;\n this.llm = new LLM(config.llm);\n }\n\n // ── Event system ──\n on(event: AgentEventType, listener: AgentEventListener): void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n this.listeners.get(event)!.add(listener);\n }\n\n off(event: AgentEventType, listener: AgentEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n private emit(event: AgentEvent): void {\n const listeners = this.listeners.get(event.type as AgentEventType);\n if (listeners) {\n for (const fn of listeners) {\n try { fn(event); } catch {}\n }\n }\n }\n\n get status(): AgentStatus { return this._status; }\n\n private setStatus(newStatus: AgentStatus): void {\n const prev = this._status;\n this._status = newStatus;\n this.emit({ type: 'statuschange', status: newStatus, previousStatus: prev });\n }\n\n private pushHistory(event: HistoricalEvent): void {\n this.history.push(event);\n this.emit({ type: 'historychange', history: this.history });\n }\n\n async execute(task: string, abortSignal?: AbortSignal): Promise<ExecutionResult> {\n this.setStatus('running');\n this.history = [];\n this.previousElementHashes.clear();\n this.totalWaitTime = 0;\n\n const maxSteps = this.config.maxSteps ?? 40;\n const stepDelay = this.config.stepDelay ?? 0.4;\n\n // Build tools\n const tools: Record<string, AgentTool> = {\n ...createDefaultTools(this.page),\n ...(this.config.customTools || {}),\n };\n for (const [name, tool] of Object.entries(tools)) {\n if (tool === null) delete tools[name];\n }\n\n const macroTool = packMacroTool(tools as Record<string, AgentTool>);\n\n // Load system prompt\n let systemPrompt: string;\n try {\n systemPrompt = readFileSync(join(__dirname, 'prompts', 'system.md'), 'utf-8');\n } catch {\n systemPrompt = 'You are an AI web agent that navigates web pages to complete tasks.';\n }\n\n if (this.config.instructions?.system) {\n systemPrompt += '\\n\\n' + this.config.instructions.system;\n }\n\n let lastURL = '';\n\n for (let step = 1; step <= maxSteps; step++) {\n if (abortSignal?.aborted) {\n this.setStatus('error');\n return { success: false, data: 'Aborted', history: this.history };\n }\n\n // ── Observe phase ──\n const browserState = await this.page.browserState().catch(() => ({\n url: '', title: '', viewportWidth: 0, viewportHeight: 0,\n pageWidth: 0, pageHeight: 0, scrollX: 0, scrollY: 0,\n scrollPercent: 0, pixelsAbove: 0, pixelsBelow: 0,\n }));\n\n const flatTree = await this.page.flatTree().catch(() => ({ rootId: '', map: {} }));\n const pageContent = flatTreeToString(flatTree);\n\n // ── New element tracking ──\n const currentHashes = new Set<string>();\n let newElementCount = 0;\n for (const node of Object.values(flatTree.map)) {\n if (node.isInteractive && node.highlightIndex !== undefined) {\n const hash = `${node.tagName}:${node.text || ''}:${JSON.stringify(node.attributes || {})}`;\n currentHashes.add(hash);\n if (!this.previousElementHashes.has(hash)) {\n newElementCount++;\n }\n }\n }\n this.previousElementHashes = currentHashes;\n\n // ── Build observations ──\n const observations: string[] = [];\n if (browserState.url !== lastURL && lastURL) {\n observations.push(`Navigated to ${browserState.url}`);\n }\n lastURL = browserState.url;\n\n if (newElementCount > 0 && step > 1) {\n observations.push(`${newElementCount} new interactive element(s) appeared`);\n }\n\n if (this.totalWaitTime > 3) {\n observations.push(`Total wait time: ${this.totalWaitTime.toFixed(1)}s — consider if page is still loading`);\n }\n\n if (step >= maxSteps - 5) {\n observations.push(`Warning: ${maxSteps - step} steps remaining`);\n }\n\n if (this.config.instructions?.getPageInstructions) {\n try {\n const pi = this.config.instructions.getPageInstructions(browserState.url);\n if (pi) observations.push(`Page instructions: ${pi}`);\n } catch {}\n }\n\n for (const obs of observations) {\n this.pushHistory({ type: 'observation', message: obs } as ObservationEvent);\n this.emit({ type: 'activity', kind: 'observation', message: obs, step });\n }\n\n // ── Assemble user prompt with browser state ──\n const userPrompt = assembleUserPrompt(\n task, pageContent, browserState, this.history, step, maxSteps,\n );\n\n // ── Think phase ──\n const messages: Message[] = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ];\n\n log.step(step, `Thinking... (${browserState.url})`);\n this.emit({ type: 'activity', kind: 'thinking', message: `Step ${step}: thinking`, step });\n\n if (this.config.onBeforeStep) await this.config.onBeforeStep(step);\n\n const startTime = Date.now();\n let result;\n try {\n result = await this.llm.invoke(messages, macroTool, abortSignal);\n } catch (err) {\n log.error(`LLM error at step ${step}: ${err}`);\n this.pushHistory({ type: 'error', error: String(err), step });\n this.emit({ type: 'activity', kind: 'error', message: String(err), step });\n continue;\n }\n const duration = Date.now() - startTime;\n\n // ── Act phase ──\n const args = result.toolCall.args;\n const action = (args.action || args) as Record<string, unknown>;\n const [actionName, actionInput] = Object.entries(action)[0] || ['unknown', {}];\n\n this.emit({ type: 'activity', kind: 'executing', message: actionName, step });\n\n // Track wait time\n if (actionName === 'wait') {\n const secs = (actionInput as any)?.seconds || 0;\n this.totalWaitTime += secs;\n }\n\n const stepEvent: AgentStepEvent = {\n type: 'step',\n step,\n reflection: {\n evaluation_previous_goal: (args.evaluation_previous_goal as string) || '',\n memory: (args.memory as string) || '',\n next_goal: (args.next_goal as string) || '',\n },\n action: { name: actionName, args: actionInput as Record<string, unknown> },\n output: result.toolResult,\n duration,\n };\n this.pushHistory(stepEvent);\n\n log.step(step, `Action: ${actionName} → ${result.toolResult.slice(0, 100)}`);\n this.emit({ type: 'activity', kind: 'executed', message: `${actionName}: ${result.toolResult.slice(0, 80)}`, step, duration });\n\n if (this.config.onAfterStep) await this.config.onAfterStep(this.history);\n\n // Check for done\n if (actionName === 'done') {\n try {\n const doneResult = JSON.parse(result.toolResult);\n this.setStatus('completed');\n return { success: doneResult.success, data: doneResult.text || result.toolResult, history: this.history };\n } catch {\n this.setStatus('completed');\n return { success: true, data: result.toolResult, history: this.history };\n }\n }\n\n if (stepDelay > 0) {\n await new Promise((r) => setTimeout(r, stepDelay * 1000));\n }\n }\n\n this.setStatus('error');\n return { success: false, data: `Reached maximum steps (${maxSteps})`, history: this.history };\n }\n}\n\nfunction assembleUserPrompt(\n task: string,\n pageContent: string,\n state: { url: string; title: string; viewportWidth: number; viewportHeight: number; pageHeight: number; scrollPercent: number; pixelsAbove: number; pixelsBelow: number },\n history: HistoricalEvent[],\n step: number,\n maxSteps: number,\n): string {\n let prompt = `# Task\\n${task}\\n\\n`;\n\n // Browser state header\n prompt += `# Current Page\\n`;\n prompt += `URL: ${state.url}\\n`;\n prompt += `Title: ${state.title}\\n`;\n prompt += `Viewport: ${state.viewportWidth}x${state.viewportHeight} | Page height: ${state.pageHeight}px\\n`;\n prompt += `Scroll: ${state.scrollPercent}%`;\n if (state.pixelsAbove > 50) prompt += ` | ${state.pixelsAbove}px above`;\n if (state.pixelsBelow > 50) prompt += ` | ${state.pixelsBelow}px below`;\n prompt += `\\nStep: ${step}/${maxSteps}\\n\\n`;\n\n prompt += `# Browser State\\n${pageContent}\\n\\n`;\n\n if (history.length > 0) {\n prompt += `# History\\n`;\n const recent = history.slice(-10);\n for (const event of recent) {\n if (event.type === 'step') {\n const s = event as AgentStepEvent;\n prompt += `<step_${s.step}>\\n`;\n if (s.reflection) {\n prompt += ` eval: ${s.reflection.evaluation_previous_goal}\\n`;\n prompt += ` memory: ${s.reflection.memory}\\n`;\n prompt += ` goal: ${s.reflection.next_goal}\\n`;\n }\n prompt += ` action: ${s.action.name}(${JSON.stringify(s.action.args)})\\n`;\n prompt += ` result: ${s.output.slice(0, 200)}\\n`;\n prompt += `</step_${s.step}>\\n`;\n } else if (event.type === 'observation') {\n prompt += `<sys>${(event as ObservationEvent).message}</sys>\\n`;\n }\n }\n }\n\n return prompt;\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createClickTool(page: IPage): AgentTool {\n return {\n description: 'Click on an interactive element by its index number from the page content.',\n inputSchema: z.object({\n index: z.number().describe('The index of the element to click'),\n }),\n execute: async (args) => {\n await page.click(args.index);\n return `Clicked element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createTypeTool(page: IPage): AgentTool {\n return {\n description: 'Type text into an input field identified by its index number.',\n inputSchema: z.object({\n index: z.number().describe('The index of the input element'),\n text: z.string().describe('The text to type'),\n }),\n execute: async (args) => {\n await page.typeText(args.index, args.text);\n return `Typed \"${args.text}\" into element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createScrollTool(page: IPage): AgentTool {\n return {\n description: 'Scroll the page in a given direction. Use to reveal more content.',\n inputSchema: z.object({\n direction: z.enum(['up', 'down', 'left', 'right']).describe('Scroll direction'),\n amount: z.number().optional().describe('Pixels to scroll (default 500)'),\n }),\n execute: async (args) => {\n await page.scroll(args.direction, args.amount);\n return `Scrolled ${args.direction}${args.amount ? ` ${args.amount}px` : ''}`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createSelectTool(page: IPage): AgentTool {\n return {\n description: 'Select an option from a dropdown/select element by its index.',\n inputSchema: z.object({\n index: z.number().describe('The index of the select element'),\n value: z.string().describe('The option text or value to select'),\n }),\n execute: async (args) => {\n await page.selectOption(args.index, args.value);\n return `Selected \"${args.value}\" in element [${args.index}]`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\n\nexport function createWaitTool(): AgentTool {\n return {\n description: 'Wait for a specified number of seconds before continuing.',\n inputSchema: z.object({\n seconds: z.number().min(0.1).max(30).describe('Seconds to wait'),\n }),\n execute: async (args) => {\n await new Promise((r) => setTimeout(r, args.seconds * 1000));\n return `Waited ${args.seconds} seconds`;\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\n\nexport function createDoneTool(): AgentTool {\n return {\n description: 'Signal that the task is complete. Call this when you have finished the task or cannot proceed further.',\n inputSchema: z.object({\n success: z.boolean().describe('Whether the task was completed successfully'),\n text: z.string().describe('Summary of the result or explanation of failure'),\n }),\n execute: async (args) => {\n return JSON.stringify({ done: true, success: args.success, text: args.text });\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport { createInterface } from 'node:readline';\n\nexport function createAskUserTool(): AgentTool {\n return {\n description: 'Ask the user a question when you need clarification or input to proceed.',\n inputSchema: z.object({\n question: z.string().describe('The question to ask the user'),\n }),\n execute: async (args) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise<string>((resolve) => {\n rl.question(`\\n🤖 Agent asks: ${args.question}\\n> `, (answer) => {\n rl.close();\n resolve(`User answered: ${answer}`);\n });\n });\n },\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\n\nexport function createExecuteJsTool(page: IPage): AgentTool {\n return {\n description: 'Execute JavaScript code on the current page. Returns the result.',\n inputSchema: z.object({\n code: z.string().describe('JavaScript code to execute on the page'),\n }),\n execute: async (args) => {\n const result = await page.evaluate(args.code);\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n },\n };\n}\n","import type { AgentTool } from '../../types/agent.js';\nimport type { IPage } from '../../types/page.js';\nimport { createClickTool } from './click.js';\nimport { createTypeTool } from './type.js';\nimport { createScrollTool } from './scroll.js';\nimport { createSelectTool } from './select.js';\nimport { createWaitTool } from './wait.js';\nimport { createDoneTool } from './done.js';\nimport { createAskUserTool } from './ask-user.js';\nimport { createExecuteJsTool } from './execute-js.js';\n\nexport function createDefaultTools(page: IPage): Record<string, AgentTool> {\n return {\n click_element_by_index: createClickTool(page),\n input_text: createTypeTool(page),\n scroll: createScrollTool(page),\n select_dropdown_option: createSelectTool(page),\n wait: createWaitTool(),\n done: createDoneTool(),\n ask_user: createAskUserTool(),\n execute_javascript: createExecuteJsTool(page),\n };\n}\n","import { z } from 'zod';\nimport type { AgentTool } from '../types/agent.js';\nimport type { MacroTool } from '../llm/client.js';\nimport { normalizeResponse } from './auto-fixer.js';\n\nexport function packMacroTool(\n tools: Record<string, AgentTool>\n): MacroTool {\n // Build the action union schema\n const actionSchemas: z.ZodTypeAny[] = [];\n const toolNames: string[] = [];\n\n for (const [name, tool] of Object.entries(tools)) {\n toolNames.push(name);\n actionSchemas.push(\n z.object({ [name]: tool.inputSchema }).describe(tool.description)\n );\n }\n\n const actionSchema = actionSchemas.length === 1\n ? actionSchemas[0]\n : z.union(actionSchemas as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]]);\n\n const macroSchema = z.object({\n evaluation_previous_goal: z.string().optional().describe('Evaluate whether the previous goal was achieved'),\n memory: z.string().optional().describe('Important information to remember for future steps'),\n next_goal: z.string().optional().describe('The next immediate goal to achieve'),\n action: actionSchema.describe('The action to take'),\n });\n\n return {\n name: 'AgentOutput',\n description: 'The agent\\'s output containing reflection and action. Must be called every step.',\n schema: macroSchema,\n execute: async (args: Record<string, unknown>) => {\n // Normalize messy LLM output\n const normalized = normalizeResponse(args, 'AgentOutput', toolNames, tools);\n const action = normalized.action as Record<string, unknown>;\n\n // Find the tool to execute\n const [toolName, toolInput] = Object.entries(action)[0];\n const tool = tools[toolName];\n\n if (!tool) {\n return `Error: Unknown tool \"${toolName}\". Available: ${toolNames.join(', ')}`;\n }\n\n try {\n const result = await tool.execute(toolInput as any);\n return result;\n } catch (err) {\n return `Error executing ${toolName}: ${err}`;\n }\n },\n };\n}\n","import type { z } from 'zod';\nimport type { AgentTool } from '../types/agent.js';\n\n/**\n * Normalize messy LLM responses into valid MacroTool output.\n * Uses tool schemas for validation instead of hardcoded tool names.\n */\nexport function normalizeResponse(\n raw: Record<string, unknown>,\n toolName: string,\n availableActions: string[],\n toolSchemas?: Record<string, AgentTool>,\n): Record<string, unknown> {\n let result = { ...raw };\n\n // Fix 1: Nested function wrapper — unwrap {type: 'function', function: {arguments}}\n if (result.type === 'function' && result.function) {\n const fn = result.function as Record<string, unknown>;\n if (typeof fn.arguments === 'string') {\n try { result = JSON.parse(fn.arguments); } catch {}\n } else if (typeof fn.arguments === 'object') {\n result = fn.arguments as Record<string, unknown>;\n }\n }\n\n // Fix 2: Double-stringified arguments\n for (const [key, value] of Object.entries(result)) {\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === 'object' && parsed !== null) {\n result[key] = parsed;\n }\n } catch {}\n }\n }\n\n // Fix 3: If no action field, try to infer one\n if (!result.action) {\n for (const actionName of availableActions) {\n if (actionName in result) {\n result = {\n ...result,\n action: { [actionName]: result[actionName] },\n };\n delete result[actionName];\n break;\n }\n }\n }\n\n // Fix 4: Still no action — fallback to wait\n if (!result.action) {\n result.action = { wait: { seconds: 1 } };\n }\n\n // Fix 5: Action is a string instead of object\n if (typeof result.action === 'string') {\n if (availableActions.includes(result.action)) {\n result.action = { [result.action]: {} };\n } else {\n result.action = { wait: { seconds: 1 } };\n }\n }\n\n // Fix 6: Schema-based validation & primitive coercion\n const action = result.action as Record<string, unknown>;\n for (const [name, input] of Object.entries(action)) {\n if (typeof input !== 'object' || input === null) {\n // Use schema to determine expected shape\n if (toolSchemas && toolSchemas[name]) {\n const schema = toolSchemas[name].inputSchema;\n const coerced = coercePrimitiveToSchema(input, schema);\n if (coerced !== null) {\n action[name] = coerced;\n continue;\n }\n }\n\n // Fallback: hardcoded coercion for known patterns\n if (typeof input === 'number') {\n action[name] = { index: input };\n } else if (typeof input === 'string') {\n action[name] = { text: input };\n } else {\n action[name] = {};\n }\n }\n\n // Fix 7: Validate action args against schema if available\n if (toolSchemas && toolSchemas[name] && typeof action[name] === 'object') {\n const schema = toolSchemas[name].inputSchema;\n const validation = schema.safeParse(action[name]);\n if (!validation.success) {\n // Try to fix common issues: wrong field names, missing required fields\n const fixed = attemptSchemaFix(action[name] as Record<string, unknown>, schema, validation.error);\n if (fixed) {\n action[name] = fixed;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Coerce a primitive value into an object matching a Zod schema.\n * Inspects the schema to find a single required field and wraps the value.\n */\nfunction coercePrimitiveToSchema(value: unknown, schema: z.ZodType): Record<string, unknown> | null {\n try {\n const def = (schema as any)._def;\n if (def?.typeName !== 'ZodObject') return null;\n\n const shape = def.shape();\n const keys = Object.keys(shape);\n\n // Single required field — wrap the primitive\n const requiredKeys = keys.filter((k) => {\n const fieldDef = (shape[k] as any)?._def;\n return fieldDef?.typeName !== 'ZodOptional';\n });\n\n if (requiredKeys.length === 1) {\n return { [requiredKeys[0]]: value };\n }\n\n // Multiple fields but value is a number — likely an index field\n const indexField = keys.find((k) => /index|idx|num|number/i.test(k));\n if (indexField && typeof value === 'number') {\n return { [indexField]: value };\n }\n\n // Value is a string — likely a text field\n const textField = keys.find((k) => /text|value|query|code|question|url/i.test(k));\n if (textField && typeof value === 'string') {\n return { [textField]: value };\n }\n } catch {}\n\n return null;\n}\n\n/**\n * Attempt to fix validation errors by mapping common mistakes.\n */\nfunction attemptSchemaFix(\n input: Record<string, unknown>,\n schema: z.ZodType,\n error: z.ZodError,\n): Record<string, unknown> | null {\n try {\n const def = (schema as any)._def;\n if (def?.typeName !== 'ZodObject') return null;\n\n const shape = def.shape();\n const expectedKeys = Object.keys(shape);\n const inputKeys = Object.keys(input);\n const fixed = { ...input };\n\n // Fix: wrong key names — try to map by position or type match\n for (const issue of error.issues) {\n if (issue.code === 'invalid_type' && issue.path.length === 1) {\n const key = String(issue.path[0]);\n const val = input[key];\n // Try type coercion\n if (issue.expected === 'number' && typeof val === 'string') {\n const num = Number(val);\n if (!isNaN(num)) fixed[key] = num;\n } else if (issue.expected === 'string' && typeof val === 'number') {\n fixed[key] = String(val);\n } else if (issue.expected === 'boolean' && typeof val === 'string') {\n fixed[key] = val === 'true';\n }\n }\n\n if (issue.code === 'unrecognized_keys') {\n // Remove unrecognized keys\n for (const k of (issue as any).keys || []) {\n delete fixed[k];\n }\n }\n }\n\n // Re-validate\n const result = schema.safeParse(fixed);\n if (result.success) return fixed;\n } catch {}\n\n return null;\n}\n\nexport function safeJsonParse(str: string): unknown {\n try {\n return JSON.parse(str);\n } catch {\n return str;\n }\n}\n\nexport function extractJsonFromString(str: string): unknown | null {\n const start = str.indexOf('{');\n const end = str.lastIndexOf('}');\n if (start === -1 || end === -1 || end <= start) return null;\n try {\n return JSON.parse(str.slice(start, end + 1));\n } catch {\n return null;\n }\n}\n","/**\n * Domain Guard — restrict which websites LobsterCLI can operate on.\n *\n * Three modes:\n * - No config: works on all websites (default)\n * - allowDomains: whitelist — ONLY these sites work\n * - blockDomains: blacklist — everything EXCEPT these sites works\n *\n * Usage (library):\n * import { DomainGuard } from 'lobster-cli'\n * const guard = new DomainGuard({ allowDomains: ['bloomberg.com', 'yahoo.com'] })\n * guard.check('https://bloomberg.com/markets') // → ok\n * guard.check('https://reddit.com') // → throws\n *\n * Usage (config):\n * lobster config set domains.allow \"bloomberg.com,yahoo.com\"\n * lobster config set domains.blockMessage \"This tool only works on finance sites.\"\n */\n\nexport interface DomainGuardConfig {\n /** Whitelist — only these domains are allowed. Empty = allow all. */\n allowDomains?: string[];\n /** Blacklist — these domains are blocked. Ignored if allowDomains is set. */\n blockDomains?: string[];\n /** Custom message shown when a domain is blocked. */\n blockMessage?: string;\n /** Allow subdomains to match (e.g., \"yahoo.com\" matches \"finance.yahoo.com\"). Default: true */\n matchSubdomains?: boolean;\n}\n\nconst DEFAULT_BLOCK_MESSAGE = 'This domain is not allowed by the current configuration.';\n\nexport class DomainGuard {\n private allow: string[];\n private block: string[];\n private message: string;\n private matchSubs: boolean;\n\n constructor(config: DomainGuardConfig = {}) {\n this.allow = (config.allowDomains || []).map(d => d.toLowerCase().replace(/^www\\./, ''));\n this.block = (config.blockDomains || []).map(d => d.toLowerCase().replace(/^www\\./, ''));\n this.message = config.blockMessage || DEFAULT_BLOCK_MESSAGE;\n this.matchSubs = config.matchSubdomains ?? true;\n }\n\n /**\n * Check if a URL is allowed. Returns true if allowed, throws if blocked.\n */\n check(url: string): true {\n // No restrictions configured — allow everything\n if (this.allow.length === 0 && this.block.length === 0) return true;\n\n const domain = this.extractDomain(url);\n if (!domain) return true; // Can't parse = allow (for local files, etc.)\n\n // Whitelist mode: only allowed domains pass\n if (this.allow.length > 0) {\n if (!this.matches(domain, this.allow)) {\n throw new DomainBlockedError(domain, this.message);\n }\n return true;\n }\n\n // Blacklist mode: blocked domains fail\n if (this.block.length > 0) {\n if (this.matches(domain, this.block)) {\n throw new DomainBlockedError(domain, this.message);\n }\n return true;\n }\n\n return true;\n }\n\n /**\n * Check without throwing — returns { allowed, domain, message }.\n */\n test(url: string): { allowed: boolean; domain: string; message?: string } {\n const domain = this.extractDomain(url);\n if (!domain) return { allowed: true, domain: '' };\n\n try {\n this.check(url);\n return { allowed: true, domain };\n } catch (err) {\n if (err instanceof DomainBlockedError) {\n return { allowed: false, domain, message: err.message };\n }\n return { allowed: true, domain };\n }\n }\n\n /**\n * Check if domain matches any pattern in the list.\n */\n private matches(domain: string, patterns: string[]): boolean {\n for (const pattern of patterns) {\n if (domain === pattern) return true;\n if (this.matchSubs && domain.endsWith('.' + pattern)) return true;\n }\n return false;\n }\n\n /**\n * Extract domain from URL, stripping www. prefix.\n */\n private extractDomain(url: string): string {\n try {\n const parsed = new URL(url.startsWith('http') ? url : 'https://' + url);\n return parsed.hostname.toLowerCase().replace(/^www\\./, '');\n } catch {\n return '';\n }\n }\n\n /**\n * Whether any restrictions are active.\n */\n get isRestricted(): boolean {\n return this.allow.length > 0 || this.block.length > 0;\n }\n\n /**\n * Get list of allowed domains (empty = all allowed).\n */\n get allowedDomains(): string[] {\n return [...this.allow];\n }\n\n /**\n * Get list of blocked domains.\n */\n get blockedDomains(): string[] {\n return [...this.block];\n }\n}\n\nexport class DomainBlockedError extends Error {\n public readonly domain: string;\n\n constructor(domain: string, message: string) {\n super(message);\n this.name = 'DomainBlockedError';\n this.domain = domain;\n }\n}\n","import Table from 'cli-table3';\n\nexport function renderTable(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const table = new Table({\n head: cols,\n style: { head: ['cyan'] },\n wordWrap: true,\n });\n\n for (const row of data) {\n table.push(cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val);\n }));\n }\n\n return table.toString();\n}\n","export function renderJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n","export function renderMarkdown(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [];\n\n lines.push('| ' + cols.join(' | ') + ' |');\n lines.push('| ' + cols.map(() => '---').join(' | ') + ' |');\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val).replace(/\\|/g, '\\\\|');\n });\n lines.push('| ' + vals.join(' | ') + ' |');\n }\n\n return lines.join('\\n');\n}\n","export function renderCsv(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [cols.join(',')];\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n const str = String(val);\n return str.includes(',') || str.includes('\"') || str.includes('\\n')\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n });\n lines.push(vals.join(','));\n }\n\n return lines.join('\\n');\n}\n","import yaml from 'js-yaml';\n\nexport function renderYaml(data: unknown): string {\n return yaml.dump(data, { indent: 2, lineWidth: 120 });\n}\n","import type { OutputFormat } from '../types/router.js';\nimport { renderTable } from './table.js';\nimport { renderJson } from './json.js';\nimport { renderMarkdown } from './markdown.js';\nimport { renderCsv } from './csv.js';\nimport { renderYaml } from './yaml.js';\n\nexport function render(data: unknown, format: OutputFormat, columns?: string[]): string {\n switch (format) {\n case 'table': return renderTable(data, columns);\n case 'json': return renderJson(data);\n case 'markdown': return renderMarkdown(data, columns);\n case 'csv': return renderCsv(data, columns);\n case 'yaml': return renderYaml(data);\n default: return renderJson(data);\n }\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC1BxB,IAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6JhC,SAAS,2BAA2B,cAAsB,KAAa;AAC5E,SAAO,wBAAwB,QAAQ,6BAA6B,wBAAwB,WAAW,GAAG;AAC5G;;;AC9JO,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACE7B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACJxB,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["readFileSync","body","resp","json","args","result","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","mkdirSync","readFileSync","writeFileSync","existsSync","el","nodes","isPdfUrl","isPdfResponse","extractPdf","duration","content","pdfParseFn","Strategy","writeFileSync","mkdirSync","existsSync","join","existsSync","mkdirSync","writeFileSync","join","yaml","readFileSync","join","z","z","z","z","z","z","z","z","z","z","readFileSync","join","yaml"]}