@shiplightai/sdk 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -10
- package/dist/agentHelpers-MRG6DCNX.js +4 -0
- package/dist/agentHelpers-MRG6DCNX.js.map +1 -0
- package/dist/agentLogin-QZDVIJMB.js +4 -0
- package/dist/agentLogin-QZDVIJMB.js.map +1 -0
- package/dist/chunk-DIRPNR2B.js +195 -0
- package/dist/chunk-DIRPNR2B.js.map +1 -0
- package/dist/chunk-FWACDSD6.js +17 -0
- package/dist/chunk-FWACDSD6.js.map +1 -0
- package/dist/chunk-GVEDIII4.js +25 -0
- package/dist/chunk-GVEDIII4.js.map +1 -0
- package/dist/{chunk-UHZTPBZ3.js → chunk-N54UPO3H.js} +95 -92
- package/dist/chunk-N54UPO3H.js.map +1 -0
- package/dist/chunk-ODNKMWXO.js +6 -0
- package/dist/chunk-ODNKMWXO.js.map +1 -0
- package/dist/{chunk-GPZJYXUG.js → chunk-SSPF674P.js} +19 -6
- package/dist/chunk-SSPF674P.js.map +1 -0
- package/dist/chunk-USNFIQN5.js +4 -0
- package/dist/chunk-USNFIQN5.js.map +1 -0
- package/dist/chunk-W6S73J4I.js +4 -0
- package/dist/chunk-W6S73J4I.js.map +1 -0
- package/dist/handler-O7GYRDNA.js +4 -0
- package/dist/handler-O7GYRDNA.js.map +1 -0
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -0
- package/dist/task-E5YOHPFW.js +193 -0
- package/dist/task-E5YOHPFW.js.map +1 -0
- package/package.json +13 -13
- package/dist/agentHelpers-UCLT5EKK.js +0 -1
- package/dist/agentLogin-ARB3NEO4.js +0 -1
- package/dist/chunk-6H2NJBNL.js +0 -1
- package/dist/chunk-GDTCZALZ.js +0 -192
- package/dist/chunk-KFC5I6R5.js +0 -14
- package/dist/chunk-QIBDXB3J.js +0 -22
- package/dist/chunk-UFLZ3URR.js +0 -1
- package/dist/chunk-YR4E7JSB.js +0 -3
- package/dist/handler-TPOFKKIB.js +0 -1
- package/dist/task-57MAWXLN.js +0 -190
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
import{e as u,h as p,i as f}from"./chunk-W6S73J4I.js";var $=class{getLevel(){return u.get("logLevel")}debug(...t){this.getLevel()<=0&&console.debug("[DEBUG]",...t)}info(...t){this.getLevel()<=1&&console.log("[INFO]",...t)}log(...t){this.info(...t)}warn(...t){this.getLevel()<=2&&console.warn("[WARN]",...t)}error(...t){this.getLevel()<=3&&console.error("[ERROR]",...t)}setLevel(t){u.set("logLevel",t)}},x=new $,i=x;var b={};f(b,{ACTION_TIMEOUT:()=>g,GOTO_TIMEOUT:()=>m,LOCATOR_TIMEOUT:()=>c,getLocator:()=>v,getMinimalActionEntity:()=>E,getPageLocatorExpression:()=>h,sanitizeForComment:()=>L});function L(t){return t.replace(/\r\n/g," ").replace(/\n/g," ").replace(/\r/g," ").trim()}function v(t,e){let a=h(e);return a?new Function("page",`return ${a}`)(t):null}function E(t){let e={action_data:t.action_data};return t.locator&&(e.locator=t.locator),t.xpath&&(e.xpath=t.xpath),t.frame_path&&(e.frame_path=t.frame_path),e}function _(t){let e=t.frame_path;return!e||e.length===0?"page":`page.frameLocator('${e[0]}')`}function O(t){let e=t.xpath;return typeof e=="string"&&e.trim()?!e.startsWith("xpath=")&&!e.startsWith("/")&&!e.startsWith("//")?`xpath=//${e}`:e.startsWith("xpath=")?e:`xpath=${e}`:null}function h(t){let e=_(t),a=t.locator;if(typeof a=="string"&&a.trim())return a=a.trim(),a.endsWith("first()")?`${e}.${a}`:`${e}.${a}.first()`;let r=O(t);if(r){let l=JSON.stringify(r);return`${e}.locator(${l}).first()`}return null}var c,g,m,d=p(()=>{c=5e3,g=1e4,m=6e4});d();async function y(t,e,a=[]){try{let r=t;for(let o of a)r=r.frameLocator(o);let l=await r.locator(`xpath=${e}`).elementHandle({timeout:c});if(!l)return i.warn(`Could not find element with xpath: ${e}`),null;let n=await t.evaluate(o=>typeof playwright<"u"&&playwright.generateLocator?playwright.generateLocator(o):null,l);return await l.dispose(),n?(i.debug(`Generated locator for ${e}: ${n}`),n):(i.debug("playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback"),null)}catch(r){return i.error(`Error in pickBestLocator: ${r}`),null}}async function C(t,e){try{let a=await t.evaluate(r=>typeof playwright<"u"&&playwright.generateLocator?playwright.generateLocator(r):null,e);return await e.dispose(),a?(i.debug(`Generated locator: ${a}`),a):(i.debug("playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback"),null)}catch(a){return i.error(`Error in pickBestLocator: ${a}`),null}}async function S(t,e){if(e<0)return;let{page:a,domService:r}=t;return(t.domState||await r.getClickableElements(a)).selectorMap.get(e)}function T(t){let e=t.split("/").filter(l=>l);if(e.length===0)return"*";let a=e[e.length-1],r=a.match(/^(\w+)(?:\[(\d+)\])?$/);if(r){let[,l,n]=r;return n?`${l}:nth-of-type(${n})`:l}return a}function W(t,e=!0){try{let a=T(t.xpath);if(t.attributes.class&&e){let l=/^[a-zA-Z_][a-zA-Z0-9_-]*$/,n=t.attributes.class.split(/\s+/);for(let o of n)o.trim()&&l.test(o)&&(a+=`.${o}`)}let r=new Set(["id","name","type","placeholder","aria-label","aria-labelledby","aria-describedby","role","for","autocomplete","required","readonly","alt","title","target"]);e&&["data-id","data-qa","data-cy","data-testid","data-handlepos"].forEach(l=>r.add(l));for(let[l,n]of Object.entries(t.attributes)){if(l==="class"||!l.trim()||!r.has(l))continue;let o=l.replace(/:/g,"\\:");if(n==="")a+=`[${o}]`;else if(/["'<>`\n\r\t]/.test(n)){let s=n;n.includes(`
|
|
4
|
+
`)&&(s=n.split(`
|
|
5
|
+
`)[0]),s=s.replace(/\s+/g," ").trim();let w=s.replace(/"/g,'\\"');a+=`[${o}*="${w}"]`}else a+=`[${o}="${n}"]`}return a}catch{return`${t.tagName||"*"}[highlight_index='${t.highlightIndex}']`}}function A(t){let e=[],a=t;for(;a&&a.parent!==null;){let n=a.parent;e.push(n),a=n}e.reverse();let r=[],l=e.filter(n=>n.tagName==="iframe");for(let n of l){let o=W(n,!0);r.push(o)}return r}async function z(t,e){let a=null,r=A(e);return e.xpath&&(a=await y(t,e.xpath)),{locator:a||void 0,xpath:e.xpath,frame_path:r}}export{i as a,b,v as c,g as d,m as e,d as f,C as g,S as h,z as i};
|
|
6
|
+
//# sourceMappingURL=chunk-ODNKMWXO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../sdk-core/src/utils/logger.ts","../../sdk-core/src/actions/utils.ts","../../sdk-core/src/dom/utils/locator.ts","../../sdk-core/src/llm_tools/utils.ts"],"sourcesContent":["/**\n * Simple logger for test runtime\n */\n\nimport sdkConfig from '../config';\nimport { LogLevel } from './logLevel';\n\n// Re-export LogLevel for convenience\nexport { LogLevel };\n\nclass Logger {\n /**\n * Get current log level from SDK config\n * This is read dynamically so configureSdk() changes take effect immediately\n */\n private getLevel(): LogLevel {\n return sdkConfig.get('logLevel');\n }\n\n debug(...args: any[]): void {\n if (this.getLevel() <= LogLevel.DEBUG) {\n console.debug('[DEBUG]', ...args);\n }\n }\n\n info(...args: any[]): void {\n if (this.getLevel() <= LogLevel.INFO) {\n console.log('[INFO]', ...args);\n }\n }\n\n log(...args: any[]): void {\n this.info(...args);\n }\n\n warn(...args: any[]): void {\n if (this.getLevel() <= LogLevel.WARN) {\n console.warn('[WARN]', ...args);\n }\n }\n\n error(...args: any[]): void {\n if (this.getLevel() <= LogLevel.ERROR) {\n console.error('[ERROR]', ...args);\n }\n }\n\n setLevel(level: LogLevel): void {\n // Update the SDK config so it persists\n sdkConfig.set('logLevel', level);\n }\n}\n\n// Export singleton instance\nconst logger = new Logger();\nexport default logger;","/**\n * Shared utility functions for actions\n */\n\nimport { Locator } from 'playwright';\nimport { ActionEntity } from './types';\n\nexport const LOCATOR_TIMEOUT = 5000;\nexport const ACTION_TIMEOUT = 10000;\nexport const GOTO_TIMEOUT = 60000;\n\n/**\n * Sanitize a string for use in single-line comments\n * Replaces newlines with spaces to prevent code injection when\n * multi-line strings are used in step descriptions\n */\nexport function sanitizeForComment(str: string): string {\n return str\n .replace(/\\r\\n/g, ' ')\n .replace(/\\n/g, ' ')\n .replace(/\\r/g, ' ')\n .trim();\n}\n\n/**\n * Get locator for an action entity\n * Priority: locator > xpath\n */\nexport function getLocator(page: any, actionEntity: ActionEntity): Locator | null {\n const locatorExpression = getPageLocatorExpression(actionEntity);\n if (!locatorExpression) {\n return null;\n }\n\n const locatorFn = new Function('page', `return ${locatorExpression}`);\n return locatorFn(page);\n}\n\n/**\n * Create a minimal ActionEntity with only fields needed by getLocator()\n * Used for transpilation to generate clean code without unnecessary metadata\n *\n * Includes:\n * - action_data (required for all actions)\n * - locator fields used by getLocator() with priority: locator > xpath\n * - frame_path (for iframe handling)\n *\n * Excludes: url, action_description, feedback, text, tag, class, and other metadata\n */\nexport function getMinimalActionEntity(actionEntity: ActionEntity): Partial<ActionEntity> {\n const minimal: Partial<ActionEntity> = {\n action_data: actionEntity.action_data,\n };\n\n // Include locator fields if present (used by getLocator with priority order)\n if (actionEntity.locator) minimal.locator = actionEntity.locator;\n if (actionEntity.xpath) minimal.xpath = actionEntity.xpath;\n if (actionEntity.frame_path) minimal.frame_path = actionEntity.frame_path;\n\n return minimal;\n}\n\n/**\n * Get the frame expression for transpilation\n */\nfunction getFrameExpression(actionEntity: ActionEntity): string {\n const framePath = actionEntity.frame_path;\n if (!framePath || framePath.length === 0) {\n return 'page';\n }\n return `page.frameLocator('${framePath[0]}')`;\n}\n\n/**\n * Get selector string from action entity (prioritizes xpath)\n */\nfunction getSelectorForAction(actionEntity: ActionEntity): string | null {\n // Priority 1: XPath\n const xpath = actionEntity.xpath;\n if (typeof xpath === 'string' && xpath.trim()) {\n if (!xpath.startsWith('xpath=') && !xpath.startsWith('/') && !xpath.startsWith('//')) {\n return `xpath=//${xpath}`;\n }\n return xpath.startsWith('xpath=') ? xpath : `xpath=${xpath}`;\n }\n\n return null;\n}\n\n/**\n * Get Playwright locator expression for transpilation\n * Returns a string like: page.getByRole('link', { name: 'Issues' }).first()\n * or: page.locator('#issues-tab').first()\n */\nexport function getPageLocatorExpression(actionEntity: ActionEntity): string | null {\n const frameExpression = getFrameExpression(actionEntity);\n\n // Priority 1: Use locator field if present (Playwright locator method)\n let locator = actionEntity.locator;\n if (typeof locator === 'string' && locator.trim()) {\n locator = locator.trim();\n // Avoid multi element locator errors\n if (locator.endsWith('first()')) {\n // If it already has .first(), assume it's a complete expression\n return `${frameExpression}.${locator}`;\n } else {\n return `${frameExpression}.${locator}.first()`;\n }\n }\n\n // Priority 2: Fall back to selector (xpath)\n const selector = getSelectorForAction(actionEntity);\n if (selector) {\n const escapedSelector = JSON.stringify(selector);\n return `${frameExpression}.locator(${escapedSelector}).first()`;\n }\n\n return null;\n}\n","/**\n * Locator Generation Utilities\n *\n * Provides utilities for generating Playwright locators for DOM elements.\n * Ported from webagent/agent_backend/base/dom_utils.py\n */\n\nimport { ElementHandle, FrameLocator, Page } from 'playwright';\nimport logger from '../../utils/logger';\nimport { LOCATOR_TIMEOUT } from '../../actions/utils';\n\n/**\n * Pick the best Playwright locator for a given element using Playwright's built-in locator generator.\n *\n * This function uses Playwright's internal `playwright.generateLocator()` function which is\n * available when PWDEBUG=console is set in the environment.\n *\n * @param page - Playwright page instance\n * @param xpath - XPath of the element to generate locator for\n * @returns Best Playwright locator string, or null if generation fails\n *\n * @example\n * ```typescript\n * const locator = await pickBestLocator(page, '//div[@id=\"submit-button\"]');\n * // Returns: 'getByRole(\"button\", { name: \"Submit\" })'\n * ```\n */\nexport async function pickBestLocator(page: Page, xpath: string, frame_path: string[] = []): Promise<string | null> {\n try {\n // First, get the element handle using xpath\n let frame = page as unknown as FrameLocator;\n for (const frameSelector of frame_path) {\n frame = frame.frameLocator(frameSelector);\n }\n const elementHandle = await frame.locator(`xpath=${xpath}`).elementHandle({ timeout: LOCATOR_TIMEOUT });\n\n if (!elementHandle) {\n logger.warn(`Could not find element with xpath: ${xpath}`);\n return null;\n }\n\n // Use Playwright's built-in locator generator\n // This requires PWDEBUG=console to be set in the environment\n const bestLocator = await page.evaluate(\n (el: Element) => {\n // @ts-ignore - playwright global is injected by Playwright when PWDEBUG=console\n if (typeof playwright !== 'undefined' && playwright.generateLocator) {\n // @ts-ignore\n return playwright.generateLocator(el);\n }\n return null;\n },\n elementHandle\n );\n\n // Clean up element handle\n await elementHandle.dispose();\n\n if (bestLocator) {\n logger.debug(`Generated locator for ${xpath}: ${bestLocator}`);\n return bestLocator as string;\n }\n\n logger.debug('playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback');\n return null;\n } catch (error) {\n logger.error(`Error in pickBestLocator: ${error}`);\n return null;\n }\n}\n\nexport async function pickBestLocatorForElement(page: Page, elementHandle: ElementHandle<HTMLElement>): Promise<string | null> {\n try {\n // First, get the element handle using xpath\n // Use Playwright's built-in locator generator\n // This requires PWDEBUG=console to be set in the environment\n const bestLocator = await page.evaluate(\n (el: Element) => {\n // @ts-ignore - playwright global is injected by Playwright when PWDEBUG=console\n if (typeof playwright !== 'undefined' && playwright.generateLocator) {\n // @ts-ignore\n return playwright.generateLocator(el);\n }\n return null;\n },\n elementHandle\n );\n\n // Clean up element handle\n await elementHandle.dispose();\n\n if (bestLocator) {\n logger.debug(`Generated locator: ${bestLocator}`);\n return bestLocator as string;\n }\n\n logger.debug('playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback');\n return null;\n } catch (error) {\n logger.error(`Error in pickBestLocator: ${error}`);\n return null;\n }\n}\n\n/**\n * Generate locators for multiple elements in batch\n *\n * @param page - Playwright page instance\n * @param xpaths - Array of XPaths to generate locators for\n * @returns Map of xpath -> locator string\n */\nexport async function pickBestLocators(\n page: Page,\n xpaths: string[]\n): Promise<Map<string, string | null>> {\n const results = new Map<string, string | null>();\n\n // Process in parallel for better performance\n await Promise.all(\n xpaths.map(async (xpath) => {\n const locator = await pickBestLocator(page, xpath);\n results.set(xpath, locator);\n })\n );\n\n return results;\n}\n\n/**\n * Check if Playwright locator generator is available\n *\n * @param page - Playwright page instance\n * @returns true if playwright.generateLocator is available\n */\nexport async function isLocatorGeneratorAvailable(page: Page): Promise<boolean> {\n try {\n const available = await page.evaluate(() => {\n // @ts-ignore\n return typeof playwright !== 'undefined' && typeof playwright.generateLocator === 'function';\n });\n return available;\n } catch {\n return false;\n }\n}\n\n/**\n * Fallback locator generation when playwright.generateLocator is not available\n *\n * Generates a simple locator based on xpath\n *\n * @param xpath - XPath of the element\n * @returns Fallback locator string\n */\nexport function getFallbackLocator(xpath: string): string {\n return `xpath=${xpath}`;\n}\n","import { Page } from \"playwright\";\nimport { ActionEntityLocatorInfo } from \"../actions/types\";\nimport { DOMElementNode } from \"../dom/types\";\nimport { pickBestLocator } from \"../dom/utils/locator\";\nimport { ToolExecutionContext } from \"./types\";\n\nexport async function getDomElementByIndex(\n ctx: ToolExecutionContext,\n index: number,\n): Promise<DOMElementNode | undefined> {\n if (index < 0) {\n return undefined;\n }\n const { page, domService } = ctx;\n const domState = (ctx as any).domState || (await domService.getClickableElements(page));\n const domElement = domState.selectorMap.get(index);\n return domElement;\n}\n\n/**\n * Converts a simple XPath to a CSS selector\n */\nfunction convertSimpleXPathToCssSelector(xpath: string): string {\n // Simple conversion - handles basic xpath like \"html/body/div[1]/span\"\n const parts = xpath.split('/').filter(p => p);\n if (parts.length === 0) return '*';\n \n // Take the last element and extract tag name and index\n const lastPart = parts[parts.length - 1];\n const match = lastPart.match(/^(\\w+)(?:\\[(\\d+)\\])?$/);\n \n if (match) {\n const [, tagName, index] = match;\n if (index) {\n return `${tagName}:nth-of-type(${index})`;\n }\n return tagName;\n }\n \n return lastPart;\n}\n\n/**\n * Creates an enhanced CSS selector for a DOM element, handling various edge cases\n * Ported from Python's _enhanced_css_selector_for_element\n */\nfunction enhancedCssSelectorForElement(\n element: DOMElementNode,\n includeDynamicAttributes: boolean = true\n): string {\n try {\n // Get base selector from XPath\n let cssSelector = convertSimpleXPathToCssSelector(element.xpath);\n\n // Handle class attributes\n if (element.attributes.class && includeDynamicAttributes) {\n const validClassNamePattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;\n const classes = element.attributes.class.split(/\\s+/);\n \n for (const className of classes) {\n if (!className.trim()) continue;\n \n if (validClassNamePattern.test(className)) {\n cssSelector += `.${className}`;\n }\n }\n }\n\n // Safe attributes that are stable and useful for selection\n const SAFE_ATTRIBUTES = new Set([\n 'id',\n 'name',\n 'type',\n 'placeholder',\n 'aria-label',\n 'aria-labelledby',\n 'aria-describedby',\n 'role',\n 'for',\n 'autocomplete',\n 'required',\n 'readonly',\n 'alt',\n 'title',\n // 'src',\n // 'href',\n 'target',\n ]);\n\n if (includeDynamicAttributes) {\n const dynamicAttributes = [\n 'data-id',\n 'data-qa',\n 'data-cy',\n 'data-testid',\n 'data-handlepos',\n ];\n dynamicAttributes.forEach(attr => SAFE_ATTRIBUTES.add(attr));\n }\n\n // Handle other attributes\n for (const [attribute, value] of Object.entries(element.attributes)) {\n if (attribute === 'class') continue;\n if (!attribute.trim()) continue;\n if (!SAFE_ATTRIBUTES.has(attribute)) continue;\n\n // Escape special characters in attribute names\n const safeAttribute = attribute.replace(/:/g, '\\\\:');\n\n // Handle different value cases\n if (value === '') {\n cssSelector += `[${safeAttribute}]`;\n } else if (/[\"'<>`\\n\\r\\t]/.test(value)) {\n // Use contains for values with special characters\n let processedValue = value;\n \n // For newline-containing text, only use the part before the newline\n if (value.includes('\\n')) {\n processedValue = value.split('\\n')[0];\n }\n \n // Collapse whitespace and strip\n processedValue = processedValue.replace(/\\s+/g, ' ').trim();\n \n // Escape embedded double-quotes\n const safeValue = processedValue.replace(/\"/g, '\\\\\"');\n cssSelector += `[${safeAttribute}*=\"${safeValue}\"]`;\n } else {\n cssSelector += `[${safeAttribute}=\"${value}\"]`;\n }\n }\n\n return cssSelector;\n } catch (error) {\n // Fallback to a more basic selector if something goes wrong\n const tagName = element.tagName || '*';\n return `${tagName}[highlight_index='${element.highlightIndex}']`;\n }\n}\n\n/**\n * Gets the frame path to an element (list of iframe CSS selectors)\n * Ported from Python's get_frame_path\n */\nexport function getFramePath(element: DOMElementNode): string[] {\n // Start with the target element and collect all parents\n const parents: DOMElementNode[] = [];\n let current: DOMElementNode | null = element;\n \n while (current && current.parent !== null) {\n const parent: DOMElementNode = current.parent;\n parents.push(parent);\n current = parent;\n }\n\n // Reverse the parents list to process from top to bottom\n parents.reverse();\n \n // Process all iframe parents in sequence\n const framePath: string[] = [];\n const iframes = parents.filter(item => item.tagName === 'iframe');\n \n for (const iframe of iframes) {\n const cssSelector = enhancedCssSelectorForElement(iframe, true);\n framePath.push(cssSelector);\n }\n \n return framePath;\n}\n\nexport async function getActionEntityLocatorInfo(\n page: Page,\n domElement: DOMElementNode,\n): Promise<ActionEntityLocatorInfo> {\n // Generate the best Playwright locator for this element\n let locator: string | null = null;\n // Get frame path\n const framePath = getFramePath(domElement);\n\n if (domElement.xpath) {\n locator = await pickBestLocator(page, domElement.xpath);\n }\n\n const locatorInfo: ActionEntityLocatorInfo = {\n locator: locator || undefined,\n xpath: domElement.xpath,\n frame_path: framePath,\n };\n return locatorInfo;\n}\n"],"mappings":"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","names":["Logger","config_default","args","level","logger","logger_default","utils_exports","__export","ACTION_TIMEOUT","GOTO_TIMEOUT","LOCATOR_TIMEOUT","getLocator","getMinimalActionEntity","getPageLocatorExpression","sanitizeForComment","str","page","actionEntity","locatorExpression","minimal","getFrameExpression","framePath","getSelectorForAction","xpath","frameExpression","locator","selector","escapedSelector","init_utils","__esmMin","init_utils","pickBestLocator","page","xpath","frame_path","frame","frameSelector","elementHandle","LOCATOR_TIMEOUT","logger_default","bestLocator","el","error","pickBestLocatorForElement","getDomElementByIndex","ctx","index","page","domService","convertSimpleXPathToCssSelector","xpath","parts","p","lastPart","match","tagName","enhancedCssSelectorForElement","element","includeDynamicAttributes","cssSelector","validClassNamePattern","classes","className","SAFE_ATTRIBUTES","attr","attribute","value","safeAttribute","processedValue","safeValue","getFramePath","parents","current","parent","framePath","iframes","item","iframe","getActionEntityLocatorInfo","domElement","locator","pickBestLocator"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
`)}};var
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
import{a as h}from"./chunk-ODNKMWXO.js";import{g as I}from"./chunk-W6S73J4I.js";import{z as v}from"zod";var U=class{constructor(){this.tools=new Map}register(e){if(this.tools.has(e.name))throw new Error(`Tool '${e.name}' is already registered`);let i={name:e.name,description:e.description,schema:e.schema,execute:e.execute,usesElementIndex:e.usesElementIndex??!1,availability:{openai:e.availability?.openai??!0,mcp:e.availability?.mcp??!0}};this.tools.set(e.name,i)}get(e){return this.tools.get(e)}has(e){return this.tools.has(e)}getToolNames(){return Array.from(this.tools.keys())}getTools(){return Array.from(this.tools.values())}async execute(e,i,o){let a=this.tools.get(e);if(!a)throw new Error(`Tool not found: ${e}`);try{let t=i?.description,l={...i};delete l.description;let n=a.schema.parse(l),c={...o,actionDescription:t};return await a.execute(n,c)}catch(t){if(t instanceof v.ZodError){let l=t.issues.map(n=>`${n.path.join(".")}: ${n.message}`).join(", ");return{success:!1,error:`Invalid arguments for tool '${e}': ${l}`,actionEntity:{action_description:i?.description||`${e} (validation failed)`,action_data:{action_name:e,kwargs:i},feedback:`Validation error: ${l}`}}}throw t}}clear(){this.tools.clear()}size(){return this.tools.size}buildActionUnionSchema(){let e=this.getTools().filter(i=>i.availability.openai);return this.buildUnionSchemaFromTools(e)}buildActionUnionSchemaForTools(e,i=!1){let o=new Set(e),a=this.getTools().filter(t=>o.has(t.name));return this.buildUnionSchemaFromTools(a,i)}buildUnionSchemaFromTools(e,i=!1){if(e.length===0)return v.object({done:v.any()});let o=e.map(n=>{let c=n.schema;if(i&&c instanceof v.ZodObject){let r=c._def.shape();c=v.object({...r,description:v.string().describe("Semantic, human-readable description of the action")})}if(c instanceof v.ZodObject){let r=c._def.shape();Object.keys(r).length===0&&(c=v.object({_empty:v.boolean().optional()}))}return v.object({[n.name]:c})});if(o.length===1)return o[0];let[a,t,...l]=o;return v.union([a,t,...l])}},ne=new U;import{createAnthropic as q}from"@ai-sdk/anthropic";function L(e){let i=I().env?.ANTHROPIC_API_KEY;if(!i)throw new Error("ANTHROPIC_API_KEY not configured in SDK config");return h.debug(`Using Anthropic provider: model=${e}`),q({apiKey:i})(e)}function H(e){return{anthropic:{structuredOutputMode:"jsonTool"}}}import{createGoogleGenerativeAI as K}from"@ai-sdk/google";import{createVertex as J}from"@ai-sdk/google-vertex";var A={MEDIA_RESOLUTION_HIGH:"MEDIA_RESOLUTION_HIGH",MEDIA_RESOLUTION_MEDIUM:"MEDIA_RESOLUTION_MEDIUM",MEDIA_RESOLUTION_LOW:"MEDIA_RESOLUTION_LOW"};function M(){let e=(I().env||{}).GOOGLE_GENAI_USE_VERTEXAI;return e==="True"||e==="true"}function O(e){let i=I().env||{};if(M()){let a=i.GOOGLE_CLOUD_PROJECT;if(!a)throw new Error("GOOGLE_CLOUD_PROJECT is required when using Vertex AI");let t=e==="gemini-3-flash-preview"?"global":i.GOOGLE_CLOUD_LOCATION;if(!t)throw new Error("GOOGLE_CLOUD_LOCATION is required when using Vertex AI");return h.debug(`Using Vertex AI provider: model=${e}, location=${t}`),J({project:a,location:t})(e)}let o=i.GOOGLE_API_KEY;if(!o)throw new Error("Google API key is missing. Set GOOGLE_API_KEY in SDK config or environment.");return h.debug(`Using Google AI provider (API key): model=${e}`),K({apiKey:o})(e)}function W(e,i){let o={thinkingConfig:{thinkingBudget:512,includeThoughts:!0}},a={thinkingConfig:{thinkingLevel:"minimal",includeThoughts:!0},mediaResolution:A.MEDIA_RESOLUTION_HIGH},t;switch(i){case"gemini-3-flash-preview":t={...a};break;default:t={...o},e===1&&(t.mediaResolution=A.MEDIA_RESOLUTION_HIGH)}return M()?{vertex:t}:{google:t}}function pe(e){if(e.startsWith("claude-"))return L(e);if(e.startsWith("gemini-"))return O(e);throw new Error(`Unsupported model: ${e}. Use 'claude-*' or 'gemini-*' models.`)}function be(e,i){return e.startsWith("claude-")?H(e):W(i,e)}async function _(){let{default:e}=await import("sharp");return e}var F=768;async function S(e,i){let o=await _(),a=await o(e).metadata(),t=a.width||0,l=a.height||0;if(t===0||l===0)throw new Error("Invalid image dimensions");let n=l,c=0,r=Math.floor((t-n)/2),d=Math.max(0,t-n),m=(w,E)=>{let b=o(e).extract({left:w,top:0,width:E,height:n});return i?.resize&&(b=b.resize(F,F)),b.png().toBuffer()},[u,f,g]=await Promise.all([m(c,Math.min(n,t)),m(r,Math.min(n,t-r)),m(d,Math.min(n,t-d))]);return[u,f,g]}async function P(e){let i=(await _())(e),o=await i.metadata(),a=o.width||0,t=o.height||0;if(a===0||t===0)throw new Error("Invalid image dimensions");let{data:l}=await i.grayscale().raw().toBuffer({resolveWithObject:!0}),n=[];for(let c=0;c<t;c++){n[c]=[];for(let r=0;r<a;r++)n[c][r]=l[c*a+r]}return{pixels:n,width:a,height:t}}var V=new Set(["button","link","textbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","tab","switch","slider","spinbutton","searchbox","scrollbar","treeitem","gridcell"]),X=new Set(["click","mousedown","mouseup","dblclick","pointerdown","pointerup","touchstart","touchend"]),$=["[onclick]","[onmousedown]","[ontouchstart]","div","span","li","tr","td","[role]",'[class*="btn"]','[class*="button"]','[class*="click"]',"[data-action]","[data-click]"],B=500;function G(e,i){return e.length>i?e.slice(0,i)+"...":e}var Y=["title","type","checked","name","role","value","placeholder","data-date-format","alt","aria-label","aria-expanded","data-state","aria-checked","data-id","data-testid","data-test-id","data-handlepos","data-item-id"],z={"react-flow__(\\S+)":"$1"};var j=class{constructor(e,i=null){this.isVisible=e,this.parent=i}},R=class extends j{constructor(e,i,o=null){super(i,o),this.text=e,this.type="TEXT_NODE"}hasParentWithHighlightIndex(){let e=this.parent;for(;e!==null;){if(e.highlightIndex!==null)return!0;e=e.parent}return!1}isParentInViewport(){return this.parent===null?!1:this.parent.isInViewport}isParentTopElement(){return this.parent===null?!1:this.parent.isTopElement}},k=class N extends j{constructor(i,o,a,t,l,n=!1,c=!1,r=!1,d=!1,m=!1,u=!1,f=null,g=null,w=null,E=null,b=null){super(l,b),this.tagName=i,this.xpath=o,this.attributes=a,this.children=t,this.isInteractive=n,this.isScrollable=c,this.markAsClickable=r,this.isTopElement=d,this.isInViewport=m,this.shadowRoot=u,this.highlightIndex=f,this.viewportCoordinates=g,this.pageCoordinates=w,this.viewportInfo=E,this.isNew=null}getAllTextTillNextClickableElement(i=-1){let o=[],a=(t,l)=>{if(!(i!==-1&&l>i)&&!(t instanceof N&&t!==this&&t.highlightIndex!==null)){if(t instanceof R)o.push(t.text);else if(t instanceof N)for(let n of t.children)a(n,l+1)}};return a(this,0),o.join(`
|
|
4
|
+
`).trim()}clickableElementsToString(i){let o=i?.includeAttributes??Y,a=i?.includeClassesWithRename??z,t=[],l=(n,c)=>{let r=c,d=" ".repeat(c);if(n instanceof N){if(n.highlightIndex!==null){r+=1;let m=n.isScrollable?"":n.getAllTextTillNextClickableElement(),u=null;if(o.length>0){let s={};for(let y of Object.keys(n.attributes))if(o.includes(y)){let C=n.attributes[y].trim();C!==""&&(s[y]=C)}let p=o.filter(y=>y in s);if(p.length>1){let y=new Set,C={};for(let T of p){let D=s[T];D.length>5&&(D in C?y.add(T):C[D]=T)}for(let T of y)delete s[T]}n.tagName===s.role&&delete s.role;let x=["aria-label","placeholder","title"];for(let y of x)s[y]&&s[y].trim().toLowerCase()===m.trim().toLowerCase()&&delete s[y];Object.keys(s).length>0&&(u=Object.entries(s).map(([y,C])=>`${y}=${G(C,200)}`).join(" "))}let f=n.isNew?`*[${n.highlightIndex}]`:`[${n.highlightIndex}]`,g=[];if(Object.keys(a).length>0&&n.attributes.class){let s=n.attributes.class.split(/\s+/);for(let p of s)for(let[x,y]of Object.entries(a))try{let C=new RegExp(`^${x}$`);if(p.match(C)){let T=p.replace(C,y);T&&g.push(T);break}}catch{continue}}let w=n.isScrollable?" (SCROLLABLE)":"",E=n.markAsClickable?" (CLICKABLE)":"",b=`${d}${f}${w}${E}<${n.tagName}`;if(g.length>0&&(b+=` ${g.join(" ")}`),u&&(b+=` ${u}`),m){let s=m.trim();u||(b+=" "),b+=`>${s}`}else u||(b+=" ");b+=" />",t.push(b)}else{let m=["data-testid","data-test-id"].filter(u=>n.attributes[u]);m.length>0&&(r+=1,t.push(`${d}<${n.tagName} ${m.map(u=>`${u}="${n.attributes[u]}"`).join(" ")} />`))}for(let m of n.children)l(m,r)}else if(n instanceof R){if(n.hasParentWithHighlightIndex())return;n.parent&&n.parent.isVisible&&n.parent.isTopElement&&t.push(`${d}${n.text}`)}};return l(this,0),t.join(`
|
|
5
|
+
`)}};var Q=`(
|
|
4
6
|
args = {
|
|
5
7
|
doHighlightElements: true,
|
|
6
8
|
focusHighlightIndex: -1,
|
|
@@ -10,6 +12,7 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
10
12
|
alwaysHighlightFileInput: false,
|
|
11
13
|
}
|
|
12
14
|
) => {
|
|
15
|
+
const SEMANTIC_ATTRIBUTES = ['data-testid', 'data-test-id'];
|
|
13
16
|
const EVENT_LISTENER_MAPPING = {
|
|
14
17
|
'onclick': 'click',
|
|
15
18
|
'onmousedown': 'mousedown',
|
|
@@ -1556,6 +1559,14 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
1556
1559
|
return hasScrollableX || hasScrollableY;
|
|
1557
1560
|
}
|
|
1558
1561
|
|
|
1562
|
+
function addSemanticAttributesToNodeData(node, nodeData) {
|
|
1563
|
+
for (const attr of SEMANTIC_ATTRIBUTES) {
|
|
1564
|
+
if (node.hasAttribute(attr)) {
|
|
1565
|
+
nodeData.attributes[attr] = node.getAttribute(attr);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1559
1570
|
/**
|
|
1560
1571
|
* Creates a node data object for a given node and its descendants.
|
|
1561
1572
|
*
|
|
@@ -1671,6 +1682,7 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
1671
1682
|
if (nodeData.isVisible) {
|
|
1672
1683
|
nodeData.isTopElement = isTopElement(node);
|
|
1673
1684
|
if (nodeData.isTopElement) {
|
|
1685
|
+
addSemanticAttributesToNodeData(node, nodeData);
|
|
1674
1686
|
let isScrollable = isElementScrollable(node);
|
|
1675
1687
|
nodeData.isInteractive = isInteractiveElement(node) || isScrollable;
|
|
1676
1688
|
nodeData.isScrollable = isScrollable;
|
|
@@ -1745,7 +1757,7 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
1745
1757
|
|
|
1746
1758
|
return { rootId, map: DOM_HASH_MAP };
|
|
1747
1759
|
}
|
|
1748
|
-
`,
|
|
1760
|
+
`,Z=`((args = {
|
|
1749
1761
|
doHighlightElements: true,
|
|
1750
1762
|
focusHighlightIndex: -1,
|
|
1751
1763
|
viewportExpansion: 0,
|
|
@@ -3793,7 +3805,7 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
3793
3805
|
// Return element data from boxes phase for use in labels phase
|
|
3794
3806
|
elementData: phase === 'boxes' ? collectedElementData : undefined,
|
|
3795
3807
|
};
|
|
3796
|
-
})`;function
|
|
3808
|
+
})`;function ee(e){return e==="about:blank"||e==="chrome://newtab/"||e==="edge://newtab/"||e==="about:newtab"}var He=class{constructor(e={}){h.debug("\u{1F333} Initializing DomService with options:",e),this.useDomTreeTs=e.useDomTreeTs??!1,this.jsCode=this.useDomTreeTs?Z:Q}async getClickableElements(e,i={}){let{highlightElements:o=!0,focusElement:a=-1,viewportExpansion:t=0,interactiveClassNames:l=[],alwaysHighlightFileInput:n=!1,sameRectIoUThreshold:c,actionIntent:r="all"}=i,[d,m]=await this.buildDomTree(e,o,a,t,l,n,c,r);return{elementTree:d,selectorMap:m}}async getClickableElementsWithScreenshot(e,i={}){if(i.useAccessibilityTree)return this.getClickableElementsWithAXTree(e,i);let o;i.useCleanScreenshot&&(o=await e.screenshot({type:"png",fullPage:!1}));let a=await this.getClickableElements(e,i);await e.waitForTimeout(100),i.useCleanScreenshot||(o=await e.screenshot({type:"png",fullPage:!1})),await this.removeHighlights(e);let t=o.toString("base64"),l;if(i.useSlicedScreenshots)try{l=(await S(o,{resize:i.resizeSlicedScreenshots})).map(n=>n.toString("base64"))}catch(n){h.warn("Failed to slice screenshot:",n)}return{domState:a,screenshotBase64:t,slicedScreenshotsBase64:l}}async getClickableElementsWithAXTree(e,i={}){h.debug("\u{1F333} Using CDP Accessibility Tree for element detection");let o;i.useCleanScreenshot&&(o=await e.screenshot({type:"png",fullPage:!1}));let a=await e.context().newCDPSession(e),{nodes:t}=await a.send("Accessibility.getFullAXTree",{depth:-1});h.debug(`\u{1F4CA} Got ${t.length} AXNodes from accessibility tree`);let l=t.filter(s=>{if(s.ignored)return!1;let p=s.role?.value;return!(!p||!V.has(p)||s.properties?.find(x=>x.name==="disabled")?.value?.value||!s.backendDOMNodeId)});h.debug(`\u2705 Found ${l.length} interactive elements from AXTree`);let n=t.filter(s=>s.role?.value==="button");h.debug(`\u{1F518} Total buttons in AXTree: ${n.length}`);for(let s of n){let p=[];s.ignored&&p.push("ignored"),s.backendDOMNodeId||p.push("no-backendDOMNodeId"),s.properties?.find(x=>x.name==="disabled")?.value?.value&&p.push("disabled"),h.debug(` - "${s.name?.value||"(no name)"}" ${p.length>0?`[SKIPPED: ${p.join(", ")}]`:"[INCLUDED]"}`)}let c=new Set(l.map(s=>s.backendDOMNodeId)),r=await this.getElementsWithEventListeners(a,i.eventListenerLimit??500),d=0;for(let s of r)c.has(s.backendNodeId)||(l.push({nodeId:`synthetic-${s.backendNodeId}`,ignored:!1,backendDOMNodeId:s.backendNodeId,role:{type:"role",value:"generic"},name:{type:"string",value:""},properties:[{name:"eventListeners",value:{type:"string",value:s.eventTypes.join(",")}}]}),c.add(s.backendNodeId),d++);h.debug(`\u{1F3AF} Added ${d} elements from event listeners (total: ${l.length})`);let m=await this.resolveAXNodesToDOM(a,l),u=m.filter(s=>s.isVisible&&s.isInViewport&&s.isTopElement&&s.boundingRect),f=m.filter(s=>!(s.isVisible&&s.isInViewport&&s.isTopElement&&s.boundingRect));if(f.length>0){h.debug(`\u{1F6AB} Filtered out ${f.length} elements:`);for(let s of f){let p=[];s.isVisible||p.push("not-visible"),s.isInViewport||p.push("not-in-viewport"),s.isTopElement||p.push("not-top-element"),s.boundingRect||p.push("no-bounding-rect"),h.debug(` - <${s.tagName}> "${s.axNode.name?.value||""}" [${p.join(", ")}]`)}}h.debug(`\u{1F441}\uFE0F ${u.length} elements are visible and in viewport`);let{domState:g,highlightIndex:w}=await this.buildDomStateFromAXTree(u);i.highlightElements!==!1&&w>0&&(await this.renderHighlightsForAXElements(e,u.slice(0,w)),await e.waitForTimeout(100)),i.useCleanScreenshot||(o=await e.screenshot({type:"png",fullPage:!1})),await this.removeHighlights(e);try{await a.detach()}catch{}let E=o.toString("base64"),b;if(i.useSlicedScreenshots)try{b=(await S(o,{resize:i.resizeSlicedScreenshots})).map(s=>s.toString("base64"))}catch(s){h.warn("Failed to slice screenshot:",s)}return{domState:g,screenshotBase64:E,slicedScreenshotsBase64:b}}async resolveAXNodesToDOM(e,i){let o=[],a=i.map(l=>l.backendDOMNodeId).filter(l=>l!==void 0);if(a.length===0)return o;let t=[];for(let l of a)try{let{object:n}=await e.send("DOM.resolveNode",{backendNodeId:l});t.push(n.objectId||null)}catch{t.push(null)}for(let l=0;l<i.length;l++){let n=i[l],c=t[l];if(c)try{let{result:r}=await e.send("Runtime.callFunctionOn",{objectId:c,functionDeclaration:`function() {
|
|
3797
3809
|
const el = this;
|
|
3798
3810
|
const rect = el.getBoundingClientRect();
|
|
3799
3811
|
const rects = el.getClientRects();
|
|
@@ -3877,4 +3889,5 @@ import{a as h}from"./chunk-YR4E7JSB.js";import{g as R}from"./chunk-UFLZ3URR.js";
|
|
|
3877
3889
|
} : null,
|
|
3878
3890
|
clientRects: clientRectsArray
|
|
3879
3891
|
};
|
|
3880
|
-
}`,returnByValue:!0});
|
|
3892
|
+
}`,returnByValue:!0});r.value&&o.push({axNode:n,...r.value})}catch(r){h.debug(`Failed to resolve element: ${r}`)}}return o}async getElementsWithEventListeners(e,i=B){let o=[];try{let{root:a}=await e.send("DOM.getDocument",{depth:0}),t=$.join(","),{nodeIds:l}=await e.send("DOM.querySelectorAll",{nodeId:a.nodeId,selector:t});h.debug(`\u{1F50D} Checking ${Math.min(l.length,i)} elements for event listeners`);for(let n of l.slice(0,i))try{let{object:c}=await e.send("DOM.resolveNode",{nodeId:n});if(!c.objectId)continue;let{listeners:r}=await e.send("DOMDebugger.getEventListeners",{objectId:c.objectId}),d=r.filter(m=>X.has(m.type));if(d.length>0){let{node:m}=await e.send("DOM.describeNode",{nodeId:n});o.push({backendNodeId:m.backendNodeId,eventTypes:d.map(u=>u.type)})}await e.send("Runtime.releaseObject",{objectId:c.objectId})}catch{}h.debug(`\u2705 Found ${o.length} elements with interaction event listeners`)}catch(a){h.warn("Failed to get elements with event listeners:",a)}return o}async buildDomStateFromAXTree(e){let i=new Map,o=new k("body","/body",{},[],!0,!1,!1,!1,!0,!0,!1,null),a=0;for(let t of e){let l=t.axNode.role?.value||"",n=t.axNode.name?.value||"",c=["button","link","menuitem","tab","switch"].includes(l),r=new k(t.tagName,t.xpath,t.attributes,[],t.isVisible,!0,l==="scrollbar",c,t.isTopElement,t.isInViewport,!1,a,t.boundingRect?{topLeft:{x:t.boundingRect.x,y:t.boundingRect.y},topRight:{x:t.boundingRect.x+t.boundingRect.width,y:t.boundingRect.y},bottomLeft:{x:t.boundingRect.x,y:t.boundingRect.y+t.boundingRect.height},bottomRight:{x:t.boundingRect.x+t.boundingRect.width,y:t.boundingRect.y+t.boundingRect.height},center:{x:t.boundingRect.x+t.boundingRect.width/2,y:t.boundingRect.y+t.boundingRect.height/2},width:t.boundingRect.width,height:t.boundingRect.height}:null,null,null,o);if(n){let d=new R(n,!0,r);r.children.push(d)}o.children.push(r),i.set(a,r),a++}return{domState:{elementTree:o,selectorMap:i},highlightIndex:a}}async renderHighlightsForAXElements(e,i){let o=["#FF0000","#00FF00","#0000FF","#FFA500","#800080","#008080","#FF69B4","#4B0082","#FF4500","#2E8B57","#DC143C","#4682B4"];await e.evaluate(({elements:a,colors:t})=>{let l="playwright-highlight-container",n=document.getElementById(l);n||(n=document.createElement("div"),n.id=l,n.style.position="fixed",n.style.pointerEvents="none",n.style.top="0",n.style.left="0",n.style.width="100%",n.style.height="100%",n.style.zIndex="2147483647",n.style.backgroundColor="transparent",document.body.appendChild(n)),a.forEach((c,r)=>{if(!c.boundingRect)return;let d=t[r%t.length],m=c.boundingRect,u=document.createElement("div");u.style.position="fixed",u.style.border=`1px solid ${d}`,u.style.backgroundColor="transparent",u.style.pointerEvents="none",u.style.boxSizing="border-box",u.style.top=`${m.y}px`,u.style.left=`${m.x}px`,u.style.width=`${m.width}px`,u.style.height=`${m.height}px`,n.appendChild(u);let f=document.createElement("div");f.style.position="fixed",f.style.background=d,f.style.color="white",f.style.padding="1px 4px",f.style.borderRadius="4px",f.style.fontSize=r>=100?"8px":"12px",f.textContent=String(r);let g=Math.max(0,m.y-16),w=Math.max(0,Math.min(m.x+m.width-20,window.innerWidth-25));f.style.top=`${g}px`,f.style.left=`${w}px`,n.appendChild(f)})},{elements:i,colors:o})}async removeHighlights(e){try{await e.evaluate(()=>{let i=document.getElementById("playwright-highlight-container");i&&i.remove(),window._highlightCleanupFunctions&&(window._highlightCleanupFunctions.forEach(o=>o()),window._highlightCleanupFunctions=[])}),h.debug("\u2705 Highlights removed from page")}catch(i){h.warn("Failed to remove highlights:",i.message)}}async getCrossOriginIframes(e){let i=await e.locator("iframe").filter({hasNot:e.locator(":visible")}).evaluateAll(c=>c.map(r=>r.src)),o=c=>{try{let r=new URL(c);return["doubleclick.net","adroll.com","googletagmanager.com"].some(d=>r.hostname.includes(d))}catch{return!1}},a=e.url(),t=new URL(a).hostname,l=e.frames(),n=[];for(let c of l){let r=c.url();try{let d=new URL(r).hostname;d&&d!==t&&!i.includes(r)&&!o(r)&&n.push(r)}catch{continue}}return n}async buildDomTree(e,i,o,a,t,l,n,c="all"){if(await e.evaluate("1+1")!==2)throw new Error("The page cannot evaluate javascript code properly");if(ee(e.url()))return[new k("body","",{},[],!1,!1,!1,!1,!1,!1,!1,null),new Map];let r={doHighlightElements:i,focusHighlightIndex:o,viewportExpansion:a,debugMode:!1,interactiveClassNames:t,alwaysHighlightFileInput:l,sameRectIoUThreshold:n,actionIntent:c};h.debug(`\u{1F527} Starting JavaScript DOM analysis for ${e.url().slice(0,50)}...`);let d,m=null;if(this.useDomTreeTs&&i)try{let f={...r,phase:"boxes",grayscaleImage:null},g=await e.evaluate(({code:x,argsObj:y})=>new Function("return "+x)()(y),{code:this.jsCode,argsObj:f});h.debug(`\u{1F4E6} Phase 1: Drew ${g.elementData?.length||0} bounding boxes`);let w=await e.screenshot({type:"png",fullPage:!1});h.debug("\u{1F4F8} Captured screenshot with bounding boxes");let E=performance.now(),b=await P(w);m=b.pixels;let s=Math.round(performance.now()-E);h.debug(`\u{1F5BC}\uFE0F Generated grayscale image (${b.width}x${b.height}) in ${s}ms`);let p={...r,phase:"labels",grayscaleImage:m,elementData:g.elementData};d=await e.evaluate(({code:x,argsObj:y})=>new Function("return "+x)()(y),{code:this.jsCode,argsObj:p}),d.map=g.map,d.rootId=g.rootId,d.highlightCount=g.highlightCount,d.perfMetrics=g.perfMetrics,h.debug("\u2705 Phase 2: Labels placed using grayscale-based positioning")}catch(f){h.warn("Two-phase rendering failed, falling back to legacy mode:",f.message),m=null;let g={...r,grayscaleImage:null};d=await e.evaluate(({code:w,argsObj:E})=>new Function("return "+w)()(E),{code:this.jsCode,argsObj:g}),h.debug("\u2705 JavaScript DOM analysis completed (legacy mode)")}else try{d=await e.evaluate(({code:f,argsObj:g})=>new Function("return "+f)()(g),{code:this.jsCode,argsObj:r}),h.debug("\u2705 JavaScript DOM analysis completed")}catch(f){throw h.error("Error evaluating JavaScript:",f.message),f}if(!d||typeof d!="object")throw h.error("JavaScript returned invalid result:",d),new Error("JavaScript DOM analysis returned invalid result");if(!d.map||!d.rootId)throw h.error("JavaScript result missing map or rootId:",JSON.stringify(d,null,2)),new Error("JavaScript result missing required fields (map or rootId)");if(c!=="all"&&d.highlightCount===0){h.debug(`\u26A0\uFE0F No elements matched intent '${c}', falling back to 'all'`);let f={...r,actionIntent:"all"};d=await e.evaluate(({code:g,argsObj:w})=>new Function("return "+g)()(w),{code:this.jsCode,argsObj:f})}if(d&&d.perfMetrics){let f=d.perfMetrics.nodeMetrics?.totalNodes??0,g=0;if(d.map)for(let E of Object.values(d.map))typeof E=="object"&&E!==null&&E.isInteractive&&g++;let w=e.url().length>50?e.url().slice(0,50)+"...":e.url();h.debug(`\u{1F50E} Ran buildDOMTree.js interactive element detection on: ${w} interactive=${g}/${f}`)}h.debug("\u{1F504} Starting TypeScript DOM tree construction...");let u=await this.constructDomTree(d);return h.debug("\u2705 TypeScript DOM tree construction completed"),u}async constructDomTree(e){let i=e.map,o=e.rootId,a=new Map,t=new Map;for(let[n,c]of Object.entries(i)){let[r,d]=this.parseNode(c);if(r!==null&&(t.set(n,r),r instanceof k&&r.highlightIndex!==null&&a.set(r.highlightIndex,r),r instanceof k))for(let m of d){let u=t.get(m);u&&(u.parent=r,r.children.push(u))}}let l=t.get(o);if(!l||!(l instanceof k))throw new Error("Failed to parse HTML to dictionary");return[l,a]}parseNode(e){if(!e)return[null,[]];if(e.type==="TEXT_NODE")return[new R(e.text,e.isVisible,null),[]];let i=null;e.viewport&&(i={width:e.viewport.width,height:e.viewport.height,scrollX:e.viewport.scrollX,scrollY:e.viewport.scrollY});let o=new k(e.tagName,e.xpath,e.attributes||{},[],e.isVisible??!1,e.isInteractive??!1,e.isScrollable??!1,e.markAsClickable??!1,e.isTopElement??!1,e.isInViewport??!1,e.shadowRoot??!1,e.highlightIndex??null,e.viewportCoordinates??null,e.pageCoordinates??null,i,null),a=e.children||[];return[o,a]}};export{ne as a,pe as b,be as c,He as d};
|
|
3893
|
+
//# sourceMappingURL=chunk-SSPF674P.js.map
|