misoai-web 1.6.0 → 1.6.1

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.
Files changed (59) hide show
  1. package/dist/es/agent.js +105 -50
  2. package/dist/es/agent.js.map +1 -1
  3. package/dist/es/bridge-mode-browser.js +3 -3
  4. package/dist/es/bridge-mode-browser.js.map +1 -1
  5. package/dist/es/bridge-mode.js +107 -52
  6. package/dist/es/bridge-mode.js.map +1 -1
  7. package/dist/es/chrome-extension.js +106 -51
  8. package/dist/es/chrome-extension.js.map +1 -1
  9. package/dist/es/index.js +106 -51
  10. package/dist/es/index.js.map +1 -1
  11. package/dist/es/midscene-playground.js +108 -53
  12. package/dist/es/midscene-playground.js.map +1 -1
  13. package/dist/es/midscene-server.js +4 -4
  14. package/dist/es/midscene-server.js.map +1 -1
  15. package/dist/es/playground.js +105 -50
  16. package/dist/es/playground.js.map +1 -1
  17. package/dist/es/playwright-report.js +1 -1
  18. package/dist/es/playwright-report.js.map +1 -1
  19. package/dist/es/playwright.js +106 -51
  20. package/dist/es/playwright.js.map +1 -1
  21. package/dist/es/puppeteer-agent-launcher.js +105 -50
  22. package/dist/es/puppeteer-agent-launcher.js.map +1 -1
  23. package/dist/es/puppeteer.js +105 -50
  24. package/dist/es/puppeteer.js.map +1 -1
  25. package/dist/es/utils.js +1 -1
  26. package/dist/es/utils.js.map +1 -1
  27. package/dist/es/yaml.js +1 -1
  28. package/dist/es/yaml.js.map +1 -1
  29. package/dist/lib/agent.js +105 -50
  30. package/dist/lib/agent.js.map +1 -1
  31. package/dist/lib/bridge-mode-browser.js +3 -3
  32. package/dist/lib/bridge-mode-browser.js.map +1 -1
  33. package/dist/lib/bridge-mode.js +107 -52
  34. package/dist/lib/bridge-mode.js.map +1 -1
  35. package/dist/lib/chrome-extension.js +106 -51
  36. package/dist/lib/chrome-extension.js.map +1 -1
  37. package/dist/lib/index.js +106 -51
  38. package/dist/lib/index.js.map +1 -1
  39. package/dist/lib/midscene-playground.js +108 -53
  40. package/dist/lib/midscene-playground.js.map +1 -1
  41. package/dist/lib/midscene-server.js +4 -4
  42. package/dist/lib/midscene-server.js.map +1 -1
  43. package/dist/lib/playground.js +105 -50
  44. package/dist/lib/playground.js.map +1 -1
  45. package/dist/lib/playwright-report.js +1 -1
  46. package/dist/lib/playwright-report.js.map +1 -1
  47. package/dist/lib/playwright.js +106 -51
  48. package/dist/lib/playwright.js.map +1 -1
  49. package/dist/lib/puppeteer-agent-launcher.js +105 -50
  50. package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
  51. package/dist/lib/puppeteer.js +105 -50
  52. package/dist/lib/puppeteer.js.map +1 -1
  53. package/dist/lib/utils.js +1 -1
  54. package/dist/lib/utils.js.map +1 -1
  55. package/dist/lib/yaml.js +1 -1
  56. package/dist/lib/yaml.js.map +1 -1
  57. package/dist/types/index.d.ts +1 -1
  58. package/dist/types/playwright.d.ts +1 -1
  59. package/package.json +18 -54
@@ -35,13 +35,13 @@ __export(reporter_exports, {
35
35
  module.exports = __toCommonJS(reporter_exports);
36
36
 
37
37
  // src/common/utils.ts
38
+ var import_dayjs = __toESM(require("dayjs"));
38
39
  var import_ai_model = require("misoai-core/ai-model");
39
40
  var import_utils = require("misoai-core/utils");
40
41
  var import_env = require("misoai-shared/env");
41
42
  var import_extractor = require("misoai-shared/extractor");
42
43
  var import_img = require("misoai-shared/img");
43
44
  var import_utils2 = require("misoai-shared/utils");
44
- var import_dayjs = __toESM(require("dayjs"));
45
45
  function reportFileName(tag = "web") {
46
46
  const reportTagName = (0, import_env.getAIConfig)(import_env.MIDSCENE_REPORT_TAG_NAME);
47
47
  const dateTimeInFileName = (0, import_dayjs.default)().format("YYYY-MM-DD_HH-mm-ss");
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["import_utils","dayjs"],"ignoreList":[],"sources":["../../src/playwright/reporter/index.ts","../../src/common/utils.ts"],"sourcesContent":["import {\n printReportMsg,\n replaceIllegalPathCharsAndSpace,\n reportFileName,\n} from '@/common/utils';\nimport type { ReportDumpWithAttributes } from 'misoai-core';\nimport { writeDumpReport } from 'misoai-core/utils';\nimport type {\n FullConfig,\n FullResult,\n Reporter,\n Suite,\n TestCase,\n TestResult,\n} from '@playwright/test/reporter';\n\nfunction logger(...message: any[]) {\n if (process.env.DEBUG === 'true') {\n console.log('Midscene e2e report:', ...message);\n }\n}\n\nconst testDataList: Array<ReportDumpWithAttributes> = [];\nlet mergedFilename: string;\nconst testTitleToFilename: Map<string, string> = new Map();\n\nfunction getStableFilename(testTitle: string): string {\n if (!testTitleToFilename.has(testTitle)) {\n // use reportFileName to generate the base filename\n // only replace the illegal characters in the file system: /, \\, :, *, ?, \", <, >, |\n const baseTag = `playwright-${replaceIllegalPathCharsAndSpace(testTitle)}`;\n const generatedFilename = reportFileName(baseTag);\n testTitleToFilename.set(testTitle, generatedFilename);\n }\n return testTitleToFilename.get(testTitle)!;\n}\n\nfunction updateReport(mode: 'merged' | 'separate', testId?: string) {\n if (mode === 'separate') {\n // in separate mode, find the data for the corresponding testID and generate a separate report\n const testData = testDataList.find(\n (data) => data.attributes?.playwright_test_id === testId,\n );\n\n if (testData) {\n // use the stable filename\n const stableFilename = getStableFilename(\n testData.attributes?.playwright_test_title,\n );\n\n const reportPath = writeDumpReport(stableFilename, [testData]);\n reportPath && printReportMsg(reportPath);\n }\n } else if (mode === 'merged') {\n // in merged mode, write all test data into one file\n if (!mergedFilename) {\n mergedFilename = reportFileName('playwright-merged');\n }\n\n const reportPath = writeDumpReport(mergedFilename, testDataList);\n reportPath && printReportMsg(reportPath);\n } else {\n throw new Error(\n `Unknown reporter type in playwright config: ${mode}, only support 'merged' or 'separate'`,\n );\n }\n}\n\nfunction getMode(reporterType: string) {\n if (!reporterType) {\n return 'merged';\n }\n\n if (reporterType !== 'merged' && reporterType !== 'separate') {\n throw new Error(\n `Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`,\n );\n }\n\n return reporterType;\n}\n\nclass MidsceneReporter implements Reporter {\n mode?: 'merged' | 'separate';\n\n async onBegin(config: FullConfig, suite: Suite) {\n const reporterType = config.reporter?.[1]?.[1]?.type;\n\n this.mode = getMode(reporterType);\n\n // const suites = suite.allTests();\n // logger(`Starting the run with ${suites.length} tests`);\n }\n\n onTestBegin(test: TestCase, _result: TestResult) {\n // logger(`Starting test ${test.title}`);\n }\n\n onTestEnd(test: TestCase, result: TestResult) {\n const dumpAnnotation = test.annotations.find((annotation) => {\n return annotation.type === 'MIDSCENE_DUMP_ANNOTATION';\n });\n if (!dumpAnnotation?.description) return;\n const retry = result.retry ? `(retry #${result.retry})` : '';\n const testId = `${test.id}${retry}`;\n const testData: ReportDumpWithAttributes = {\n dumpString: dumpAnnotation.description,\n attributes: {\n playwright_test_id: testId,\n playwright_test_title: `${test.title}${retry}`,\n playwright_test_status: result.status,\n playwright_test_duration: result.duration,\n },\n };\n\n testDataList.push(testData);\n\n updateReport(this.mode!, testId);\n\n test.annotations = test.annotations.filter(\n (annotation) => annotation.type !== 'MIDSCENE_DUMP_ANNOTATION',\n );\n }\n\n onEnd(result: FullResult) {\n updateReport(this.mode!);\n\n logger(`Finished the run: ${result.status}`);\n }\n}\n\nexport default MidsceneReporter;\n","import type { StaticPage } from '@/playground';\nimport type {\n BaseElement,\n ElementTreeNode,\n PlanningLocateParam,\n PlaywrightParserOpt,\n UIContext,\n} from 'misoai-core';\nimport { elementByPositionWithElementInfo } from 'misoai-core/ai-model';\nimport { uploadTestInfoToServer } from 'misoai-core/utils';\nimport { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from 'misoai-shared/env';\nimport type { ElementInfo } from 'misoai-shared/extractor';\nimport {\n generateElementByPosition,\n getNodeFromCacheList,\n traverseTree,\n treeToList,\n} from 'misoai-shared/extractor';\nimport { resizeImgBase64 } from 'misoai-shared/img';\nimport type { DebugFunction } from 'misoai-shared/logger';\nimport { assert, logMsg, uuid } from 'misoai-shared/utils';\nimport dayjs from 'dayjs';\nimport type { Page as PlaywrightPage } from 'playwright';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport { WebElementInfo } from '../web-element';\nimport type { WebPage } from './page';\n\nexport type WebUIContext = UIContext<WebElementInfo> & {\n url: string;\n};\n\nexport async function parseContextFromWebPage(\n page: WebPage,\n _opt?: PlaywrightParserOpt,\n): Promise<WebUIContext> {\n assert(page, 'page is required');\n if ((page as StaticPage)._forceUsePageContext) {\n return await (page as any)._forceUsePageContext();\n }\n const url = await page.url();\n uploadTestInfoToServer({ testUrl: url });\n\n let screenshotBase64: string;\n let tree: ElementTreeNode<ElementInfo>;\n\n await Promise.all([\n page.screenshotBase64().then((base64) => {\n screenshotBase64 = base64;\n }),\n page.getElementsNodeTree().then(async (treeRoot) => {\n tree = treeRoot;\n }),\n ]);\n\n const webTree = traverseTree(tree!, (elementInfo) => {\n const { rect, id, content, attributes, locator, indexId, isVisible } =\n elementInfo;\n return new WebElementInfo({\n rect,\n locator,\n id,\n content,\n attributes,\n indexId,\n isVisible,\n });\n });\n\n assert(screenshotBase64!, 'screenshotBase64 is required');\n\n const elementsInfo = treeToList(webTree);\n const size = await page.size();\n\n if (size.dpr && size.dpr > 1) {\n // console.time('resizeImgBase64');\n screenshotBase64 = await resizeImgBase64(screenshotBase64, {\n width: size.width,\n height: size.height,\n });\n // console.timeEnd('resizeImgBase64');\n }\n\n return {\n content: elementsInfo!,\n tree: webTree,\n size,\n screenshotBase64: screenshotBase64!,\n url,\n };\n}\n\nexport function reportFileName(tag = 'web') {\n const reportTagName = getAIConfig(MIDSCENE_REPORT_TAG_NAME);\n const dateTimeInFileName = dayjs().format('YYYY-MM-DD_HH-mm-ss');\n // ensure uniqueness at the same time\n const uniqueId = uuid().substring(0, 8);\n return `${reportTagName || tag}-${dateTimeInFileName}-${uniqueId}`;\n}\n\nexport function printReportMsg(filepath: string) {\n logMsg(`Midscene - report file updated: ${filepath}`);\n}\n\n/**\n * Get the current execution file name\n * @returns The name of the current execution file\n */\nexport function getCurrentExecutionFile(trace?: string): string | false {\n const error = new Error();\n const stackTrace = trace || error.stack;\n const pkgDir = process.cwd() || '';\n if (stackTrace) {\n const stackLines = stackTrace.split('\\n');\n for (const line of stackLines) {\n if (\n line.includes('.spec.') ||\n line.includes('.test.') ||\n line.includes('.ts') ||\n line.includes('.js')\n ) {\n const match = line.match(/(?:at\\s+)?(.*?\\.(?:spec|test)\\.[jt]s)/);\n if (match?.[1]) {\n const targetFileName = match[1]\n .replace(pkgDir, '')\n .trim()\n .replace('at ', '');\n return targetFileName;\n }\n }\n }\n }\n return false;\n}\n\nconst testFileIndex = new Map<string, number>();\n\nexport function generateCacheId(fileName?: string): string {\n let taskFile = fileName || getCurrentExecutionFile();\n if (!taskFile) {\n taskFile = uuid();\n console.warn(\n 'Midscene - using random UUID for cache id. Cache may be invalid.',\n );\n }\n\n if (testFileIndex.has(taskFile)) {\n const currentIndex = testFileIndex.get(taskFile);\n if (currentIndex !== undefined) {\n testFileIndex.set(taskFile, currentIndex + 1);\n }\n } else {\n testFileIndex.set(taskFile, 1);\n }\n return `${taskFile}-${testFileIndex.get(taskFile)}`;\n}\n\nexport const ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED =\n 'NOT_IMPLEMENTED_AS_DESIGNED';\n\nexport function replaceIllegalPathCharsAndSpace(str: string) {\n // Only replace characters that are illegal in filenames, but preserve path separators\n return str.replace(/[:*?\"<>| ]/g, '-');\n}\n\nexport function forceClosePopup(\n page: PuppeteerPage | PlaywrightPage,\n debug: DebugFunction,\n) {\n page.on('popup', async (popup) => {\n if (!popup) {\n console.warn('got a popup event, but the popup is not ready yet, skip');\n return;\n }\n const url = await (popup as PuppeteerPage).url();\n console.log(`Popup opened: ${url}`);\n if (!(popup as PuppeteerPage).isClosed()) {\n try {\n await (popup as PuppeteerPage).close(); // Close the newly opened TAB\n } catch (error) {\n debug(`failed to close popup ${url}, error: ${error}`);\n }\n } else {\n debug(`popup is already closed, skip close ${url}`);\n }\n\n if (!page.isClosed()) {\n try {\n await page.goto(url);\n } catch (error) {\n debug(`failed to goto ${url}, error: ${error}`);\n }\n } else {\n debug(`page is already closed, skip goto ${url}`);\n }\n });\n}\n\nexport function matchElementFromPlan(\n planLocateParam: PlanningLocateParam,\n tree: ElementTreeNode<BaseElement>,\n) {\n if (!planLocateParam) {\n return undefined;\n }\n if (planLocateParam.id) {\n return getNodeFromCacheList(planLocateParam.id);\n }\n\n if (planLocateParam.bbox) {\n const centerPosition = {\n x: Math.floor((planLocateParam.bbox[0] + planLocateParam.bbox[2]) / 2),\n y: Math.floor((planLocateParam.bbox[1] + planLocateParam.bbox[3]) / 2),\n };\n let element = elementByPositionWithElementInfo(tree, centerPosition);\n\n if (!element) {\n element = generateElementByPosition(centerPosition) as BaseElement;\n }\n\n return element;\n }\n\n return undefined;\n}\n"]}
1
+ {"version":3,"mappings":"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","names":["import_utils","dayjs"],"ignoreList":[],"sources":["../../src/playwright/reporter/index.ts","../../src/common/utils.ts"],"sourcesContent":["import {\n printReportMsg,\n replaceIllegalPathCharsAndSpace,\n reportFileName,\n} from '@/common/utils';\nimport type {\n FullConfig,\n FullResult,\n Reporter,\n Suite,\n TestCase,\n TestResult,\n} from '@playwright/test/reporter';\nimport type { ReportDumpWithAttributes } from 'misoai-core';\nimport { writeDumpReport } from 'misoai-core/utils';\n\nfunction logger(...message: any[]) {\n if (process.env.DEBUG === 'true') {\n console.log('Midscene e2e report:', ...message);\n }\n}\n\nconst testDataList: Array<ReportDumpWithAttributes> = [];\nlet mergedFilename: string;\nconst testTitleToFilename: Map<string, string> = new Map();\n\nfunction getStableFilename(testTitle: string): string {\n if (!testTitleToFilename.has(testTitle)) {\n // use reportFileName to generate the base filename\n // only replace the illegal characters in the file system: /, \\, :, *, ?, \", <, >, |\n const baseTag = `playwright-${replaceIllegalPathCharsAndSpace(testTitle)}`;\n const generatedFilename = reportFileName(baseTag);\n testTitleToFilename.set(testTitle, generatedFilename);\n }\n return testTitleToFilename.get(testTitle)!;\n}\n\nfunction updateReport(mode: 'merged' | 'separate', testId?: string) {\n if (mode === 'separate') {\n // in separate mode, find the data for the corresponding testID and generate a separate report\n const testData = testDataList.find(\n (data) => data.attributes?.playwright_test_id === testId,\n );\n\n if (testData) {\n // use the stable filename\n const stableFilename = getStableFilename(\n testData.attributes?.playwright_test_title,\n );\n\n const reportPath = writeDumpReport(stableFilename, [testData]);\n reportPath && printReportMsg(reportPath);\n }\n } else if (mode === 'merged') {\n // in merged mode, write all test data into one file\n if (!mergedFilename) {\n mergedFilename = reportFileName('playwright-merged');\n }\n\n const reportPath = writeDumpReport(mergedFilename, testDataList);\n reportPath && printReportMsg(reportPath);\n } else {\n throw new Error(\n `Unknown reporter type in playwright config: ${mode}, only support 'merged' or 'separate'`,\n );\n }\n}\n\nfunction getMode(reporterType: string) {\n if (!reporterType) {\n return 'merged';\n }\n\n if (reporterType !== 'merged' && reporterType !== 'separate') {\n throw new Error(\n `Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`,\n );\n }\n\n return reporterType;\n}\n\nclass MidsceneReporter implements Reporter {\n mode?: 'merged' | 'separate';\n\n async onBegin(config: FullConfig, suite: Suite) {\n const reporterType = config.reporter?.[1]?.[1]?.type;\n\n this.mode = getMode(reporterType);\n\n // const suites = suite.allTests();\n // logger(`Starting the run with ${suites.length} tests`);\n }\n\n onTestBegin(test: TestCase, _result: TestResult) {\n // logger(`Starting test ${test.title}`);\n }\n\n onTestEnd(test: TestCase, result: TestResult) {\n const dumpAnnotation = test.annotations.find((annotation) => {\n return annotation.type === 'MIDSCENE_DUMP_ANNOTATION';\n });\n if (!dumpAnnotation?.description) return;\n const retry = result.retry ? `(retry #${result.retry})` : '';\n const testId = `${test.id}${retry}`;\n const testData: ReportDumpWithAttributes = {\n dumpString: dumpAnnotation.description,\n attributes: {\n playwright_test_id: testId,\n playwright_test_title: `${test.title}${retry}`,\n playwright_test_status: result.status,\n playwright_test_duration: result.duration,\n },\n };\n\n testDataList.push(testData);\n\n updateReport(this.mode!, testId);\n\n test.annotations = test.annotations.filter(\n (annotation) => annotation.type !== 'MIDSCENE_DUMP_ANNOTATION',\n );\n }\n\n onEnd(result: FullResult) {\n updateReport(this.mode!);\n\n logger(`Finished the run: ${result.status}`);\n }\n}\n\nexport default MidsceneReporter;\n","import type { StaticPage } from '@/playground';\nimport dayjs from 'dayjs';\nimport type {\n BaseElement,\n ElementTreeNode,\n PlanningLocateParam,\n PlaywrightParserOpt,\n UIContext,\n} from 'misoai-core';\nimport { elementByPositionWithElementInfo } from 'misoai-core/ai-model';\nimport { uploadTestInfoToServer } from 'misoai-core/utils';\nimport { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from 'misoai-shared/env';\nimport type { ElementInfo } from 'misoai-shared/extractor';\nimport {\n generateElementByPosition,\n getNodeFromCacheList,\n traverseTree,\n treeToList,\n} from 'misoai-shared/extractor';\nimport { resizeImgBase64 } from 'misoai-shared/img';\nimport type { DebugFunction } from 'misoai-shared/logger';\nimport { assert, logMsg, uuid } from 'misoai-shared/utils';\nimport type { Page as PlaywrightPage } from 'playwright';\nimport type { Page as PuppeteerPage } from 'puppeteer';\nimport { WebElementInfo } from '../web-element';\nimport type { WebPage } from './page';\n\nexport type WebUIContext = UIContext<WebElementInfo> & {\n url: string;\n};\n\nexport async function parseContextFromWebPage(\n page: WebPage,\n _opt?: PlaywrightParserOpt,\n): Promise<WebUIContext> {\n assert(page, 'page is required');\n if ((page as StaticPage)._forceUsePageContext) {\n return await (page as any)._forceUsePageContext();\n }\n const url = await page.url();\n uploadTestInfoToServer({ testUrl: url });\n\n let screenshotBase64: string;\n let tree: ElementTreeNode<ElementInfo>;\n\n await Promise.all([\n page.screenshotBase64().then((base64) => {\n screenshotBase64 = base64;\n }),\n page.getElementsNodeTree().then(async (treeRoot) => {\n tree = treeRoot;\n }),\n ]);\n\n const webTree = traverseTree(tree!, (elementInfo) => {\n const { rect, id, content, attributes, locator, indexId, isVisible } =\n elementInfo;\n return new WebElementInfo({\n rect,\n locator,\n id,\n content,\n attributes,\n indexId,\n isVisible,\n });\n });\n\n assert(screenshotBase64!, 'screenshotBase64 is required');\n\n const elementsInfo = treeToList(webTree);\n const size = await page.size();\n\n if (size.dpr && size.dpr > 1) {\n // console.time('resizeImgBase64');\n screenshotBase64 = await resizeImgBase64(screenshotBase64, {\n width: size.width,\n height: size.height,\n });\n // console.timeEnd('resizeImgBase64');\n }\n\n return {\n content: elementsInfo!,\n tree: webTree,\n size,\n screenshotBase64: screenshotBase64!,\n url,\n };\n}\n\nexport function reportFileName(tag = 'web') {\n const reportTagName = getAIConfig(MIDSCENE_REPORT_TAG_NAME);\n const dateTimeInFileName = dayjs().format('YYYY-MM-DD_HH-mm-ss');\n // ensure uniqueness at the same time\n const uniqueId = uuid().substring(0, 8);\n return `${reportTagName || tag}-${dateTimeInFileName}-${uniqueId}`;\n}\n\nexport function printReportMsg(filepath: string) {\n logMsg(`Midscene - report file updated: ${filepath}`);\n}\n\n/**\n * Get the current execution file name\n * @returns The name of the current execution file\n */\nexport function getCurrentExecutionFile(trace?: string): string | false {\n const error = new Error();\n const stackTrace = trace || error.stack;\n const pkgDir = process.cwd() || '';\n if (stackTrace) {\n const stackLines = stackTrace.split('\\n');\n for (const line of stackLines) {\n if (\n line.includes('.spec.') ||\n line.includes('.test.') ||\n line.includes('.ts') ||\n line.includes('.js')\n ) {\n const match = line.match(/(?:at\\s+)?(.*?\\.(?:spec|test)\\.[jt]s)/);\n if (match?.[1]) {\n const targetFileName = match[1]\n .replace(pkgDir, '')\n .trim()\n .replace('at ', '');\n return targetFileName;\n }\n }\n }\n }\n return false;\n}\n\nconst testFileIndex = new Map<string, number>();\n\nexport function generateCacheId(fileName?: string): string {\n let taskFile = fileName || getCurrentExecutionFile();\n if (!taskFile) {\n taskFile = uuid();\n console.warn(\n 'Midscene - using random UUID for cache id. Cache may be invalid.',\n );\n }\n\n if (testFileIndex.has(taskFile)) {\n const currentIndex = testFileIndex.get(taskFile);\n if (currentIndex !== undefined) {\n testFileIndex.set(taskFile, currentIndex + 1);\n }\n } else {\n testFileIndex.set(taskFile, 1);\n }\n return `${taskFile}-${testFileIndex.get(taskFile)}`;\n}\n\nexport const ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED =\n 'NOT_IMPLEMENTED_AS_DESIGNED';\n\nexport function replaceIllegalPathCharsAndSpace(str: string) {\n // Only replace characters that are illegal in filenames, but preserve path separators\n return str.replace(/[:*?\"<>| ]/g, '-');\n}\n\nexport function forceClosePopup(\n page: PuppeteerPage | PlaywrightPage,\n debug: DebugFunction,\n) {\n page.on('popup', async (popup) => {\n if (!popup) {\n console.warn('got a popup event, but the popup is not ready yet, skip');\n return;\n }\n const url = await (popup as PuppeteerPage).url();\n console.log(`Popup opened: ${url}`);\n if (!(popup as PuppeteerPage).isClosed()) {\n try {\n await (popup as PuppeteerPage).close(); // Close the newly opened TAB\n } catch (error) {\n debug(`failed to close popup ${url}, error: ${error}`);\n }\n } else {\n debug(`popup is already closed, skip close ${url}`);\n }\n\n if (!page.isClosed()) {\n try {\n await page.goto(url);\n } catch (error) {\n debug(`failed to goto ${url}, error: ${error}`);\n }\n } else {\n debug(`page is already closed, skip goto ${url}`);\n }\n });\n}\n\nexport function matchElementFromPlan(\n planLocateParam: PlanningLocateParam,\n tree: ElementTreeNode<BaseElement>,\n) {\n if (!planLocateParam) {\n return undefined;\n }\n if (planLocateParam.id) {\n return getNodeFromCacheList(planLocateParam.id);\n }\n\n if (planLocateParam.bbox) {\n const centerPosition = {\n x: Math.floor((planLocateParam.bbox[0] + planLocateParam.bbox[2]) / 2),\n y: Math.floor((planLocateParam.bbox[1] + planLocateParam.bbox[3]) / 2),\n };\n let element = elementByPositionWithElementInfo(tree, centerPosition);\n\n if (!element) {\n element = generateElementByPosition(centerPosition) as BaseElement;\n }\n\n return element;\n }\n\n return undefined;\n}\n"]}
@@ -345,8 +345,8 @@ var ScriptPlayer = class {
345
345
  var import_js_yaml = __toESM(require("js-yaml"));
346
346
 
347
347
  // src/yaml/utils.ts
348
- var import_utils2 = require("misoai-shared/utils");
349
348
  var import_js_yaml2 = __toESM(require("js-yaml"));
349
+ var import_utils2 = require("misoai-shared/utils");
350
350
  function interpolateEnvVars(content) {
351
351
  return content.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
352
352
  const value = process.env[envVar.trim()];
@@ -492,13 +492,13 @@ function paramStr(task) {
492
492
  }
493
493
 
494
494
  // src/common/utils.ts
495
+ var import_dayjs = __toESM(require("dayjs"));
495
496
  var import_ai_model = require("misoai-core/ai-model");
496
497
  var import_utils3 = require("misoai-core/utils");
497
498
  var import_env = require("misoai-shared/env");
498
499
  var import_extractor = require("misoai-shared/extractor");
499
500
  var import_img = require("misoai-shared/img");
500
501
  var import_utils4 = require("misoai-shared/utils");
501
- var import_dayjs = __toESM(require("dayjs"));
502
502
 
503
503
  // src/web-element.ts
504
504
  var WebElementInfo = class {
@@ -667,8 +667,12 @@ var WorkflowMemory = class {
667
667
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
668
668
  workflow.memory = [...memory];
669
669
  workflow.metadata.totalSteps = workflow.steps.length;
670
- workflow.metadata.completedSteps = workflow.steps.filter((s) => s.status === "completed").length;
671
- workflow.metadata.failedSteps = workflow.steps.filter((s) => s.status === "failed").length;
670
+ workflow.metadata.completedSteps = workflow.steps.filter(
671
+ (s) => s.status === "completed"
672
+ ).length;
673
+ workflow.metadata.failedSteps = workflow.steps.filter(
674
+ (s) => s.status === "failed"
675
+ ).length;
672
676
  this.workflows.set(workflowId, workflow);
673
677
  this.enforceRetentionPolicy();
674
678
  }
@@ -679,7 +683,9 @@ var WorkflowMemory = class {
679
683
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
680
684
  workflow.context = { ...workflow.context, ...context };
681
685
  if (context.currentStep) {
682
- const existingStep = workflow.steps.find((s) => s.stepName === context.currentStep);
686
+ const existingStep = workflow.steps.find(
687
+ (s) => s.stepName === context.currentStep
688
+ );
683
689
  if (!existingStep) {
684
690
  workflow.steps.push({
685
691
  stepId: `step_${workflow.steps.length + 1}`,
@@ -724,7 +730,9 @@ var WorkflowMemory = class {
724
730
  enforceRetentionPolicy() {
725
731
  const maxWorkflows = 10;
726
732
  if (this.workflows.size > maxWorkflows) {
727
- const sortedWorkflows = Array.from(this.workflows.entries()).sort(([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime));
733
+ const sortedWorkflows = Array.from(this.workflows.entries()).sort(
734
+ ([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime)
735
+ );
728
736
  const toDelete = sortedWorkflows.slice(maxWorkflows);
729
737
  toDelete.forEach(([workflowId]) => this.workflows.delete(workflowId));
730
738
  }
@@ -1463,7 +1471,9 @@ var PageTaskExecutor = class {
1463
1471
  */
1464
1472
  getPersistentExecutor() {
1465
1473
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1466
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1474
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1475
+ this.sessionContext.workflowId
1476
+ );
1467
1477
  this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1468
1478
  onTaskStart: this.onTaskStartCallback,
1469
1479
  initialMemory: previousMemory
@@ -1492,7 +1502,9 @@ var PageTaskExecutor = class {
1492
1502
  if (this.persistentExecutor) {
1493
1503
  this.persistentExecutor.clearMemory();
1494
1504
  }
1495
- this.workflowMemory.clearWorkflow(this.sessionContext.workflowId || "default");
1505
+ this.workflowMemory.clearWorkflow(
1506
+ this.sessionContext.workflowId || "default"
1507
+ );
1496
1508
  }
1497
1509
  /**
1498
1510
  * Mevcut hafızayı döndürür
@@ -1504,7 +1516,9 @@ var PageTaskExecutor = class {
1504
1516
  * İş akışı hafızasını döndürür
1505
1517
  */
1506
1518
  getWorkflowMemory() {
1507
- return this.workflowMemory.getWorkflowData(this.sessionContext.workflowId || "default");
1519
+ return this.workflowMemory.getWorkflowData(
1520
+ this.sessionContext.workflowId || "default"
1521
+ );
1508
1522
  }
1509
1523
  /**
1510
1524
  * Hafıza istatistiklerini döndürür
@@ -1512,7 +1526,13 @@ var PageTaskExecutor = class {
1512
1526
  getMemoryStats() {
1513
1527
  return this.persistentExecutor?.getMemoryStats() || {
1514
1528
  totalItems: 0,
1515
- analytics: { totalTasks: 0, memoryHits: 0, memoryMisses: 0, averageMemorySize: 0, memoryEffectiveness: 0 },
1529
+ analytics: {
1530
+ totalTasks: 0,
1531
+ memoryHits: 0,
1532
+ memoryMisses: 0,
1533
+ averageMemorySize: 0,
1534
+ memoryEffectiveness: 0
1535
+ },
1516
1536
  config: this.memoryConfig
1517
1537
  };
1518
1538
  }
@@ -1548,11 +1568,14 @@ var PageTaskExecutor = class {
1548
1568
  let taskExecutor;
1549
1569
  if (useMemory) {
1550
1570
  taskExecutor = this.getPersistentExecutor();
1551
- this.workflowMemory.updateWorkflowContext({
1552
- currentStep: title,
1553
- pageInfo: this.sessionContext.pageInfo,
1554
- timestamp: Date.now()
1555
- }, this.sessionContext.workflowId || "default");
1571
+ this.workflowMemory.updateWorkflowContext(
1572
+ {
1573
+ currentStep: title,
1574
+ pageInfo: this.sessionContext.pageInfo,
1575
+ timestamp: Date.now()
1576
+ },
1577
+ this.sessionContext.workflowId || "default"
1578
+ );
1556
1579
  } else {
1557
1580
  taskExecutor = new import_misoai_core.Executor(title, {
1558
1581
  onTaskStart: this.onTaskStartCallback
@@ -1918,14 +1941,19 @@ var PageTaskExecutor = class {
1918
1941
  */
1919
1942
  addToMemory(memoryItem) {
1920
1943
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1921
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1944
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1945
+ this.sessionContext.workflowId
1946
+ );
1922
1947
  this.persistentExecutor = new import_misoai_core.Executor("Persistent Task Executor", {
1923
1948
  onTaskStart: this.onTaskStartCallback,
1924
1949
  initialMemory: previousMemory
1925
1950
  });
1926
1951
  }
1927
1952
  this.persistentExecutor.memoryStore?.add(memoryItem);
1928
- this.persistentExecutor.memoryAnalytics?.recordMemoryOperation("add", memoryItem);
1953
+ this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
1954
+ "add",
1955
+ memoryItem
1956
+ );
1929
1957
  }
1930
1958
  };
1931
1959
 
@@ -2014,14 +2042,14 @@ function buildPlans(type, locateParam, param) {
2014
2042
  var import_node_assert = __toESM(require("assert"));
2015
2043
  var import_node_fs2 = require("fs");
2016
2044
  var import_node_path2 = require("path");
2045
+ var import_js_yaml3 = __toESM(require("js-yaml"));
2017
2046
  var import_common2 = require("misoai-shared/common");
2018
2047
  var import_logger3 = require("misoai-shared/logger");
2019
2048
  var import_utils9 = require("misoai-shared/utils");
2020
- var import_js_yaml3 = __toESM(require("js-yaml"));
2021
2049
  var import_semver = __toESM(require("semver"));
2022
2050
 
2023
2051
  // package.json
2024
- var version = "1.6.0";
2052
+ var version = "1.6.1";
2025
2053
 
2026
2054
  // src/common/task-cache.ts
2027
2055
  var debug3 = (0, import_logger3.getDebug)("cache");
@@ -2316,22 +2344,28 @@ var PageAgent = class {
2316
2344
  const allThoughts = executor.tasks.filter((task) => task.thought).map((task) => task.thought);
2317
2345
  const allLocates = executor.tasks.filter((task) => task.locate).map((task) => task.locate);
2318
2346
  const allPlans = executor.tasks.filter((task) => task.param?.plans).map((task) => task.param?.plans);
2319
- const planningTasks = executor.tasks.filter((task) => task.type === "Planning");
2320
- const insightTasks = executor.tasks.filter((task) => task.type === "Insight");
2347
+ const planningTasks = executor.tasks.filter(
2348
+ (task) => task.type === "Planning"
2349
+ );
2350
+ const insightTasks = executor.tasks.filter(
2351
+ (task) => task.type === "Insight"
2352
+ );
2321
2353
  const actionTasks = executor.tasks.filter((task) => task.type === "Action");
2322
2354
  const planning = planningTasks.length > 0 ? {
2323
2355
  type: "Planning",
2324
- description: `Planning for task execution`,
2356
+ description: "Planning for task execution",
2325
2357
  steps: planningTasks.map((task) => task.thought || "Planning step")
2326
2358
  } : void 0;
2327
2359
  const insight = insightTasks.length > 0 ? {
2328
2360
  type: "Insight",
2329
- description: `Insight for task execution`,
2330
- elements: insightTasks.map((task) => task.thought || "Insight element")
2361
+ description: "Insight for task execution",
2362
+ elements: insightTasks.map(
2363
+ (task) => task.thought || "Insight element"
2364
+ )
2331
2365
  } : void 0;
2332
2366
  const action = actionTasks.length > 0 ? {
2333
2367
  type: "Action",
2334
- description: `Action for task execution`,
2368
+ description: "Action for task execution",
2335
2369
  result: lastTask?.output
2336
2370
  } : void 0;
2337
2371
  const actionDetails = executor.tasks.map((task) => ({
@@ -2665,7 +2699,10 @@ ${memoryContext}` : void 0;
2665
2699
  }
2666
2700
  const memoryContext = this.getMemoryAsContext();
2667
2701
  const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2668
- const { output, executor } = await this.taskExecutor.assert(assertionWithContext, memoryContext);
2702
+ const { output, executor } = await this.taskExecutor.assert(
2703
+ assertionWithContext,
2704
+ memoryContext
2705
+ );
2669
2706
  const metadata = this.afterTaskRunning(executor, true);
2670
2707
  if (output && opt?.keepRawResponse) {
2671
2708
  return {
@@ -2704,7 +2741,10 @@ A complex CAPTCHA typically has one or more of these characteristics:
2704
2741
  Return only "complex" or "simple" based on your analysis.
2705
2742
  `;
2706
2743
  const complexityMsgs = [
2707
- { role: "system", content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity." },
2744
+ {
2745
+ role: "system",
2746
+ content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity."
2747
+ },
2708
2748
  {
2709
2749
  role: "user",
2710
2750
  content: [
@@ -2728,7 +2768,12 @@ Return only "complex" or "simple" based on your analysis.
2728
2768
  );
2729
2769
  const responseText = typeof complexityResult.content === "string" ? complexityResult.content.toLowerCase() : JSON.stringify(complexityResult.content).toLowerCase();
2730
2770
  shouldUseDeepThink = responseText.includes("complex");
2731
- debug4("CAPTCHA complexity analysis:", responseText, "Using deep think:", shouldUseDeepThink);
2771
+ debug4(
2772
+ "CAPTCHA complexity analysis:",
2773
+ responseText,
2774
+ "Using deep think:",
2775
+ shouldUseDeepThink
2776
+ );
2732
2777
  } catch (error) {
2733
2778
  debug4("Failed to analyze CAPTCHA complexity:", error);
2734
2779
  }
@@ -2745,7 +2790,9 @@ Return only "complex" or "simple" based on your analysis.
2745
2790
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2746
2791
  } else if (action.type === "input" && action.value) {
2747
2792
  if (action.target) {
2748
- await this.aiInput(action.value, action.target, { deepThink: shouldUseDeepThink });
2793
+ await this.aiInput(action.value, action.target, {
2794
+ deepThink: shouldUseDeepThink
2795
+ });
2749
2796
  }
2750
2797
  } else if (action.type === "verify" && action.target) {
2751
2798
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
@@ -2757,7 +2804,9 @@ Return only "complex" or "simple" based on your analysis.
2757
2804
  if (action.coordinates) {
2758
2805
  const x = action.coordinates[0];
2759
2806
  const y = action.coordinates[1];
2760
- await this.aiTap(`element at coordinates (${x}, ${y})`, { deepThink: shouldUseDeepThink });
2807
+ await this.aiTap(`element at coordinates (${x}, ${y})`, {
2808
+ deepThink: shouldUseDeepThink
2809
+ });
2761
2810
  } else if (action.target) {
2762
2811
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2763
2812
  }
@@ -2909,25 +2958,27 @@ ${errors}`);
2909
2958
  const executionDump = {
2910
2959
  name: screenshotTitle,
2911
2960
  description: content,
2912
- tasks: [{
2913
- type: "Screenshot",
2914
- subType: "log",
2915
- status: "finished",
2916
- executor: null,
2917
- param: {
2918
- title: screenshotTitle,
2919
- content
2920
- },
2921
- output: {
2922
- screenshot
2923
- },
2924
- thought: `Logged screenshot: ${screenshotTitle}`,
2925
- timing: {
2926
- start: Date.now(),
2927
- end: Date.now(),
2928
- cost: 0
2961
+ tasks: [
2962
+ {
2963
+ type: "Screenshot",
2964
+ subType: "log",
2965
+ status: "finished",
2966
+ executor: null,
2967
+ param: {
2968
+ title: screenshotTitle,
2969
+ content
2970
+ },
2971
+ output: {
2972
+ screenshot
2973
+ },
2974
+ thought: `Logged screenshot: ${screenshotTitle}`,
2975
+ timing: {
2976
+ start: Date.now(),
2977
+ end: Date.now(),
2978
+ cost: 0
2979
+ }
2929
2980
  }
2930
- }],
2981
+ ],
2931
2982
  sdkVersion: "1.0.0",
2932
2983
  logTime: Date.now(),
2933
2984
  model_name: "screenshot"
@@ -2979,7 +3030,9 @@ ${errors}`);
2979
3030
  totalTasks: stats.analytics.totalTasks,
2980
3031
  memoryHits: stats.analytics.memoryHits,
2981
3032
  memoryMisses: stats.analytics.memoryMisses,
2982
- memoryEffectiveness: Math.round(stats.analytics.memoryEffectiveness * 100),
3033
+ memoryEffectiveness: Math.round(
3034
+ stats.analytics.memoryEffectiveness * 100
3035
+ ),
2983
3036
  averageMemorySize: Math.round(stats.analytics.averageMemorySize * 100) / 100
2984
3037
  },
2985
3038
  config: stats.config,
@@ -3043,7 +3096,9 @@ ${errors}`);
3043
3096
  calculateSuccessRate(memory) {
3044
3097
  if (memory.length === 0)
3045
3098
  return 0;
3046
- const successCount = memory.filter((item) => item.metadata?.success !== false).length;
3099
+ const successCount = memory.filter(
3100
+ (item) => item.metadata?.success !== false
3101
+ ).length;
3047
3102
  return Math.round(successCount / memory.length * 100);
3048
3103
  }
3049
3104
  calculateAverageExecutionTime(memory) {
@@ -3361,8 +3416,8 @@ var WebPage = class extends Page {
3361
3416
 
3362
3417
  // src/playwright/ai-fixture.ts
3363
3418
  var import_node_crypto = require("crypto");
3364
- var import_logger6 = require("misoai-shared/logger");
3365
3419
  var import_test = require("@playwright/test");
3420
+ var import_logger6 = require("misoai-shared/logger");
3366
3421
  var debugPage2 = (0, import_logger6.getDebug)("web:playwright:ai-fixture");
3367
3422
  var groupAndCaseForTest = (testInfo) => {
3368
3423
  let taskFile;