doc-detective 4.27.0 → 4.28.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.
Files changed (35) hide show
  1. package/dist/core/tests/appSurface.d.ts +2 -0
  2. package/dist/core/tests/appSurface.d.ts.map +1 -1
  3. package/dist/core/tests/appSurface.js +11 -10
  4. package/dist/core/tests/appSurface.js.map +1 -1
  5. package/dist/core/tests/mobileBrowser.d.ts +3 -1
  6. package/dist/core/tests/mobileBrowser.d.ts.map +1 -1
  7. package/dist/core/tests/mobileBrowser.js +6 -7
  8. package/dist/core/tests/mobileBrowser.js.map +1 -1
  9. package/dist/hints/context.d.ts +16 -0
  10. package/dist/hints/context.d.ts.map +1 -1
  11. package/dist/hints/context.js +34 -0
  12. package/dist/hints/context.js.map +1 -1
  13. package/dist/hints/hints.d.ts.map +1 -1
  14. package/dist/hints/hints.js +17 -0
  15. package/dist/hints/hints.js.map +1 -1
  16. package/dist/hints/types.d.ts +14 -0
  17. package/dist/hints/types.d.ts.map +1 -1
  18. package/dist/index.cjs +370 -269
  19. package/dist/runtime/cacheDir.d.ts +5 -0
  20. package/dist/runtime/cacheDir.d.ts.map +1 -1
  21. package/dist/runtime/cacheDir.js +3 -0
  22. package/dist/runtime/cacheDir.js.map +1 -1
  23. package/dist/runtime/iosInstaller.d.ts +44 -1
  24. package/dist/runtime/iosInstaller.d.ts.map +1 -1
  25. package/dist/runtime/iosInstaller.js +381 -13
  26. package/dist/runtime/iosInstaller.js.map +1 -1
  27. package/dist/runtime/lock.d.ts +56 -0
  28. package/dist/runtime/lock.d.ts.map +1 -0
  29. package/dist/runtime/lock.js +218 -0
  30. package/dist/runtime/lock.js.map +1 -0
  31. package/dist/runtime/wdaProducts.d.ts +147 -0
  32. package/dist/runtime/wdaProducts.d.ts.map +1 -0
  33. package/dist/runtime/wdaProducts.js +234 -0
  34. package/dist/runtime/wdaProducts.js.map +1 -0
  35. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -632440,6 +632440,8 @@ function readInstalledRecord(ctx = {}) {
632440
632440
  };
632441
632441
  if (isPlainObject(parsed?.android))
632442
632442
  record.android = parsed.android;
632443
+ if (isPlainObject(parsed?.ios))
632444
+ record.ios = parsed.ios;
632443
632445
  if (isPlainObject(parsed?.tools))
632444
632446
  record.tools = parsed.tools;
632445
632447
  return record;
@@ -634500,12 +634502,12 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634500
634502
  }
634501
634503
  if (!force && existing && isStillFresh(existing.latestCheckedAt, now)) {
634502
634504
  if (existing.latestKnownVersion === existing.installedVersion) {
634503
- const path28 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634504
- return { path: path28, version: existing.installedVersion, outdated: false };
634505
+ const path29 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634506
+ return { path: path29, version: existing.installedVersion, outdated: false };
634505
634507
  }
634506
- const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634508
+ const path28 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634507
634509
  logger(`${name} ${existing.installedVersion} installed in ${cacheDir}; "${BROWSER_CHANNELS[name]}" channel is now ${existing.latestKnownVersion}. Run \`doc-detective install browsers ${name} --force\` to update.`, "warn");
634508
- return { path: path27, version: existing.installedVersion, outdated: true };
634510
+ return { path: path28, version: existing.installedVersion, outdated: true };
634509
634511
  }
634510
634512
  let latest;
634511
634513
  try {
@@ -634513,8 +634515,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634513
634515
  } catch (err) {
634514
634516
  logger(`Channel resolution for ${name} skipped: ${String(err)}`, "debug");
634515
634517
  if (existing) {
634516
- const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634517
- return { path: path27, version: existing.installedVersion, outdated: false };
634518
+ const path28 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634519
+ return { path: path28, version: existing.installedVersion, outdated: false };
634518
634520
  }
634519
634521
  throw err;
634520
634522
  }
@@ -634525,8 +634527,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634525
634527
  latestCheckedAt: now.toISOString()
634526
634528
  };
634527
634529
  writeInstalledRecord(record, ctx);
634528
- const path27 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634529
- return { path: path27, version: latest, outdated: false };
634530
+ const path28 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634531
+ return { path: path28, version: latest, outdated: false };
634530
634532
  }
634531
634533
  if (!force && existing) {
634532
634534
  record.browsers[name] = {
@@ -634536,8 +634538,8 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634536
634538
  };
634537
634539
  writeInstalledRecord(record, ctx);
634538
634540
  logger(`${name} ${existing.installedVersion} installed in ${cacheDir}; "${BROWSER_CHANNELS[name]}" channel is now ${latest}. Run \`doc-detective install browsers ${name} --force\` to update.`, "warn");
634539
- const path27 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634540
- return { path: path27, version: existing.installedVersion, outdated: true };
634541
+ const path28 = await locateExecutable(browsersModule, name, existing.installedVersion, cacheDir, platform);
634542
+ return { path: path28, version: existing.installedVersion, outdated: true };
634541
634543
  }
634542
634544
  logger(`Installing ${name} ${latest} into ${cacheDir}`, "info");
634543
634545
  await browsersModule.install({
@@ -634545,9 +634547,9 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634545
634547
  buildId: latest,
634546
634548
  cacheDir
634547
634549
  });
634548
- let path26 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634549
- if (name === "chromedriver" && isAllowedDriverPath(path26)) {
634550
- let verify = await verifyDriverBinary(name, path26, { exec: deps.verifyExec });
634550
+ let path27 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634551
+ if (name === "chromedriver" && isAllowedDriverPath(path27)) {
634552
+ let verify = await verifyDriverBinary(name, path27, { exec: deps.verifyExec });
634551
634553
  if (!verify.ok) {
634552
634554
  logger(`Installed ${name} ${latest} failed validation (${verify.error}); reinstalling once.`, "warn");
634553
634555
  try {
@@ -634556,11 +634558,11 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634556
634558
  logger(`Failed to prune broken ${name} ${latest}: ${String(err)}`, "debug");
634557
634559
  }
634558
634560
  await browsersModule.install({ browser: name, buildId: latest, cacheDir });
634559
- path26 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634560
- verify = await verifyDriverBinary(name, path26, { exec: deps.verifyExec });
634561
+ path27 = await locateExecutable(browsersModule, name, latest, cacheDir, platform);
634562
+ verify = await verifyDriverBinary(name, path27, { exec: deps.verifyExec });
634561
634563
  }
634562
634564
  if (!verify.ok) {
634563
- throw new Error(`${name} ${latest} is present but non-functional after a reinstall (${verify.error}). It may be a partial or corrupt download; delete ${path26} or reinstall.`);
634565
+ throw new Error(`${name} ${latest} is present but non-functional after a reinstall (${verify.error}). It may be a partial or corrupt download; delete ${path27} or reinstall.`);
634564
634566
  }
634565
634567
  }
634566
634568
  if (existing && existing.installedVersion !== latest) {
@@ -634581,7 +634583,7 @@ async function ensureBrowserInstalledImpl(name, options = {}) {
634581
634583
  latestCheckedAt: now.toISOString()
634582
634584
  };
634583
634585
  writeInstalledRecord(record, ctx);
634584
- return { path: path26, version: latest, outdated: false };
634586
+ return { path: path27, version: latest, outdated: false };
634585
634587
  }
634586
634588
  async function locateExecutable(browsersModule, name, buildId, cacheDir, platform) {
634587
634589
  if (typeof browsersModule.computeExecutablePath === "function") {
@@ -635027,10 +635029,10 @@ async function getOperation(definition = {}, operationId = "", responseCode = ""
635027
635029
  if (!operationId) {
635028
635030
  throw new Error("OperationId is required.");
635029
635031
  }
635030
- for (const path26 in definition.paths) {
635031
- for (const method in definition.paths[path26]) {
635032
- if (definition.paths[path26][method].operationId === operationId) {
635033
- const operation = definition.paths[path26][method];
635032
+ for (const path27 in definition.paths) {
635033
+ for (const method in definition.paths[path27]) {
635034
+ if (definition.paths[path27][method].operationId === operationId) {
635035
+ const operation = definition.paths[path27][method];
635034
635036
  if (!server) {
635035
635037
  if (definition.servers && definition.servers.length > 0) {
635036
635038
  server = definition.servers[0].url;
@@ -635038,9 +635040,9 @@ async function getOperation(definition = {}, operationId = "", responseCode = ""
635038
635040
  throw new Error("No server URL provided and no servers defined in the OpenAPI definition.");
635039
635041
  }
635040
635042
  }
635041
- const example = await compileExample(operation, server + path26, responseCode, exampleKey);
635043
+ const example = await compileExample(operation, server + path27, responseCode, exampleKey);
635042
635044
  const schemas2 = getSchemas(operation, responseCode);
635043
- return { path: path26, method, definition: operation, schemas: schemas2, example };
635045
+ return { path: path27, method, definition: operation, schemas: schemas2, example };
635044
635046
  }
635045
635047
  }
635046
635048
  }
@@ -635061,15 +635063,15 @@ function getSchemas(definition = {}, responseCode = "") {
635061
635063
  schemas2.response = definition.responses[responseCode].content[Object.keys(definition.responses[responseCode].content)[0]].schema;
635062
635064
  return schemas2;
635063
635065
  }
635064
- async function compileExample(operation = {}, path26 = "", responseCode = "", exampleKey = "") {
635066
+ async function compileExample(operation = {}, path27 = "", responseCode = "", exampleKey = "") {
635065
635067
  if (!operation) {
635066
635068
  throw new Error("Operation is required.");
635067
635069
  }
635068
- if (!path26) {
635070
+ if (!path27) {
635069
635071
  throw new Error("Path is required.");
635070
635072
  }
635071
635073
  let example = {
635072
- url: path26,
635074
+ url: path27,
635073
635075
  request: { parameters: {}, headers: {}, body: {} },
635074
635076
  response: { headers: {}, body: {} }
635075
635077
  };
@@ -638931,7 +638933,7 @@ init_utils();
638931
638933
 
638932
638934
  // dist/core/tests.js
638933
638935
  var import_tree_kill3 = __toESM(require("tree-kill"), 1);
638934
- var import_node_fs28 = __toESM(require("node:fs"), 1);
638936
+ var import_node_fs29 = __toESM(require("node:fs"), 1);
638935
638937
  init_loader();
638936
638938
  init_browsers();
638937
638939
  init_browserStepKeys();
@@ -639644,12 +639646,116 @@ async function resolveCloseTargets(driver, ref, opts = {}) {
639644
639646
  }
639645
639647
 
639646
639648
  // dist/core/tests/appSurface.js
639647
- var import_node_fs16 = __toESM(require("node:fs"), 1);
639648
- var import_node_path13 = __toESM(require("node:path"), 1);
639649
- var import_node_child_process9 = require("node:child_process");
639649
+ var import_node_fs17 = __toESM(require("node:fs"), 1);
639650
+ var import_node_path14 = __toESM(require("node:path"), 1);
639651
+ var import_node_child_process10 = require("node:child_process");
639650
639652
  init_loader();
639651
639653
  init_appium();
639652
639654
  init_cacheDir();
639655
+
639656
+ // dist/runtime/wdaProducts.js
639657
+ var import_node_child_process7 = require("node:child_process");
639658
+ var import_node_fs14 = __toESM(require("node:fs"), 1);
639659
+ var import_node_path12 = __toESM(require("node:path"), 1);
639660
+ init_cacheDir();
639661
+ init_loader();
639662
+ function parseXcodebuildVersion(output) {
639663
+ const text = String(output ?? "");
639664
+ const version = /^\s*Xcode\s+(\S+)/m.exec(text)?.[1];
639665
+ const build = /^\s*Build version\s+(\S+)/m.exec(text)?.[1];
639666
+ if (!version || !build)
639667
+ return null;
639668
+ return { version, build };
639669
+ }
639670
+ function getWdaRoot(ctx = {}) {
639671
+ return import_node_path12.default.join(getCacheDir(ctx), "ios", "wda");
639672
+ }
639673
+ function sanitizeKeySegment(value) {
639674
+ return (value || "unknown").trim().replace(/[^A-Za-z0-9._-]+/g, "-") || "unknown";
639675
+ }
639676
+ function computeWdaKey(xcode, driverVersion) {
639677
+ return `xcode-${sanitizeKeySegment(xcode.version)}-${sanitizeKeySegment(xcode.build)}-driver-${sanitizeKeySegment(driverVersion)}`;
639678
+ }
639679
+ var RUNNER_APP_RELATIVE = import_node_path12.default.join("DerivedData", "Build", "Products", "Debug-iphonesimulator", "WebDriverAgentRunner-Runner.app");
639680
+ var PRODUCTS_MARKER = "products.json";
639681
+ var LAST_USED_STAMP = "last-used";
639682
+ function readProductsMarker(keyDir, fs28) {
639683
+ try {
639684
+ const parsed = JSON.parse(String(fs28.readFileSync(import_node_path12.default.join(keyDir, PRODUCTS_MARKER))));
639685
+ if (typeof parsed?.key !== "string" || typeof parsed?.driverVersion !== "string") {
639686
+ return null;
639687
+ }
639688
+ if (!fs28.existsSync(import_node_path12.default.join(keyDir, RUNNER_APP_RELATIVE)))
639689
+ return null;
639690
+ return parsed;
639691
+ } catch {
639692
+ return null;
639693
+ }
639694
+ }
639695
+ function touchLastUsed(keyDir, fs28, now) {
639696
+ try {
639697
+ fs28.writeFileSync(import_node_path12.default.join(keyDir, LAST_USED_STAMP), String(now()));
639698
+ } catch {
639699
+ }
639700
+ }
639701
+ var MIN_PREBUILT_WDA_DRIVER_MAJOR = 10;
639702
+ var cachedXcodeProbe;
639703
+ function probeXcodeVersionCached() {
639704
+ if (cachedXcodeProbe === void 0) {
639705
+ try {
639706
+ const result = (0, import_node_child_process7.spawnSync)("xcodebuild", ["-version"], {
639707
+ encoding: "utf8",
639708
+ windowsHide: true,
639709
+ timeout: 15e3
639710
+ });
639711
+ cachedXcodeProbe = result.status === 0 ? parseXcodebuildVersion(result.stdout) : null;
639712
+ } catch {
639713
+ cachedXcodeProbe = null;
639714
+ }
639715
+ }
639716
+ return cachedXcodeProbe;
639717
+ }
639718
+ function locateManagedWda(options = {}) {
639719
+ const { ctx = {}, fs: fs28 = import_node_fs14.default, platform = process.platform, probeXcode = probeXcodeVersionCached, resolveDriverVersion = resolveHeavyDepVersion, now = Date.now } = options;
639720
+ try {
639721
+ if (platform !== "darwin")
639722
+ return null;
639723
+ const driverVersion = resolveDriverVersion("appium-xcuitest-driver", ctx);
639724
+ if (!driverVersion)
639725
+ return null;
639726
+ const driverMajor = Number.parseInt(driverVersion, 10);
639727
+ if (!Number.isFinite(driverMajor) || driverMajor < MIN_PREBUILT_WDA_DRIVER_MAJOR) {
639728
+ return null;
639729
+ }
639730
+ const xcode = probeXcode();
639731
+ if (!xcode)
639732
+ return null;
639733
+ const wdaRoot = import_node_path12.default.normalize(options.wdaRootDir ?? getWdaRoot(ctx));
639734
+ const key = computeWdaKey(xcode, driverVersion);
639735
+ const keyDir = import_node_path12.default.join(wdaRoot, key);
639736
+ const marker = readProductsMarker(keyDir, fs28);
639737
+ if (!marker || marker.key !== key)
639738
+ return null;
639739
+ touchLastUsed(keyDir, fs28, now);
639740
+ return { key, derivedDataPath: import_node_path12.default.join(keyDir, "DerivedData") };
639741
+ } catch {
639742
+ return null;
639743
+ }
639744
+ }
639745
+ function applyManagedWdaCapabilities(capabilities, locateWda) {
639746
+ const derivedDataPath = process.env.DOC_DETECTIVE_IOS_WDA_DERIVED_DATA_PATH;
639747
+ if (derivedDataPath && derivedDataPath.trim()) {
639748
+ capabilities["appium:derivedDataPath"] = derivedDataPath.trim();
639749
+ return;
639750
+ }
639751
+ const managed = locateWda?.();
639752
+ if (managed) {
639753
+ capabilities["appium:derivedDataPath"] = managed.derivedDataPath;
639754
+ capabilities["appium:usePrebuiltWDA"] = true;
639755
+ }
639756
+ }
639757
+
639758
+ // dist/core/tests/appSurface.js
639653
639759
  init_utils();
639654
639760
 
639655
639761
  // dist/core/tests/appWindows.js
@@ -640088,17 +640194,17 @@ async function closeAppWindow({ entry, selector }) {
640088
640194
  }
640089
640195
 
640090
640196
  // dist/core/tests/androidEmulator.js
640091
- var import_node_child_process8 = require("node:child_process");
640197
+ var import_node_child_process9 = require("node:child_process");
640092
640198
 
640093
640199
  // dist/runtime/androidInstaller.js
640094
- var import_node_fs15 = __toESM(require("node:fs"), 1);
640200
+ var import_node_fs16 = __toESM(require("node:fs"), 1);
640095
640201
  var import_node_os6 = __toESM(require("node:os"), 1);
640096
- var import_node_path12 = __toESM(require("node:path"), 1);
640097
- var import_node_child_process7 = require("node:child_process");
640202
+ var import_node_path13 = __toESM(require("node:path"), 1);
640203
+ var import_node_child_process8 = require("node:child_process");
640098
640204
  init_cacheDir();
640099
640205
 
640100
640206
  // dist/runtime/androidSdk.js
640101
- var import_node_fs14 = __toESM(require("node:fs"), 1);
640207
+ var import_node_fs15 = __toESM(require("node:fs"), 1);
640102
640208
  init_cacheDir();
640103
640209
  function trimTrailingSeparators(s) {
640104
640210
  let end = s.length;
@@ -640142,7 +640248,7 @@ function usable(tools) {
640142
640248
  }
640143
640249
  function detectAndroidSdk(ctx = {}, deps = {}) {
640144
640250
  const env = deps.env ?? process.env;
640145
- const existsSync2 = deps.existsSync ?? import_node_fs14.default.existsSync;
640251
+ const existsSync2 = deps.existsSync ?? import_node_fs15.default.existsSync;
640146
640252
  const platform = deps.platform ?? process.platform;
640147
640253
  const cacheRoot = safeCacheDir(ctx);
640148
640254
  const cacheAndroidSdk = deps.cacheAndroidSdk ?? (cacheRoot ? joinFor(platform, cacheRoot, "android-sdk") : void 0);
@@ -640248,11 +640354,11 @@ function resolveJavaHome(extractDir, entries, platform = process.platform) {
640248
640354
  const top = entries.find((e) => /jdk|jre/i.test(e));
640249
640355
  if (!top)
640250
640356
  return null;
640251
- const base = import_node_path12.default.join(extractDir, top);
640252
- return platform === "darwin" ? import_node_path12.default.join(base, "Contents", "Home") : base;
640357
+ const base = import_node_path13.default.join(extractDir, top);
640358
+ return platform === "darwin" ? import_node_path13.default.join(base, "Contents", "Home") : base;
640253
640359
  }
640254
640360
  function javaBinPath(javaHome, platform = process.platform) {
640255
- return import_node_path12.default.join(javaHome, "bin", platform === "win32" ? "java.exe" : "java");
640361
+ return import_node_path13.default.join(javaHome, "bin", platform === "win32" ? "java.exe" : "java");
640256
640362
  }
640257
640363
  function cmdlineToolsUrl(platform) {
640258
640364
  const token = platform === "win32" ? "win" : platform === "darwin" ? "mac" : "linux";
@@ -640293,9 +640399,9 @@ function pickSystemImage(images, { osVersion, abi }) {
640293
640399
  return candidates.length > 0 ? candidates[0].pkg : null;
640294
640400
  }
640295
640401
  function listInstalledSystemImages(sdkRoot, deps = {}) {
640296
- const existsSync2 = deps.existsSync ?? import_node_fs15.default.existsSync;
640297
- const readdirSync = deps.readdirSync ?? ((p) => import_node_fs15.default.readdirSync(p));
640298
- const base = import_node_path12.default.join(sdkRoot, "system-images");
640402
+ const existsSync2 = deps.existsSync ?? import_node_fs16.default.existsSync;
640403
+ const readdirSync = deps.readdirSync ?? ((p) => import_node_fs16.default.readdirSync(p));
640404
+ const base = import_node_path13.default.join(sdkRoot, "system-images");
640299
640405
  if (!existsSync2(base))
640300
640406
  return [];
640301
640407
  const out = [];
@@ -640308,14 +640414,14 @@ function listInstalledSystemImages(sdkRoot, deps = {}) {
640308
640414
  for (const api of apis) {
640309
640415
  let tags = [];
640310
640416
  try {
640311
- tags = readdirSync(import_node_path12.default.join(base, api));
640417
+ tags = readdirSync(import_node_path13.default.join(base, api));
640312
640418
  } catch {
640313
640419
  continue;
640314
640420
  }
640315
640421
  for (const tag of tags) {
640316
640422
  let abis = [];
640317
640423
  try {
640318
- abis = readdirSync(import_node_path12.default.join(base, api, tag));
640424
+ abis = readdirSync(import_node_path13.default.join(base, api, tag));
640319
640425
  } catch {
640320
640426
  continue;
640321
640427
  }
@@ -640331,22 +640437,22 @@ function systemImageDir(sdkRoot, pkg) {
640331
640437
  const parts = pkg.split(";");
640332
640438
  if (parts.length !== 4 || parts[0] !== "system-images")
640333
640439
  return null;
640334
- const base = import_node_path12.default.join(sdkRoot, "system-images");
640335
- const dir = import_node_path12.default.join(base, parts[1], parts[2], parts[3]);
640336
- const rel = import_node_path12.default.relative(base, dir);
640337
- if (rel === "" || rel.startsWith("..") || import_node_path12.default.isAbsolute(rel))
640440
+ const base = import_node_path13.default.join(sdkRoot, "system-images");
640441
+ const dir = import_node_path13.default.join(base, parts[1], parts[2], parts[3]);
640442
+ const rel = import_node_path13.default.relative(base, dir);
640443
+ if (rel === "" || rel.startsWith("..") || import_node_path13.default.isAbsolute(rel))
640338
640444
  return null;
640339
640445
  return dir;
640340
640446
  }
640341
640447
  function isSystemImageComplete(sdkRoot, pkg, deps = {}) {
640342
- const existsSync2 = deps.existsSync ?? import_node_fs15.default.existsSync;
640448
+ const existsSync2 = deps.existsSync ?? import_node_fs16.default.existsSync;
640343
640449
  const dir = systemImageDir(sdkRoot, pkg);
640344
640450
  if (!dir)
640345
640451
  return false;
640346
- return SYSTEM_IMAGE_MARKERS.every((marker) => existsSync2(import_node_path12.default.join(dir, marker)));
640452
+ return SYSTEM_IMAGE_MARKERS.every((marker) => existsSync2(import_node_path13.default.join(dir, marker)));
640347
640453
  }
640348
640454
  function wipeSystemImage(sdkRoot, pkg, deps = {}) {
640349
- const rmSync = deps.rmSync ?? import_node_fs15.default.rmSync;
640455
+ const rmSync = deps.rmSync ?? import_node_fs16.default.rmSync;
640350
640456
  const dir = systemImageDir(sdkRoot, pkg);
640351
640457
  if (!dir)
640352
640458
  return;
@@ -640444,7 +640550,7 @@ async function runSdkInstallWithRetry(run2, command, args, opts = {}, deps = {})
640444
640550
  }
640445
640551
  function applyJavaEnv(javaHome, platform) {
640446
640552
  process.env.JAVA_HOME = javaHome;
640447
- const bin = import_node_path12.default.join(javaHome, "bin");
640553
+ const bin = import_node_path13.default.join(javaHome, "bin");
640448
640554
  const sep = platform === "win32" ? ";" : ":";
640449
640555
  if (!(process.env.PATH ?? "").split(sep).includes(bin)) {
640450
640556
  process.env.PATH = `${bin}${sep}${process.env.PATH ?? ""}`;
@@ -640479,7 +640585,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
640479
640585
  const abi = hostAbi(deps.arch);
640480
640586
  const detect = deps.detect ?? detectAndroidSdk;
640481
640587
  const fsDeps = deps.fs ?? {};
640482
- const cacheSdkRoot = import_node_path12.default.join(getCacheDir(ctx), "android-sdk");
640588
+ const cacheSdkRoot = import_node_path13.default.join(getCacheDir(ctx), "android-sdk");
640483
640589
  const detected = detect(ctx, {});
640484
640590
  const installedImages = detected ? listInstalledSystemImages(detected.sdkRoot, fsDeps) : [];
640485
640591
  const needAvailable = pickSystemImage(installedImages, { osVersion, abi }) === null;
@@ -640519,7 +640625,7 @@ async function installAndroid({ yes = false, force = false, dryRun = false, osVe
640519
640625
  logger("Android SDK licenses: https://developer.android.com/studio/terms", "info");
640520
640626
  return [{ kind: "android", assetId: "confirmation", action: "declined" }];
640521
640627
  }
640522
- const cacheJreRoot = import_node_path12.default.join(getCacheDir(ctx), "jre");
640628
+ const cacheJreRoot = import_node_path13.default.join(getCacheDir(ctx), "jre");
640523
640629
  const java = await ensureJava({
640524
640630
  javaPresent: deps.javaPresent ?? realJavaPresent,
640525
640631
  cacheJreRoot,
@@ -640635,7 +640741,7 @@ function actionAssetId(a) {
640635
640741
  }
640636
640742
  function toolPath(sdkRoot, tool, platform) {
640637
640743
  const suffix = platform === "win32" ? ".bat" : "";
640638
- return import_node_path12.default.join(sdkRoot, "cmdline-tools", "latest", "bin", tool + suffix);
640744
+ return import_node_path13.default.join(sdkRoot, "cmdline-tools", "latest", "bin", tool + suffix);
640639
640745
  }
640640
640746
  var SAFE_SHELL_TOKEN = /^[A-Za-z0-9 ._:;=\\/@+~()-]*$/;
640641
640747
  function winShellCommand(command, args) {
@@ -640670,16 +640776,16 @@ function nowIso() {
640670
640776
  }
640671
640777
  function realJavaPresent() {
640672
640778
  try {
640673
- const res = (0, import_node_child_process7.spawnSync)("java", ["-version"], { stdio: "ignore" });
640779
+ const res = (0, import_node_child_process8.spawnSync)("java", ["-version"], { stdio: "ignore" });
640674
640780
  return res.status === 0;
640675
640781
  } catch {
640676
640782
  return false;
640677
640783
  }
640678
640784
  }
640679
640785
  function androidAvdHome() {
640680
- const home = import_node_path12.default.join(import_node_os6.default.homedir(), ".android", "avd");
640786
+ const home = import_node_path13.default.join(import_node_os6.default.homedir(), ".android", "avd");
640681
640787
  try {
640682
- import_node_fs15.default.mkdirSync(home, { recursive: true });
640788
+ import_node_fs16.default.mkdirSync(home, { recursive: true });
640683
640789
  } catch {
640684
640790
  }
640685
640791
  return home;
@@ -640690,12 +640796,12 @@ async function realRun(command, args, opts = {}) {
640690
640796
  ANDROID_AVD_HOME: androidAvdHome()
640691
640797
  };
640692
640798
  const useShell = process.platform === "win32" && /\.(bat|cmd)$/i.test(command);
640693
- const child = useShell ? (0, import_node_child_process7.spawn)(winShellCommand(command, args), {
640799
+ const child = useShell ? (0, import_node_child_process8.spawn)(winShellCommand(command, args), {
640694
640800
  cwd: opts.cwd,
640695
640801
  stdio: ["pipe", "pipe", "pipe"],
640696
640802
  shell: true,
640697
640803
  env
640698
- }) : (0, import_node_child_process7.spawn)(command, args, {
640804
+ }) : (0, import_node_child_process8.spawn)(command, args, {
640699
640805
  cwd: opts.cwd,
640700
640806
  stdio: ["pipe", "pipe", "pipe"],
640701
640807
  env
@@ -640713,20 +640819,20 @@ async function realRun(command, args, opts = {}) {
640713
640819
  });
640714
640820
  }
640715
640821
  function realDetectCachedJavaHome(cacheJreRoot) {
640716
- if (!import_node_fs15.default.existsSync(cacheJreRoot))
640822
+ if (!import_node_fs16.default.existsSync(cacheJreRoot))
640717
640823
  return null;
640718
- const entries = import_node_fs15.default.readdirSync(cacheJreRoot);
640824
+ const entries = import_node_fs16.default.readdirSync(cacheJreRoot);
640719
640825
  const home = resolveJavaHome(cacheJreRoot, entries, process.platform);
640720
- return home && import_node_fs15.default.existsSync(javaBinPath(home)) ? home : null;
640826
+ return home && import_node_fs16.default.existsSync(javaBinPath(home)) ? home : null;
640721
640827
  }
640722
640828
  async function realBootstrapJava(cacheJreRoot) {
640723
640829
  const url = jreDownloadUrl();
640724
- const tmpDir = import_node_fs15.default.mkdtempSync(import_node_path12.default.join(import_node_os6.default.tmpdir(), "dd-jre-"));
640830
+ const tmpDir = import_node_fs16.default.mkdtempSync(import_node_path13.default.join(import_node_os6.default.tmpdir(), "dd-jre-"));
640725
640831
  try {
640726
- const archive = import_node_path12.default.join(tmpDir, jreArchiveFilename());
640832
+ const archive = import_node_path13.default.join(tmpDir, jreArchiveFilename());
640727
640833
  await downloadFile(url, archive);
640728
- import_node_fs15.default.rmSync(cacheJreRoot, { recursive: true, force: true });
640729
- import_node_fs15.default.mkdirSync(cacheJreRoot, { recursive: true });
640834
+ import_node_fs16.default.rmSync(cacheJreRoot, { recursive: true, force: true });
640835
+ import_node_fs16.default.mkdirSync(cacheJreRoot, { recursive: true });
640730
640836
  await extractZip(archive, cacheJreRoot);
640731
640837
  const home = realDetectCachedJavaHome(cacheJreRoot);
640732
640838
  if (!home) {
@@ -640734,31 +640840,31 @@ async function realBootstrapJava(cacheJreRoot) {
640734
640840
  }
640735
640841
  return home;
640736
640842
  } finally {
640737
- import_node_fs15.default.rmSync(tmpDir, { recursive: true, force: true });
640843
+ import_node_fs16.default.rmSync(tmpDir, { recursive: true, force: true });
640738
640844
  }
640739
640845
  }
640740
640846
  async function realBootstrap(url, destSdkRoot) {
640741
- const tmpDir = import_node_fs15.default.mkdtempSync(import_node_path12.default.join(import_node_os6.default.tmpdir(), "dd-android-cli-"));
640847
+ const tmpDir = import_node_fs16.default.mkdtempSync(import_node_path13.default.join(import_node_os6.default.tmpdir(), "dd-android-cli-"));
640742
640848
  try {
640743
- const zipPath = import_node_path12.default.join(tmpDir, "cmdline-tools.zip");
640849
+ const zipPath = import_node_path13.default.join(tmpDir, "cmdline-tools.zip");
640744
640850
  await downloadFile(url, zipPath);
640745
- const extractDir = import_node_path12.default.join(tmpDir, "extracted");
640746
- import_node_fs15.default.mkdirSync(extractDir, { recursive: true });
640851
+ const extractDir = import_node_path13.default.join(tmpDir, "extracted");
640852
+ import_node_fs16.default.mkdirSync(extractDir, { recursive: true });
640747
640853
  await extractZip(zipPath, extractDir);
640748
- const inner = import_node_path12.default.join(extractDir, "cmdline-tools");
640749
- if (!import_node_fs15.default.existsSync(inner)) {
640854
+ const inner = import_node_path13.default.join(extractDir, "cmdline-tools");
640855
+ if (!import_node_fs16.default.existsSync(inner)) {
640750
640856
  throw new Error("unexpected command-line tools archive layout (no top-level cmdline-tools/)");
640751
640857
  }
640752
- const dest = import_node_path12.default.join(destSdkRoot, "cmdline-tools", "latest");
640753
- import_node_fs15.default.mkdirSync(import_node_path12.default.dirname(dest), { recursive: true });
640754
- import_node_fs15.default.rmSync(dest, { recursive: true, force: true });
640858
+ const dest = import_node_path13.default.join(destSdkRoot, "cmdline-tools", "latest");
640859
+ import_node_fs16.default.mkdirSync(import_node_path13.default.dirname(dest), { recursive: true });
640860
+ import_node_fs16.default.rmSync(dest, { recursive: true, force: true });
640755
640861
  try {
640756
- import_node_fs15.default.renameSync(inner, dest);
640862
+ import_node_fs16.default.renameSync(inner, dest);
640757
640863
  } catch {
640758
- import_node_fs15.default.cpSync(inner, dest, { recursive: true });
640864
+ import_node_fs16.default.cpSync(inner, dest, { recursive: true });
640759
640865
  }
640760
640866
  } finally {
640761
- import_node_fs15.default.rmSync(tmpDir, { recursive: true, force: true });
640867
+ import_node_fs16.default.rmSync(tmpDir, { recursive: true, force: true });
640762
640868
  }
640763
640869
  }
640764
640870
 
@@ -640987,7 +641093,7 @@ async function teardownDeviceRegistry(registry, kill4) {
640987
641093
  }
640988
641094
  function runTool(command, args, timeout = 3e4, env) {
640989
641095
  return new Promise((resolve) => {
640990
- (0, import_node_child_process8.execFile)(command, args, { timeout, env }, (error, stdout) => {
641096
+ (0, import_node_child_process9.execFile)(command, args, { timeout, env }, (error, stdout) => {
640991
641097
  resolve({ code: error?.code ?? 0, stdout: String(stdout ?? "") });
640992
641098
  });
640993
641099
  });
@@ -641031,11 +641137,11 @@ async function realCreateAvd(avdmanagerPath, { name, systemImage, device }, env)
641031
641137
  "--force"
641032
641138
  ];
641033
641139
  await new Promise((resolve, reject) => {
641034
- const child = useShell ? (0, import_node_child_process8.spawn)(winShellCommand(avdmanagerPath, args), {
641140
+ const child = useShell ? (0, import_node_child_process9.spawn)(winShellCommand(avdmanagerPath, args), {
641035
641141
  stdio: ["pipe", "ignore", "pipe"],
641036
641142
  shell: true,
641037
641143
  env
641038
- }) : (0, import_node_child_process8.spawn)(avdmanagerPath, args, { stdio: ["pipe", "ignore", "pipe"], env });
641144
+ }) : (0, import_node_child_process9.spawn)(avdmanagerPath, args, { stdio: ["pipe", "ignore", "pipe"], env });
641039
641145
  let err = "";
641040
641146
  child.stderr?.on("data", (d) => err += d.toString());
641041
641147
  child.on("error", reject);
@@ -641048,7 +641154,7 @@ async function realBootEmulator(emulatorPath, adbPath, desc, port, env, timeout
641048
641154
  const udid = udidForPort(port);
641049
641155
  const bootDesc = { ...desc, headless: effectiveHeadless(desc) };
641050
641156
  const bootArgs = emulatorBootArgs(bootDesc, port);
641051
- const child = (0, import_node_child_process8.spawn)(emulatorPath, bootArgs, {
641157
+ const child = (0, import_node_child_process9.spawn)(emulatorPath, bootArgs, {
641052
641158
  detached: false,
641053
641159
  stdio: ["ignore", "pipe", "pipe"],
641054
641160
  env
@@ -641088,7 +641194,7 @@ function buildAcquireDeviceDeps(sdk, abi, log3) {
641088
641194
  const emulator = sdk.emulator ?? "emulator";
641089
641195
  const avdmanager = sdk.avdmanager ?? "avdmanager";
641090
641196
  const javaPresent = () => {
641091
- const { status } = (0, import_node_child_process8.spawnSync)("java", ["-version"], { stdio: "ignore" });
641197
+ const { status } = (0, import_node_child_process9.spawnSync)("java", ["-version"], { stdio: "ignore" });
641092
641198
  return status === 0;
641093
641199
  };
641094
641200
  const env = {
@@ -641736,7 +641842,7 @@ var APP_DRIVER_PLATFORMS = {
641736
641842
  if (extras?.udid)
641737
641843
  capabilities["appium:udid"] = extras.udid;
641738
641844
  if (descriptor.install) {
641739
- capabilities["appium:app"] = import_node_path13.default.resolve(descriptor.install);
641845
+ capabilities["appium:app"] = import_node_path14.default.resolve(descriptor.install);
641740
641846
  }
641741
641847
  if (descriptor.activity) {
641742
641848
  capabilities["appium:appActivity"] = descriptor.activity;
@@ -641779,20 +641885,17 @@ var APP_DRIVER_PLATFORMS = {
641779
641885
  if (classifyAppIdentifier(appId) === "id") {
641780
641886
  capabilities["appium:bundleId"] = appId;
641781
641887
  } else {
641782
- capabilities["appium:app"] = import_node_path13.default.resolve(appId);
641888
+ capabilities["appium:app"] = import_node_path14.default.resolve(appId);
641783
641889
  }
641784
641890
  if (descriptor.install) {
641785
- capabilities["appium:app"] = import_node_path13.default.resolve(descriptor.install);
641891
+ capabilities["appium:app"] = import_node_path14.default.resolve(descriptor.install);
641786
641892
  }
641787
641893
  if (extras?.udid)
641788
641894
  capabilities["appium:udid"] = extras.udid;
641789
641895
  const timeout = descriptor.timeout ?? 6e4;
641790
641896
  capabilities["appium:wdaLaunchTimeout"] = Math.max(timeout, 12e4);
641791
641897
  capabilities["appium:wdaConnectionTimeout"] = Math.max(timeout, 12e4);
641792
- const derivedDataPath = process.env.DOC_DETECTIVE_IOS_WDA_DERIVED_DATA_PATH;
641793
- if (derivedDataPath && derivedDataPath.trim()) {
641794
- capabilities["appium:derivedDataPath"] = derivedDataPath.trim();
641795
- }
641898
+ applyManagedWdaCapabilities(capabilities, extras?.locateWda);
641796
641899
  return capabilities;
641797
641900
  },
641798
641901
  unsupportedFields: [
@@ -641852,18 +641955,18 @@ function resolveAppSurfaceRef(surface, appSession) {
641852
641955
  return null;
641853
641956
  }
641854
641957
  function invalidateStaleAppiumManifest(home, driverPackage) {
641855
- const cacheDir = import_node_path13.default.join(home, "node_modules", ".cache", "appium");
641958
+ const cacheDir = import_node_path14.default.join(home, "node_modules", ".cache", "appium");
641856
641959
  try {
641857
- const manifest = import_node_fs16.default.readFileSync(import_node_path13.default.join(cacheDir, "extensions.yaml"), "utf8");
641960
+ const manifest = import_node_fs17.default.readFileSync(import_node_path14.default.join(cacheDir, "extensions.yaml"), "utf8");
641858
641961
  if (!manifest.includes(driverPackage)) {
641859
- import_node_fs16.default.rmSync(cacheDir, { recursive: true, force: true });
641962
+ import_node_fs17.default.rmSync(cacheDir, { recursive: true, force: true });
641860
641963
  }
641861
641964
  } catch {
641862
641965
  }
641863
641966
  }
641864
641967
  async function probeMacAccessibility() {
641865
641968
  return await new Promise((resolve) => {
641866
- (0, import_node_child_process9.execFile)("osascript", [
641969
+ (0, import_node_child_process10.execFile)("osascript", [
641867
641970
  "-l",
641868
641971
  "JavaScript",
641869
641972
  "-e",
@@ -641879,7 +641982,7 @@ async function probeMacAccessibility() {
641879
641982
  function probeIosToolchain(deps = {}) {
641880
641983
  const platform = deps.platform ?? process.platform;
641881
641984
  const run2 = deps.run ?? ((command, args) => {
641882
- const result = (0, import_node_child_process9.spawnSync)(command, args, {
641985
+ const result = (0, import_node_child_process10.spawnSync)(command, args, {
641883
641986
  encoding: "utf8",
641884
641987
  windowsHide: true,
641885
641988
  // xcrun/simctl gets 2 minutes for the cold CoreSimulator warm-up;
@@ -642170,7 +642273,8 @@ async function startAppSurface({ config, step, appSession, platform, serverDeps
642170
642273
  const deviceSession = sessions.get(deviceName);
642171
642274
  if (!deviceSession) {
642172
642275
  const capabilities = platformDriver.buildCapabilities(descriptor, appId, {
642173
- udid: acquired.entry.udid
642276
+ udid: acquired.entry.udid,
642277
+ locateWda: serverDeps.locateWda ?? (() => locateManagedWda({ ctx: { cacheDir: config?.cacheDir } }))
642174
642278
  });
642175
642279
  Object.assign(capabilities, descriptor.driverOptions ?? {});
642176
642280
  try {
@@ -642189,7 +642293,7 @@ async function startAppSurface({ config, step, appSession, platform, serverDeps
642189
642293
  driver = deviceSession.driver;
642190
642294
  try {
642191
642295
  if (descriptor.install)
642192
- await driver.installApp(import_node_path13.default.resolve(descriptor.install));
642296
+ await driver.installApp(import_node_path14.default.resolve(descriptor.install));
642193
642297
  if (descriptor.activity) {
642194
642298
  await driver.execute("mobile: startActivity", {
642195
642299
  appPackage: appId,
@@ -642355,7 +642459,7 @@ function defaultForceKill(pid) {
642355
642459
  function queryWindowsProcessTable() {
642356
642460
  return new Promise((resolve, reject) => {
642357
642461
  const script = 'Get-CimInstance Win32_Process | ForEach-Object { "$($_.ProcessId),$($_.ParentProcessId)" }';
642358
- (0, import_node_child_process9.execFile)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { windowsHide: true, timeout: 1e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
642462
+ (0, import_node_child_process10.execFile)("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], { windowsHide: true, timeout: 1e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
642359
642463
  if (error)
642360
642464
  return reject(error);
642361
642465
  const rows = [];
@@ -642830,10 +642934,10 @@ init_validate();
642830
642934
  init_loader();
642831
642935
 
642832
642936
  // dist/core/tests/ffmpegRecorder.js
642833
- var import_node_child_process10 = require("node:child_process");
642937
+ var import_node_child_process11 = require("node:child_process");
642834
642938
  var import_node_os7 = __toESM(require("node:os"), 1);
642835
- var import_node_path14 = __toESM(require("node:path"), 1);
642836
- var import_node_fs17 = __toESM(require("node:fs"), 1);
642939
+ var import_node_path15 = __toESM(require("node:path"), 1);
642940
+ var import_node_fs18 = __toESM(require("node:fs"), 1);
642837
642941
  var import_node_crypto6 = __toESM(require("node:crypto"), 1);
642838
642942
  init_loader();
642839
642943
  init_utils();
@@ -642912,7 +643016,7 @@ function browserCaptureTitle(contextId) {
642912
643016
  return `RECORD_ME_${safeContextId(contextId)}`;
642913
643017
  }
642914
643018
  function browserDownloadDir(contextId) {
642915
- return import_node_path14.default.join(import_node_os7.default.tmpdir(), "doc-detective", "recordings", safeContextId(contextId));
643019
+ return import_node_path15.default.join(import_node_os7.default.tmpdir(), "doc-detective", "recordings", safeContextId(contextId));
642916
643020
  }
642917
643021
  function engineFields(record) {
642918
643022
  const engine = record && typeof record === "object" ? record.engine : void 0;
@@ -643051,11 +643155,11 @@ async function resolveCropGeometry({ driver, target }) {
643051
643155
  return null;
643052
643156
  }
643053
643157
  function ffmpegPathEnv(ffmpegPath, baseEnv = process.env) {
643054
- const dir = import_node_path14.default.dirname(ffmpegPath);
643158
+ const dir = import_node_path15.default.dirname(ffmpegPath);
643055
643159
  const pathKey = Object.keys(baseEnv).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
643056
643160
  const existing = baseEnv[pathKey];
643057
643161
  return {
643058
- [pathKey]: existing ? `${dir}${import_node_path14.default.delimiter}${existing}` : dir
643162
+ [pathKey]: existing ? `${dir}${import_node_path15.default.delimiter}${existing}` : dir
643059
643163
  };
643060
643164
  }
643061
643165
  function parseCaptureFrameSize(stderr) {
@@ -643079,7 +643183,7 @@ async function detectDisplayPointSize() {
643079
643183
  if (process.platform !== "darwin")
643080
643184
  return null;
643081
643185
  return await new Promise((resolve) => {
643082
- (0, import_node_child_process10.execFile)("osascript", [
643186
+ (0, import_node_child_process11.execFile)("osascript", [
643083
643187
  "-l",
643084
643188
  "JavaScript",
643085
643189
  "-e",
@@ -643225,7 +643329,7 @@ async function detectMacScreenIndex(ffmpegPath) {
643225
643329
  resolve(v);
643226
643330
  };
643227
643331
  try {
643228
- proc = (0, import_node_child_process10.spawn)(ffmpegPath, ["-f", "avfoundation", "-list_devices", "true", "-i", ""], { stdio: ["ignore", "ignore", "pipe"] });
643332
+ proc = (0, import_node_child_process11.spawn)(ffmpegPath, ["-f", "avfoundation", "-list_devices", "true", "-i", ""], { stdio: ["ignore", "ignore", "pipe"] });
643229
643333
  proc.stderr?.on("data", (d) => {
643230
643334
  out += d.toString();
643231
643335
  });
@@ -643254,7 +643358,7 @@ async function detectX11ScreenSize(display) {
643254
643358
  };
643255
643359
  try {
643256
643360
  const env = display ? { ...process.env, DISPLAY: display } : process.env;
643257
- proc = (0, import_node_child_process10.spawn)("xdpyinfo", [], { env, stdio: ["ignore", "pipe", "ignore"] });
643361
+ proc = (0, import_node_child_process11.spawn)("xdpyinfo", [], { env, stdio: ["ignore", "pipe", "ignore"] });
643258
643362
  proc.stdout?.on("data", (d) => {
643259
643363
  out += d.toString();
643260
643364
  });
@@ -643272,7 +643376,7 @@ async function detectX11ScreenSize(display) {
643272
643376
  async function checkSystemBinary(name) {
643273
643377
  return new Promise((resolve) => {
643274
643378
  try {
643275
- const proc = (0, import_node_child_process10.spawn)(name, ["-help"], { stdio: "ignore" });
643379
+ const proc = (0, import_node_child_process11.spawn)(name, ["-help"], { stdio: "ignore" });
643276
643380
  proc.on("error", () => resolve(false));
643277
643381
  proc.on("close", () => resolve(true));
643278
643382
  } catch {
@@ -643289,7 +643393,7 @@ async function startXvfb(display, opts = {}) {
643289
643393
  const w = opts.width ?? defW;
643290
643394
  const h = opts.height ?? defH;
643291
643395
  const startMs = Date.now();
643292
- const proc = (0, import_node_child_process10.spawn)("Xvfb", [display, "-screen", "0", `${w}x${h}x24`, "-nolisten", "tcp"], { stdio: "ignore" });
643396
+ const proc = (0, import_node_child_process11.spawn)("Xvfb", [display, "-screen", "0", `${w}x${h}x24`, "-nolisten", "tcp"], { stdio: "ignore" });
643293
643397
  let spawnErr = null;
643294
643398
  proc.on("error", (e) => {
643295
643399
  spawnErr = e;
@@ -643301,7 +643405,7 @@ async function startXvfb(display, opts = {}) {
643301
643405
  if (proc.exitCode !== null)
643302
643406
  throw new Error(`Xvfb exited early on ${display} (code ${proc.exitCode})`);
643303
643407
  try {
643304
- if (import_node_fs17.default.statSync(lock).mtimeMs >= startMs)
643408
+ if (import_node_fs18.default.statSync(lock).mtimeMs >= startMs)
643305
643409
  return proc;
643306
643410
  } catch {
643307
643411
  }
@@ -643573,11 +643677,11 @@ function hasUnresolvedMetaReference(expression, context) {
643573
643677
  }
643574
643678
  return false;
643575
643679
  }
643576
- function getMetaValue(path26, context) {
643680
+ function getMetaValue(path27, context) {
643577
643681
  if (!context) {
643578
643682
  return void 0;
643579
643683
  }
643580
- const [basePath, jsonPointer] = path26.split("#");
643684
+ const [basePath, jsonPointer] = path27.split("#");
643581
643685
  const resolvedPath = resolvePathTemplateVariables(basePath, context);
643582
643686
  let value = getNestedProperty(context, resolvedPath);
643583
643687
  if (jsonPointer && value) {
@@ -643594,9 +643698,9 @@ function getMetaValue(path26, context) {
643594
643698
  }
643595
643699
  return value;
643596
643700
  }
643597
- function resolvePathTemplateVariables(path26, context) {
643701
+ function resolvePathTemplateVariables(path27, context) {
643598
643702
  const templateRegex = /\{\{(\w+)\}\}/g;
643599
- return path26.replace(templateRegex, (match, varName) => {
643703
+ return path27.replace(templateRegex, (match, varName) => {
643600
643704
  if (context && context.id && varName === "id") {
643601
643705
  return context.id;
643602
643706
  }
@@ -643633,10 +643737,10 @@ async function resolveEmbeddedExpressions(str, context) {
643633
643737
  parts.push(str.slice(lastIdx));
643634
643738
  return parts.join("");
643635
643739
  }
643636
- function getNestedProperty(obj, path26) {
643637
- if (!obj || !path26)
643740
+ function getNestedProperty(obj, path27) {
643741
+ if (!obj || !path27)
643638
643742
  return void 0;
643639
- const parts = path26.split(".");
643743
+ const parts = path27.split(".");
643640
643744
  let current = obj;
643641
643745
  for (const part of parts) {
643642
643746
  if (current === null || current === void 0)
@@ -645317,8 +645421,8 @@ async function startBackgroundProcessSurface({ config, descriptor, processRegist
645317
645421
  }
645318
645422
 
645319
645423
  // dist/core/tests/runShell.js
645320
- var import_node_fs18 = __toESM(require("node:fs"), 1);
645321
- var import_node_path15 = __toESM(require("node:path"), 1);
645424
+ var import_node_fs19 = __toESM(require("node:fs"), 1);
645425
+ var import_node_path16 = __toESM(require("node:path"), 1);
645322
645426
  async function runShell({ config, step, driver, processRegistry }) {
645323
645427
  const result = {
645324
645428
  status: "PASS",
@@ -645431,19 +645535,19 @@ async function runShell({ config, step, driver, processRegistry }) {
645431
645535
  descriptions.push(stdioMatched ? `Found expected output (${step.runShell.stdio}) in stdio.` : isRegex ? `Couldn't find expected output (${step.runShell.stdio}) in actual output (stdout or stderr).` : `Couldn't find expected output (${step.runShell.stdio}) in stdio (stdout or stderr).`);
645432
645536
  }
645433
645537
  if (step.runShell.path) {
645434
- const dir = import_node_path15.default.dirname(step.runShell.path);
645435
- if (!import_node_fs18.default.existsSync(dir)) {
645436
- import_node_fs18.default.mkdirSync(dir, { recursive: true });
645538
+ const dir = import_node_path16.default.dirname(step.runShell.path);
645539
+ if (!import_node_fs19.default.existsSync(dir)) {
645540
+ import_node_fs19.default.mkdirSync(dir, { recursive: true });
645437
645541
  }
645438
645542
  let filePath = step.runShell.path;
645439
645543
  log(config, "debug", `Saving stdio to file: ${filePath}`);
645440
- if (!import_node_fs18.default.existsSync(filePath)) {
645441
- import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645544
+ if (!import_node_fs19.default.existsSync(filePath)) {
645545
+ import_node_fs19.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645442
645546
  } else {
645443
645547
  if (step.runShell.overwrite == "false") {
645444
645548
  descriptions.push(`Didn't save output. File already exists.`);
645445
645549
  }
645446
- const existingFile = import_node_fs18.default.readFileSync(filePath, "utf8");
645550
+ const existingFile = import_node_fs19.default.readFileSync(filePath, "utf8");
645447
645551
  const fractionalDiff = calculateFractionalDifference(existingFile, result.outputs.stdio.stdout);
645448
645552
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
645449
645553
  result.outputs.variation = fractionalDiff;
@@ -645453,13 +645557,13 @@ async function runShell({ config, step, driver, processRegistry }) {
645453
645557
  });
645454
645558
  if (fractionalDiff > step.runShell.maxVariation) {
645455
645559
  if (step.runShell.overwrite == "aboveVariation") {
645456
- import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645560
+ import_node_fs19.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645457
645561
  descriptions.push(`Saved output to file.`);
645458
645562
  }
645459
645563
  descriptions.push(`The difference between the existing output and the new output (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.runShell.maxVariation}).`);
645460
645564
  } else {
645461
645565
  if (step.runShell.overwrite == "true") {
645462
- import_node_fs18.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645566
+ import_node_fs19.default.writeFileSync(filePath, result.outputs.stdio.stdout);
645463
645567
  descriptions.push(`Saved output to file.`);
645464
645568
  }
645465
645569
  descriptions.push(`Saved-file variation (${fractionalDiff.toFixed(2)}) is within the max accepted variation (${step.runShell.maxVariation}).`);
@@ -645806,8 +645910,8 @@ async function swipeSurface({ config, step, driver, appSession }) {
645806
645910
  // dist/core/tests/saveScreenshot.js
645807
645911
  init_validate();
645808
645912
  init_utils();
645809
- var import_node_path16 = __toESM(require("node:path"), 1);
645810
- var import_node_fs19 = __toESM(require("node:fs"), 1);
645913
+ var import_node_path17 = __toESM(require("node:path"), 1);
645914
+ var import_node_fs20 = __toESM(require("node:fs"), 1);
645811
645915
  init_loader();
645812
645916
  var _pngjs = null;
645813
645917
  var _sharp = null;
@@ -645958,7 +646062,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645958
646062
  if (typeof step.screenshot.path === "undefined") {
645959
646063
  step.screenshot.path = `${step.stepId}.png`;
645960
646064
  if (step.screenshot.directory) {
645961
- step.screenshot.path = import_node_path16.default.resolve(step.screenshot.directory, step.screenshot.path);
646065
+ step.screenshot.path = import_node_path17.default.resolve(step.screenshot.directory, step.screenshot.path);
645962
646066
  }
645963
646067
  }
645964
646068
  step.screenshot = {
@@ -645994,17 +646098,17 @@ async function saveScreenshot({ config, step, driver, appSession }) {
645994
646098
  } catch {
645995
646099
  urlPathname = originalUrlPath;
645996
646100
  }
645997
- const rawBase = import_node_path16.default.basename(urlPathname.split("?")[0].split("#")[0].replace(/\\/g, "/"));
646101
+ const rawBase = import_node_path17.default.basename(urlPathname.split("?")[0].split("#")[0].replace(/\\/g, "/"));
645998
646102
  const safeBase = sanitizeFilesystemName(rawBase, `${step.stepId}.png`);
645999
- dir = import_node_path16.default.join(process.cwd(), "doc-detective-runs", getOrInitRunTimestamp(config));
646000
- if (!import_node_fs19.default.existsSync(dir)) {
646001
- import_node_fs19.default.mkdirSync(dir, { recursive: true });
646103
+ dir = import_node_path17.default.join(process.cwd(), "doc-detective-runs", getOrInitRunTimestamp(config));
646104
+ if (!import_node_fs20.default.existsSync(dir)) {
646105
+ import_node_fs20.default.mkdirSync(dir, { recursive: true });
646002
646106
  }
646003
646107
  const captureId = `${step.stepId || "screenshot"}_${Date.now()}`;
646004
- filePath = import_node_path16.default.join(dir, `${captureId}_${safeBase}`);
646005
- const resolvedDir = import_node_path16.default.resolve(dir);
646006
- const resolvedFile = import_node_path16.default.resolve(filePath);
646007
- if (!resolvedFile.startsWith(resolvedDir + import_node_path16.default.sep)) {
646108
+ filePath = import_node_path17.default.join(dir, `${captureId}_${safeBase}`);
646109
+ const resolvedDir = import_node_path17.default.resolve(dir);
646110
+ const resolvedFile = import_node_path17.default.resolve(filePath);
646111
+ if (!resolvedFile.startsWith(resolvedDir + import_node_path17.default.sep)) {
646008
646112
  result.status = "FAIL";
646009
646113
  result.description = `Refusing to write screenshot outside run folder: ${resolvedFile}`;
646010
646114
  return result;
@@ -646013,11 +646117,11 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646013
646117
  log(config, "debug", `Screenshot path is a URL (${redactedUrl}); overwrite is ignored, running comparison only.`);
646014
646118
  }
646015
646119
  } else {
646016
- dir = import_node_path16.default.dirname(step.screenshot.path);
646017
- if (!import_node_fs19.default.existsSync(dir)) {
646018
- import_node_fs19.default.mkdirSync(dir, { recursive: true });
646120
+ dir = import_node_path17.default.dirname(step.screenshot.path);
646121
+ if (!import_node_fs20.default.existsSync(dir)) {
646122
+ import_node_fs20.default.mkdirSync(dir, { recursive: true });
646019
646123
  }
646020
- if (import_node_fs19.default.existsSync(filePath)) {
646124
+ if (import_node_fs20.default.existsSync(filePath)) {
646021
646125
  if (step.screenshot.overwrite == "false") {
646022
646126
  result.status = "SKIPPED";
646023
646127
  result.description = `File already exists: ${filePath}`;
@@ -646025,7 +646129,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646025
646129
  return result;
646026
646130
  } else {
646027
646131
  existFilePath = filePath;
646028
- filePath = import_node_path16.default.join(dir, `${step.stepId}_${Date.now()}.png`);
646132
+ filePath = import_node_path17.default.join(dir, `${step.stepId}_${Date.now()}.png`);
646029
646133
  }
646030
646134
  }
646031
646135
  }
@@ -646127,8 +646231,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646127
646231
  } catch (error) {
646128
646232
  result.status = "FAIL";
646129
646233
  result.description = `Couldn't save screenshot. ${error}`;
646130
- if (existFilePath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646131
- import_node_fs19.default.unlinkSync(filePath);
646234
+ if (existFilePath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646235
+ import_node_fs20.default.unlinkSync(filePath);
646132
646236
  }
646133
646237
  return result;
646134
646238
  } finally {
@@ -646183,7 +646287,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646183
646287
  rect.width = clamped.width;
646184
646288
  rect.height = clamped.height;
646185
646289
  log(config, "debug", { padded_rect: rect });
646186
- const croppedPath = import_node_path16.default.join(dir, `cropped_${step.stepId || Date.now()}.png`);
646290
+ const croppedPath = import_node_path17.default.join(dir, `cropped_${step.stepId || Date.now()}.png`);
646187
646291
  try {
646188
646292
  await sharp(filePath).extract({
646189
646293
  left: rect.x,
@@ -646191,12 +646295,12 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646191
646295
  width: rect.width,
646192
646296
  height: rect.height
646193
646297
  }).toFile(croppedPath);
646194
- import_node_fs19.default.renameSync(croppedPath, filePath);
646298
+ import_node_fs20.default.renameSync(croppedPath, filePath);
646195
646299
  } catch (error) {
646196
646300
  result.status = "FAIL";
646197
646301
  result.description = `Couldn't crop image. ${error}`;
646198
- if (existFilePath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646199
- import_node_fs19.default.unlinkSync(filePath);
646302
+ if (existFilePath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646303
+ import_node_fs20.default.unlinkSync(filePath);
646200
646304
  }
646201
646305
  return result;
646202
646306
  }
@@ -646204,7 +646308,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646204
646308
  if (existFilePath) {
646205
646309
  if (step.screenshot.overwrite == "true" && !isUrlPath) {
646206
646310
  result.description += ` Overwrote existing file.`;
646207
- import_node_fs19.default.renameSync(filePath, existFilePath);
646311
+ import_node_fs20.default.renameSync(filePath, existFilePath);
646208
646312
  result.outputs.screenshotPath = existFilePath;
646209
646313
  result.outputs.changed = true;
646210
646314
  if (step.screenshot.sourceIntegration) {
@@ -646217,13 +646321,13 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646217
646321
  let img1;
646218
646322
  let img2;
646219
646323
  try {
646220
- img1 = PNG.sync.read(import_node_fs19.default.readFileSync(existFilePath));
646221
- img2 = PNG.sync.read(import_node_fs19.default.readFileSync(filePath));
646324
+ img1 = PNG.sync.read(import_node_fs20.default.readFileSync(existFilePath));
646325
+ img2 = PNG.sync.read(import_node_fs20.default.readFileSync(filePath));
646222
646326
  } catch (error) {
646223
646327
  result.status = "FAIL";
646224
646328
  result.description = isUrlPath ? `Couldn't decode PNG for comparison. The URL reference (${redactedUrl}) may not be a valid PNG. ${error}` : `Couldn't decode PNG for comparison. ${error}`;
646225
- if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646226
- import_node_fs19.default.unlinkSync(filePath);
646329
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646330
+ import_node_fs20.default.unlinkSync(filePath);
646227
646331
  }
646228
646332
  return result;
646229
646333
  }
@@ -646235,8 +646339,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646235
646339
  });
646236
646340
  if (!aspectRatioMatch) {
646237
646341
  result.description = `Couldn't compare images. Images have different aspect ratios.`;
646238
- if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646239
- import_node_fs19.default.unlinkSync(filePath);
646342
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646343
+ import_node_fs20.default.unlinkSync(filePath);
646240
646344
  }
646241
646345
  return await evaluateApplicable();
646242
646346
  }
@@ -646263,8 +646367,8 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646263
646367
  } catch (error) {
646264
646368
  result.status = "FAIL";
646265
646369
  result.description = `Couldn't load screenshot comparison dependency (pixelmatch). ${error?.message ?? error}`;
646266
- if (!isUrlPath && filePath !== existFilePath && import_node_fs19.default.existsSync(filePath)) {
646267
- import_node_fs19.default.unlinkSync(filePath);
646370
+ if (!isUrlPath && filePath !== existFilePath && import_node_fs20.default.existsSync(filePath)) {
646371
+ import_node_fs20.default.unlinkSync(filePath);
646268
646372
  }
646269
646373
  return result;
646270
646374
  }
@@ -646282,7 +646386,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646282
646386
  });
646283
646387
  if (fractionalDiff > step.screenshot.maxVariation) {
646284
646388
  if (step.screenshot.overwrite == "aboveVariation" && !isUrlPath) {
646285
- import_node_fs19.default.renameSync(filePath, existFilePath);
646389
+ import_node_fs20.default.renameSync(filePath, existFilePath);
646286
646390
  }
646287
646391
  result.description += ` The difference between the existing screenshot and new screenshot (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.screenshot.maxVariation}).`;
646288
646392
  if (isUrlPath) {
@@ -646307,7 +646411,7 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646307
646411
  result.outputs.sourceIntegration = step.screenshot.sourceIntegration;
646308
646412
  }
646309
646413
  if (step.screenshot.overwrite != "true") {
646310
- import_node_fs19.default.unlinkSync(filePath);
646414
+ import_node_fs20.default.unlinkSync(filePath);
646311
646415
  }
646312
646416
  }
646313
646417
  }
@@ -646326,10 +646430,10 @@ async function saveScreenshot({ config, step, driver, appSession }) {
646326
646430
  // dist/core/tests/startRecording.js
646327
646431
  init_validate();
646328
646432
  init_utils();
646329
- var import_node_child_process11 = require("node:child_process");
646433
+ var import_node_child_process12 = require("node:child_process");
646330
646434
  var import_node_crypto7 = require("node:crypto");
646331
- var import_node_path17 = __toESM(require("node:path"), 1);
646332
- var import_node_fs20 = __toESM(require("node:fs"), 1);
646435
+ var import_node_path18 = __toESM(require("node:path"), 1);
646436
+ var import_node_fs21 = __toESM(require("node:fs"), 1);
646333
646437
  var import_node_os8 = __toESM(require("node:os"), 1);
646334
646438
  async function startRecording({ config, context, step, driver, recordingHost, appSession, deps = {} }) {
646335
646439
  let result = {
@@ -646398,7 +646502,7 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646398
646502
  if (typeof step.record.path === "undefined") {
646399
646503
  step.record.path = `${step.stepId}.mp4`;
646400
646504
  if (step.record.directory) {
646401
- step.record.path = import_node_path17.default.resolve(step.record.directory, step.record.path);
646505
+ step.record.path = import_node_path18.default.resolve(step.record.directory, step.record.path);
646402
646506
  }
646403
646507
  }
646404
646508
  step.record = {
@@ -646406,18 +646510,18 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646406
646510
  overwrite: step.record.overwrite || "false"
646407
646511
  };
646408
646512
  let filePath = step.record.path;
646409
- const baseName = import_node_path17.default.basename(filePath, import_node_path17.default.extname(filePath));
646410
- const dir = import_node_path17.default.dirname(step.record.path);
646411
- if (!import_node_fs20.default.existsSync(dir)) {
646412
- import_node_fs20.default.mkdirSync(dir, { recursive: true });
646513
+ const baseName = import_node_path18.default.basename(filePath, import_node_path18.default.extname(filePath));
646514
+ const dir = import_node_path18.default.dirname(step.record.path);
646515
+ if (!import_node_fs21.default.existsSync(dir)) {
646516
+ import_node_fs21.default.mkdirSync(dir, { recursive: true });
646413
646517
  }
646414
- if (import_node_fs20.default.existsSync(filePath) && step.record.overwrite == "false") {
646518
+ if (import_node_fs21.default.existsSync(filePath) && step.record.overwrite == "false") {
646415
646519
  result.status = "SKIPPED";
646416
646520
  result.description = `File already exists: ${filePath}`;
646417
646521
  return result;
646418
646522
  }
646419
646523
  const normalizeActiveTarget = (p) => {
646420
- const resolved = import_node_path17.default.resolve(p);
646524
+ const resolved = import_node_path18.default.resolve(p);
646421
646525
  return process.platform === "win32" || process.platform === "darwin" ? resolved.toLowerCase() : resolved;
646422
646526
  };
646423
646527
  const normalizedTarget = normalizeActiveTarget(filePath);
@@ -646505,13 +646609,13 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646505
646609
  }
646506
646610
  const captureTitle = browserCaptureTitle(context.contextId);
646507
646611
  const downloadDir = browserDownloadDir(context.contextId);
646508
- if (!import_node_fs20.default.existsSync(downloadDir)) {
646509
- import_node_fs20.default.mkdirSync(downloadDir, { recursive: true });
646612
+ if (!import_node_fs21.default.existsSync(downloadDir)) {
646613
+ import_node_fs21.default.mkdirSync(downloadDir, { recursive: true });
646510
646614
  }
646511
- const downloadPath = import_node_path17.default.join(downloadDir, `${baseName}.webm`);
646512
- if (import_node_fs20.default.existsSync(downloadPath)) {
646615
+ const downloadPath = import_node_path18.default.join(downloadDir, `${baseName}.webm`);
646616
+ if (import_node_fs21.default.existsSync(downloadPath)) {
646513
646617
  try {
646514
- import_node_fs20.default.unlinkSync(downloadPath);
646618
+ import_node_fs21.default.unlinkSync(downloadPath);
646515
646619
  } catch {
646516
646620
  }
646517
646621
  }
@@ -646651,10 +646755,10 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646651
646755
  } catch {
646652
646756
  }
646653
646757
  }
646654
- const tempDir = import_node_path17.default.join(import_node_os8.default.tmpdir(), "doc-detective", "recordings");
646655
- if (!import_node_fs20.default.existsSync(tempDir))
646656
- import_node_fs20.default.mkdirSync(tempDir, { recursive: true });
646657
- const tempPath = import_node_path17.default.join(tempDir, `${safeContextId(context.contextId)}-${baseName}-${(0, import_node_crypto7.randomUUID)().slice(0, 8)}.mkv`);
646758
+ const tempDir = import_node_path18.default.join(import_node_os8.default.tmpdir(), "doc-detective", "recordings");
646759
+ if (!import_node_fs21.default.existsSync(tempDir))
646760
+ import_node_fs21.default.mkdirSync(tempDir, { recursive: true });
646761
+ const tempPath = import_node_path18.default.join(tempDir, `${safeContextId(context.contextId)}-${baseName}-${(0, import_node_crypto7.randomUUID)().slice(0, 8)}.mkv`);
646658
646762
  let ffmpegPath;
646659
646763
  try {
646660
646764
  ffmpegPath = await (deps.getFfmpegPath ?? getFfmpegPath)({
@@ -646685,7 +646789,7 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646685
646789
  screenSize
646686
646790
  });
646687
646791
  log(config, "debug", `ffmpeg recording: platform=${process.platform} target=${plan.target}${screenIndex !== void 0 ? ` screen=${screenIndex}` : ""}${context.__display ? ` display=${context.__display}` : ""} -> ${tempPath}`);
646688
- const proc = (deps.spawn ?? import_node_child_process11.spawn)(ffmpegPath, args, {
646792
+ const proc = (deps.spawn ?? import_node_child_process12.spawn)(ffmpegPath, args, {
646689
646793
  stdio: ["pipe", "ignore", "pipe"]
646690
646794
  });
646691
646795
  let spawnError = null;
@@ -646724,10 +646828,10 @@ async function startRecording({ config, context, step, driver, recordingHost, ap
646724
646828
  // dist/core/tests/stopRecording.js
646725
646829
  init_validate();
646726
646830
  init_utils();
646727
- var import_node_child_process12 = require("node:child_process");
646831
+ var import_node_child_process13 = require("node:child_process");
646728
646832
  var import_node_crypto8 = require("node:crypto");
646729
- var import_node_path18 = __toESM(require("node:path"), 1);
646730
- var import_node_fs21 = __toESM(require("node:fs"), 1);
646833
+ var import_node_path19 = __toESM(require("node:path"), 1);
646834
+ var import_node_fs22 = __toESM(require("node:fs"), 1);
646731
646835
  var import_node_os9 = __toESM(require("node:os"), 1);
646732
646836
  async function stopRecording({ config, step, driver, deps = {} }) {
646733
646837
  let result = {
@@ -646922,14 +647026,14 @@ async function stopRecording({ config, step, driver, deps = {} }) {
646922
647026
  dropHandle();
646923
647027
  return result;
646924
647028
  }
646925
- if (import_node_path18.default.extname(recording.targetPath) === ".mp4") {
646926
- import_node_fs21.default.writeFileSync(recording.targetPath, buffer);
647029
+ if (import_node_path19.default.extname(recording.targetPath) === ".mp4") {
647030
+ import_node_fs22.default.writeFileSync(recording.targetPath, buffer);
646927
647031
  } else {
646928
- const tempDir = import_node_path18.default.join(import_node_os9.default.tmpdir(), "doc-detective", "recordings");
646929
- if (!import_node_fs21.default.existsSync(tempDir))
646930
- import_node_fs21.default.mkdirSync(tempDir, { recursive: true });
646931
- const tempPath = import_node_path18.default.join(tempDir, `device-${(0, import_node_crypto8.randomUUID)().slice(0, 8)}.mp4`);
646932
- import_node_fs21.default.writeFileSync(tempPath, buffer);
647032
+ const tempDir = import_node_path19.default.join(import_node_os9.default.tmpdir(), "doc-detective", "recordings");
647033
+ if (!import_node_fs22.default.existsSync(tempDir))
647034
+ import_node_fs22.default.mkdirSync(tempDir, { recursive: true });
647035
+ const tempPath = import_node_path19.default.join(tempDir, `device-${(0, import_node_crypto8.randomUUID)().slice(0, 8)}.mp4`);
647036
+ import_node_fs22.default.writeFileSync(tempPath, buffer);
646933
647037
  await transcode({
646934
647038
  config,
646935
647039
  sourcePath: tempPath,
@@ -646957,7 +647061,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646957
647061
  const cy = `max(0\\,min(${crop.y}\\,ih-${ch}))`;
646958
647062
  filters.push(`crop=w=${cw}:h=${ch}:x=${cx}:y=${cy}`);
646959
647063
  }
646960
- if (import_node_path18.default.extname(targetPath) === ".gif") {
647064
+ if (import_node_path19.default.extname(targetPath) === ".gif") {
646961
647065
  filters.push("scale=iw:-1:flags=lanczos");
646962
647066
  }
646963
647067
  if (filters.length > 0) {
@@ -646966,7 +647070,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646966
647070
  ffmpegArgs.push(`${targetPath}`);
646967
647071
  const ffmpegPath = await getFfmpegPath({ cacheDir: config?.cacheDir });
646968
647072
  await new Promise((resolve, reject) => {
646969
- const child = (0, import_node_child_process12.spawn)(ffmpegPath, ffmpegArgs);
647073
+ const child = (0, import_node_child_process13.spawn)(ffmpegPath, ffmpegArgs);
646970
647074
  let stderr = "";
646971
647075
  child.stderr?.on("data", (d) => {
646972
647076
  stderr = (stderr + d.toString()).slice(-2e3);
@@ -646975,7 +647079,7 @@ async function transcode({ config, sourcePath, targetPath, deleteSource, crop })
646975
647079
  if (code === 0) {
646976
647080
  if (deleteSource && sourcePath !== targetPath) {
646977
647081
  try {
646978
- import_node_fs21.default.unlinkSync(sourcePath);
647082
+ import_node_fs22.default.unlinkSync(sourcePath);
646979
647083
  } catch {
646980
647084
  }
646981
647085
  }
@@ -646994,7 +647098,7 @@ async function waitForStableFile(filePath, maxSeconds) {
646994
647098
  for (let i = 0; i < deadline; i++) {
646995
647099
  let size = -1;
646996
647100
  try {
646997
- size = import_node_fs21.default.statSync(filePath).size;
647101
+ size = import_node_fs22.default.statSync(filePath).size;
646998
647102
  } catch {
646999
647103
  size = -1;
647000
647104
  }
@@ -647034,8 +647138,8 @@ async function loadVariables({ step }) {
647034
647138
  // dist/core/tests/saveCookie.js
647035
647139
  init_validate();
647036
647140
  init_utils();
647037
- var import_node_path19 = __toESM(require("node:path"), 1);
647038
- var import_node_fs22 = __toESM(require("node:fs"), 1);
647141
+ var import_node_path20 = __toESM(require("node:path"), 1);
647142
+ var import_node_fs23 = __toESM(require("node:fs"), 1);
647039
647143
  async function saveCookie({ config, step, driver }) {
647040
647144
  let result = {
647041
647145
  status: "PASS",
@@ -647052,7 +647156,7 @@ async function saveCookie({ config, step, driver }) {
647052
647156
  let cookieName, filePath, directory, overwrite, domain, variable;
647053
647157
  if (typeof step.saveCookie === "string") {
647054
647158
  if (step.saveCookie.endsWith(".txt")) {
647055
- cookieName = import_node_path19.default.basename(step.saveCookie, ".txt");
647159
+ cookieName = import_node_path20.default.basename(step.saveCookie, ".txt");
647056
647160
  filePath = step.saveCookie;
647057
647161
  } else {
647058
647162
  cookieName = step.saveCookie;
@@ -647101,15 +647205,15 @@ async function saveCookie({ config, step, driver }) {
647101
647205
  }
647102
647206
  if (filePath) {
647103
647207
  const outputDirectory = directory || config.output || process.cwd();
647104
- const fullPath = import_node_path19.default.resolve(outputDirectory, filePath);
647105
- if (import_node_fs22.default.existsSync(fullPath) && !(overwrite === true || overwrite === "true")) {
647208
+ const fullPath = import_node_path20.default.resolve(outputDirectory, filePath);
647209
+ if (import_node_fs23.default.existsSync(fullPath) && !(overwrite === true || overwrite === "true")) {
647106
647210
  result.status = "FAIL";
647107
647211
  result.description = `File '${fullPath}' already exists and overwrite is not enabled.`;
647108
647212
  return result;
647109
647213
  }
647110
- const dir = import_node_path19.default.dirname(fullPath);
647111
- if (!import_node_fs22.default.existsSync(dir)) {
647112
- import_node_fs22.default.mkdirSync(dir, { recursive: true });
647214
+ const dir = import_node_path20.default.dirname(fullPath);
647215
+ if (!import_node_fs23.default.existsSync(dir)) {
647216
+ import_node_fs23.default.mkdirSync(dir, { recursive: true });
647113
647217
  }
647114
647218
  if (targetCookie) {
647115
647219
  const netscapeCookie = formatCookieForNetscape(targetCookie);
@@ -647117,11 +647221,11 @@ async function saveCookie({ config, step, driver }) {
647117
647221
  # This is a cookie file saved by Doc Detective
647118
647222
  ${netscapeCookie}
647119
647223
  `;
647120
- import_node_fs22.default.writeFileSync(fullPath, content, "utf8");
647224
+ import_node_fs23.default.writeFileSync(fullPath, content, "utf8");
647121
647225
  result.description = `Saved cookie '${cookieName}' to '${fullPath}'.`;
647122
647226
  log(config, "debug", `Saved cookie '${cookieName}' to file: ${fullPath}`);
647123
647227
  } else {
647124
- import_node_fs22.default.writeFileSync(fullPath, "# No cookie data\n", "utf8");
647228
+ import_node_fs23.default.writeFileSync(fullPath, "# No cookie data\n", "utf8");
647125
647229
  result.description = `Created empty cookie file at '${fullPath}'.`;
647126
647230
  log(config, "debug", `Created empty cookie file: ${fullPath}`);
647127
647231
  }
@@ -647148,8 +647252,8 @@ function formatCookieForNetscape(cookie) {
647148
647252
  // dist/core/tests/loadCookie.js
647149
647253
  init_validate();
647150
647254
  init_utils();
647151
- var import_node_path20 = __toESM(require("node:path"), 1);
647152
- var import_node_fs23 = __toESM(require("node:fs"), 1);
647255
+ var import_node_path21 = __toESM(require("node:path"), 1);
647256
+ var import_node_fs24 = __toESM(require("node:fs"), 1);
647153
647257
  async function loadCookie({ config, step, driver }) {
647154
647258
  let result = {
647155
647259
  status: "PASS",
@@ -647166,7 +647270,7 @@ async function loadCookie({ config, step, driver }) {
647166
647270
  let cookieName, filePath, directory, domain, variable;
647167
647271
  if (typeof step.loadCookie === "string") {
647168
647272
  if (step.loadCookie.endsWith(".txt")) {
647169
- cookieName = import_node_path20.default.basename(step.loadCookie, ".txt");
647273
+ cookieName = import_node_path21.default.basename(step.loadCookie, ".txt");
647170
647274
  filePath = step.loadCookie;
647171
647275
  } else {
647172
647276
  cookieName = step.loadCookie;
@@ -647179,9 +647283,9 @@ async function loadCookie({ config, step, driver }) {
647179
647283
  domain = step.loadCookie.domain;
647180
647284
  variable = step.loadCookie.variable;
647181
647285
  if (filePath && !cookieName) {
647182
- const ext = import_node_path20.default.extname(filePath).toLowerCase();
647286
+ const ext = import_node_path21.default.extname(filePath).toLowerCase();
647183
647287
  if (ext === ".txt") {
647184
- cookieName = import_node_path20.default.basename(filePath, ext);
647288
+ cookieName = import_node_path21.default.basename(filePath, ext);
647185
647289
  }
647186
647290
  }
647187
647291
  }
@@ -647204,14 +647308,14 @@ async function loadCookie({ config, step, driver }) {
647204
647308
  }
647205
647309
  } else if (filePath) {
647206
647310
  const inputDirectory = directory || config.output || process.cwd();
647207
- const fullPath = import_node_path20.default.resolve(inputDirectory, filePath);
647208
- if (!import_node_fs23.default.existsSync(fullPath)) {
647311
+ const fullPath = import_node_path21.default.resolve(inputDirectory, filePath);
647312
+ if (!import_node_fs24.default.existsSync(fullPath)) {
647209
647313
  result.status = "FAIL";
647210
647314
  result.description = `Cookie file '${fullPath}' not found`;
647211
647315
  return result;
647212
647316
  }
647213
647317
  try {
647214
- const fileContent = import_node_fs23.default.readFileSync(fullPath, "utf8");
647318
+ const fileContent = import_node_fs24.default.readFileSync(fullPath, "utf8");
647215
647319
  const cookies = parseNetscapeCookieFile(fileContent);
647216
647320
  if (cookies.length === 0) {
647217
647321
  result.status = "FAIL";
@@ -647377,8 +647481,8 @@ function isDomainCompatible(currentDomain, cookieDomain) {
647377
647481
  // dist/core/tests/httpRequest.js
647378
647482
  init_validate();
647379
647483
  var import_axios5 = __toESM(require("axios"), 1);
647380
- var import_node_fs24 = __toESM(require("node:fs"), 1);
647381
- var import_node_path21 = __toESM(require("node:path"), 1);
647484
+ var import_node_fs25 = __toESM(require("node:fs"), 1);
647485
+ var import_node_path22 = __toESM(require("node:path"), 1);
647382
647486
  var import_ajv2 = __toESM(require("ajv"), 1);
647383
647487
  init_openapi();
647384
647488
  init_utils();
@@ -647408,9 +647512,9 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
647408
647512
  delete step.httpRequest.openApi.definition;
647409
647513
  } else if (openApiDefinitions.length > 0) {
647410
647514
  findOperation: for (const openApiConfig of openApiDefinitions) {
647411
- for (const path26 in openApiConfig.definition.paths) {
647412
- for (const method in openApiConfig.definition.paths[path26]) {
647413
- if (openApiConfig.definition.paths[path26][method].operationId === step.httpRequest.openApi.operationId) {
647515
+ for (const path27 in openApiConfig.definition.paths) {
647516
+ for (const method in openApiConfig.definition.paths[path27]) {
647517
+ if (openApiConfig.definition.paths[path27][method].operationId === step.httpRequest.openApi.operationId) {
647414
647518
  openApiDefinition = openApiConfig.definition;
647415
647519
  step.httpRequest.openApi = {
647416
647520
  ...openApiConfig,
@@ -647724,20 +647828,20 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
647724
647828
  }
647725
647829
  }
647726
647830
  if (step.httpRequest.path) {
647727
- const dir = import_node_path21.default.dirname(step.httpRequest.path);
647728
- if (!import_node_fs24.default.existsSync(dir)) {
647729
- import_node_fs24.default.mkdirSync(dir, { recursive: true });
647831
+ const dir = import_node_path22.default.dirname(step.httpRequest.path);
647832
+ if (!import_node_fs25.default.existsSync(dir)) {
647833
+ import_node_fs25.default.mkdirSync(dir, { recursive: true });
647730
647834
  }
647731
647835
  let filePath = step.httpRequest.path;
647732
647836
  log(config, "debug", `Saving output to file: ${filePath}`);
647733
- if (!import_node_fs24.default.existsSync(filePath)) {
647734
- await import_node_fs24.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647837
+ if (!import_node_fs25.default.existsSync(filePath)) {
647838
+ await import_node_fs25.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647735
647839
  descriptions.push(`Saved output to file.`);
647736
647840
  } else {
647737
647841
  if (step.httpRequest.overwrite == "false") {
647738
647842
  descriptions.push(`Didn't save output. File already exists.`);
647739
647843
  }
647740
- const existingFile = import_node_fs24.default.readFileSync(filePath, "utf8");
647844
+ const existingFile = import_node_fs25.default.readFileSync(filePath, "utf8");
647741
647845
  const fractionalDiff = calculateFractionalDifference(existingFile, JSON.stringify(response.data, null, 2));
647742
647846
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
647743
647847
  result.outputs.variation = fractionalDiff;
@@ -647747,13 +647851,13 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
647747
647851
  });
647748
647852
  if (fractionalDiff > step.httpRequest.maxVariation) {
647749
647853
  if (step.httpRequest.overwrite == "aboveVariation") {
647750
- await import_node_fs24.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647854
+ await import_node_fs25.default.promises.writeFile(filePath, JSON.stringify(response.data, null, 2));
647751
647855
  descriptions.push(`Saved response to file.`);
647752
647856
  }
647753
647857
  descriptions.push(`The difference between the existing saved response and the new response (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.httpRequest.maxVariation}).`);
647754
647858
  } else {
647755
647859
  if (step.httpRequest.overwrite == "true") {
647756
- import_node_fs24.default.writeFileSync(filePath, JSON.stringify(response.data, null, 2));
647860
+ import_node_fs25.default.writeFileSync(filePath, JSON.stringify(response.data, null, 2));
647757
647861
  descriptions.push(`Saved response to file.`);
647758
647862
  }
647759
647863
  }
@@ -647766,8 +647870,8 @@ async function httpRequest({ config, step, openApiDefinitions = [] }) {
647766
647870
  result.description = descriptions.join(" ").trim();
647767
647871
  return result;
647768
647872
  }
647769
- function fieldExistsAtPath(obj, path26) {
647770
- const segments = path26.match(/[^.[\]]+/g);
647873
+ function fieldExistsAtPath(obj, path27) {
647874
+ const segments = path27.match(/[^.[\]]+/g);
647771
647875
  if (!segments) {
647772
647876
  return false;
647773
647877
  }
@@ -647957,8 +648061,8 @@ async function clickElement({ config, step, driver, appSession }) {
647957
648061
  // dist/core/tests/runCode.js
647958
648062
  init_validate();
647959
648063
  init_utils();
647960
- var import_node_fs25 = __toESM(require("node:fs"), 1);
647961
- var import_node_path22 = __toESM(require("node:path"), 1);
648064
+ var import_node_fs26 = __toESM(require("node:fs"), 1);
648065
+ var import_node_path23 = __toESM(require("node:path"), 1);
647962
648066
  var import_node_os10 = __toESM(require("node:os"), 1);
647963
648067
  function createTempScript(code, language) {
647964
648068
  let extension;
@@ -647983,9 +648087,9 @@ function createTempScript(code, language) {
647983
648087
  extension = "";
647984
648088
  }
647985
648089
  const tmpDir = import_node_os10.default.tmpdir();
647986
- const tmpFile = import_node_path22.default.join(tmpDir, `doc-detective-${Date.now()}${extension}`);
648090
+ const tmpFile = import_node_path23.default.join(tmpDir, `doc-detective-${Date.now()}${extension}`);
647987
648091
  try {
647988
- import_node_fs25.default.writeFileSync(tmpFile, code);
648092
+ import_node_fs26.default.writeFileSync(tmpFile, code);
647989
648093
  } catch (error) {
647990
648094
  throw new Error(`Failed to create temporary script: ${error.message}`);
647991
648095
  }
@@ -648090,7 +648194,7 @@ async function runCode({ config, step, driver, processRegistry }) {
648090
648194
  if (typeof step.runCode.stdio !== "undefined")
648091
648195
  runShellOptions.stdio = step.runCode.stdio;
648092
648196
  if (typeof step.runCode.path !== "undefined") {
648093
- runShellOptions.path = step.runCode.directory ? import_node_path22.default.join(step.runCode.directory, step.runCode.path) : step.runCode.path;
648197
+ runShellOptions.path = step.runCode.directory ? import_node_path23.default.join(step.runCode.directory, step.runCode.path) : step.runCode.path;
648094
648198
  }
648095
648199
  if (step.runCode.background) {
648096
648200
  runShellOptions.background = step.runCode.background;
@@ -648119,7 +648223,7 @@ async function runCode({ config, step, driver, processRegistry }) {
648119
648223
  } finally {
648120
648224
  if (!deferTempCleanup) {
648121
648225
  try {
648122
- import_node_fs25.default.unlinkSync(scriptPath);
648226
+ import_node_fs26.default.unlinkSync(scriptPath);
648123
648227
  log(config, "debug", `Removed temporary script: ${scriptPath}`);
648124
648228
  } catch (error) {
648125
648229
  log(config, "warning", `Failed to remove temporary script: ${scriptPath}`);
@@ -648133,7 +648237,7 @@ async function runCode({ config, step, driver, processRegistry }) {
648133
648237
  init_validate();
648134
648238
  init_utils();
648135
648239
  var import_tree_kill2 = __toESM(require("tree-kill"), 1);
648136
- var import_node_fs26 = __toESM(require("node:fs"), 1);
648240
+ var import_node_fs27 = __toESM(require("node:fs"), 1);
648137
648241
  async function closeSurface({ config, step, driver, processRegistry, appSession }) {
648138
648242
  const result = {
648139
648243
  status: "PASS",
@@ -648282,7 +648386,7 @@ async function closeSurface({ config, step, driver, processRegistry, appSession
648282
648386
  }
648283
648387
  if (entry.tempPath) {
648284
648388
  try {
648285
- import_node_fs26.default.unlinkSync(entry.tempPath);
648389
+ import_node_fs27.default.unlinkSync(entry.tempPath);
648286
648390
  } catch {
648287
648391
  }
648288
648392
  }
@@ -648535,7 +648639,7 @@ async function applyViewport(driver, viewport) {
648535
648639
  }
648536
648640
 
648537
648641
  // dist/core/tests/mobileBrowser.js
648538
- var import_node_path23 = __toESM(require("node:path"), 1);
648642
+ var import_node_path24 = __toESM(require("node:path"), 1);
648539
648643
  var SUPPORTED_MOBILE_BROWSER = {
648540
648644
  android: "chrome",
648541
648645
  ios: "safari"
@@ -648592,7 +648696,7 @@ function mobileBrowserGate({ platform, browser, hasBrowserStep, hasAppStep }) {
648592
648696
  }
648593
648697
  return { action: "proceed", browserName };
648594
648698
  }
648595
- function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
648699
+ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout, locateWda = () => locateManagedWda({ ctx: { cacheDir } }) }) {
648596
648700
  if (platform === "android") {
648597
648701
  return {
648598
648702
  platformName: "Android",
@@ -648610,7 +648714,7 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
648610
648714
  // --allow-insecure=uiautomator2:chromedriver_autodownload. The
648611
648715
  // download lands in the Doc Detective cache so later runs reuse it.
648612
648716
  "appium:chromedriverAutodownload": true,
648613
- "appium:chromedriverExecutableDir": import_node_path23.default.join(cacheDir, MOBILE_CHROMEDRIVER_DIR)
648717
+ "appium:chromedriverExecutableDir": import_node_path24.default.join(cacheDir, MOBILE_CHROMEDRIVER_DIR)
648614
648718
  };
648615
648719
  }
648616
648720
  const capabilities = {
@@ -648624,10 +648728,7 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
648624
648728
  const effectiveTimeout = timeout ?? 9e5;
648625
648729
  capabilities["appium:wdaLaunchTimeout"] = Math.max(effectiveTimeout, 12e4);
648626
648730
  capabilities["appium:wdaConnectionTimeout"] = Math.max(effectiveTimeout, 12e4);
648627
- const derivedDataPath = process.env.DOC_DETECTIVE_IOS_WDA_DERIVED_DATA_PATH;
648628
- if (derivedDataPath && derivedDataPath.trim()) {
648629
- capabilities["appium:derivedDataPath"] = derivedDataPath.trim();
648630
- }
648731
+ applyManagedWdaCapabilities(capabilities, locateWda);
648631
648732
  return capabilities;
648632
648733
  }
648633
648734
 
@@ -648635,7 +648736,7 @@ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout }) {
648635
648736
  init_cacheDir();
648636
648737
 
648637
648738
  // dist/core/tests/iosSimulator.js
648638
- var import_node_child_process13 = require("node:child_process");
648739
+ var import_node_child_process14 = require("node:child_process");
648639
648740
  function parseSimctlDevices(text) {
648640
648741
  let data;
648641
648742
  try {
@@ -648909,7 +649010,7 @@ async function teardownSimulatorRegistry(registry, shutdown) {
648909
649010
  }
648910
649011
  function runSimctl(args, timeout = 6e4) {
648911
649012
  return new Promise((resolve) => {
648912
- (0, import_node_child_process13.execFile)("xcrun", ["simctl", ...args], { timeout, maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
649013
+ (0, import_node_child_process14.execFile)("xcrun", ["simctl", ...args], { timeout, maxBuffer: 32 * 1024 * 1024 }, (error, stdout, stderr) => {
648913
649014
  resolve({
648914
649015
  // A timeout or spawn error sets no numeric `code` (it's null) — treat
648915
649016
  // that as a failure, not success, so a hung `simctl` doesn't look like
@@ -648966,8 +649067,8 @@ function buildAcquireSimulatorDeps(log3) {
648966
649067
  // dist/core/tests/runBrowserScript.js
648967
649068
  init_validate();
648968
649069
  init_utils();
648969
- var import_node_fs27 = __toESM(require("node:fs"), 1);
648970
- var import_node_path24 = __toESM(require("node:path"), 1);
649070
+ var import_node_fs28 = __toESM(require("node:fs"), 1);
649071
+ var import_node_path25 = __toESM(require("node:path"), 1);
648971
649072
  async function runBrowserScript({ config, step, driver }) {
648972
649073
  const result = {
648973
649074
  status: "PASS",
@@ -649042,16 +649143,16 @@ async function runBrowserScript({ config, step, driver }) {
649042
649143
  }
649043
649144
  if (step.runBrowserScript.path) {
649044
649145
  try {
649045
- const dir = import_node_path24.default.dirname(step.runBrowserScript.path);
649046
- if (!import_node_fs27.default.existsSync(dir)) {
649047
- import_node_fs27.default.mkdirSync(dir, { recursive: true });
649146
+ const dir = import_node_path25.default.dirname(step.runBrowserScript.path);
649147
+ if (!import_node_fs28.default.existsSync(dir)) {
649148
+ import_node_fs28.default.mkdirSync(dir, { recursive: true });
649048
649149
  }
649049
649150
  const filePath = step.runBrowserScript.path;
649050
649151
  log(config, "debug", `Saving script result to file: ${filePath}`);
649051
- if (!import_node_fs27.default.existsSync(filePath)) {
649052
- import_node_fs27.default.writeFileSync(filePath, serialized);
649152
+ if (!import_node_fs28.default.existsSync(filePath)) {
649153
+ import_node_fs28.default.writeFileSync(filePath, serialized);
649053
649154
  } else {
649054
- const existingFile = import_node_fs27.default.readFileSync(filePath, "utf8");
649155
+ const existingFile = import_node_fs28.default.readFileSync(filePath, "utf8");
649055
649156
  const fractionalDiff = calculateFractionalDifference(existingFile, serialized);
649056
649157
  log(config, "debug", `Fractional difference: ${fractionalDiff}`);
649057
649158
  result.outputs.variation = fractionalDiff;
@@ -649061,7 +649162,7 @@ async function runBrowserScript({ config, step, driver }) {
649061
649162
  });
649062
649163
  if (fractionalDiff > step.runBrowserScript.maxVariation) {
649063
649164
  if (step.runBrowserScript.overwrite == "aboveVariation" || step.runBrowserScript.overwrite == "true") {
649064
- import_node_fs27.default.writeFileSync(filePath, serialized);
649165
+ import_node_fs28.default.writeFileSync(filePath, serialized);
649065
649166
  descriptions.push(`Saved output to file.`);
649066
649167
  } else {
649067
649168
  descriptions.push(`Didn't overwrite the existing file.`);
@@ -649069,7 +649170,7 @@ async function runBrowserScript({ config, step, driver }) {
649069
649170
  descriptions.push(`The difference between the existing output and the new output (${fractionalDiff.toFixed(2)}) is greater than the max accepted variation (${step.runBrowserScript.maxVariation}).`);
649070
649171
  } else {
649071
649172
  if (step.runBrowserScript.overwrite == "true") {
649072
- import_node_fs27.default.writeFileSync(filePath, serialized);
649173
+ import_node_fs28.default.writeFileSync(filePath, serialized);
649073
649174
  descriptions.push(`Saved output to file.`);
649074
649175
  }
649075
649176
  }
@@ -649237,8 +649338,8 @@ async function dragAndDropElement({ config, step, driver }) {
649237
649338
  }
649238
649339
 
649239
649340
  // dist/core/tests.js
649240
- var import_node_path25 = __toESM(require("node:path"), 1);
649241
- var import_node_child_process14 = require("node:child_process");
649341
+ var import_node_path26 = __toESM(require("node:path"), 1);
649342
+ var import_node_child_process15 = require("node:child_process");
649242
649343
  var import_node_crypto9 = require("node:crypto");
649243
649344
  init_appium();
649244
649345
  init_config();
@@ -649391,7 +649492,7 @@ function getIntegrationConfig(config, sourceIntegration) {
649391
649492
  var import_node_http2 = __toESM(require("node:http"), 1);
649392
649493
  var import_node_https3 = __toESM(require("node:https"), 1);
649393
649494
  var import_node_url6 = require("node:url");
649394
- var __dirname5 = import_node_path25.default.dirname((0, import_node_url6.fileURLToPath)(importMetaUrl));
649495
+ var __dirname5 = import_node_path26.default.dirname((0, import_node_url6.fileURLToPath)(importMetaUrl));
649395
649496
  var KNOWN_BROWSERS = ["firefox", "chrome", "safari", "webkit"];
649396
649497
  function killTree(pid, timeoutMs = 5e3) {
649397
649498
  return new Promise((resolve) => {
@@ -650015,7 +650116,7 @@ async function runSpecs({ resolvedTests }) {
650015
650116
  const runDir = getRunOutputDir(config, {
650016
650117
  create: runArchivesArtifacts(config, specs)
650017
650118
  });
650018
- const runId = import_node_path25.default.basename(runDir);
650119
+ const runId = import_node_path26.default.basename(runDir);
650019
650120
  const report = {
650020
650121
  runId,
650021
650122
  runDir,
@@ -650241,7 +650342,7 @@ async function runSpecs({ resolvedTests }) {
650241
650342
  }
650242
650343
  if (entry?.tempPath) {
650243
650344
  try {
650244
- import_node_fs28.default.unlinkSync(entry.tempPath);
650345
+ import_node_fs29.default.unlinkSync(entry.tempPath);
650245
650346
  } catch {
650246
650347
  }
650247
650348
  }
@@ -650818,7 +650919,7 @@ function buildAutoRecordStep({ config, spec, test, context }) {
650818
650919
  return null;
650819
650920
  const runDir = getRunOutputDir(config, { create: false });
650820
650921
  const contextSegment = capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context"));
650821
- const recordPath = import_node_path25.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizeFilesystemName(String(test.testId ?? ""), "test")), "contexts", contextSegment, "recordings", `${contextSegment}.mp4`);
650922
+ const recordPath = import_node_path26.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizeFilesystemName(String(test.testId ?? ""), "test")), "contexts", contextSegment, "recordings", `${contextSegment}.mp4`);
650822
650923
  return {
650823
650924
  // Mobile-target contexts record the device screen through the app driver
650824
650925
  // (the internal device plan, resolved from the platform) — pinning ffmpeg
@@ -650847,7 +650948,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
650847
650948
  const action = BROWSER_STEP_KEYS.find((key) => typeof step[key] !== "undefined") || "step";
650848
650949
  const sanitizedTestId = sanitizeFilesystemName(String(test.testId ?? ""), "test");
650849
650950
  const runDir = getRunOutputDir(config);
650850
- const dir = import_node_path25.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizedTestId), "contexts", capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context")), "screenshots");
650951
+ const dir = import_node_path26.default.join(runDir, "specs", capPathSegment(sanitizeFilesystemName(String(spec.specId ?? ""), "spec")), "tests", capPathSegment(sanitizedTestId), "contexts", capPathSegment(sanitizeFilesystemName(String(context.contextId ?? ""), "context")), "screenshots");
650851
650952
  const stepIdString = sanitizeFilesystemName(String(step.stepId ?? ""), "step");
650852
650953
  const stepRef = capPathSegment(stepIdString.startsWith(`${sanitizedTestId}~`) ? stepIdString.slice(sanitizedTestId.length + 1) : stepIdString);
650853
650954
  const pad = Math.max(2, String(stepCount).length);
@@ -650856,7 +650957,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
650856
650957
  stepId: `${step.stepId}_auto`,
650857
650958
  description: "Automatic post-step screenshot",
650858
650959
  screenshot: {
650859
- path: import_node_path25.default.join(dir, fileName),
650960
+ path: import_node_path26.default.join(dir, fileName),
650860
650961
  overwrite: "true"
650861
650962
  }
650862
650963
  };
@@ -650869,7 +650970,7 @@ async function captureAutoScreenshot({ config, driver, spec, test, context, step
650869
650970
  log(config, "warning", `Auto screenshot failed after step ${step.stepId}: ${captureResult.description}`);
650870
650971
  return null;
650871
650972
  }
650872
- return import_node_path25.default.relative(runDir, screenshotStep.screenshot.path).split(import_node_path25.default.sep).join("/");
650973
+ return import_node_path26.default.relative(runDir, screenshotStep.screenshot.path).split(import_node_path26.default.sep).join("/");
650873
650974
  } catch (error) {
650874
650975
  log(config, "warning", `Auto screenshot failed after step ${step.stepId}: ${error?.message ?? error}`);
650875
650976
  return null;
@@ -651832,9 +651933,9 @@ async function startAppiumServer(appiumEntry, config, display, extraEnv, extraAr
651832
651933
  ...display ? { DISPLAY: display } : {},
651833
651934
  ...extraEnv ?? {}
651834
651935
  } : process.env;
651835
- const proc = (0, import_node_child_process14.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(port), ...extraArgs ?? []], {
651936
+ const proc = (0, import_node_child_process15.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(port), ...extraArgs ?? []], {
651836
651937
  windowsHide: true,
651837
- cwd: import_node_path25.default.join(__dirname5, "../.."),
651938
+ cwd: import_node_path26.default.join(__dirname5, "../.."),
651838
651939
  env
651839
651940
  });
651840
651941
  proc.on("error", (err) => {
@@ -651980,9 +652081,9 @@ async function getRunner(options = {}) {
651980
652081
  if (!appiumEntry) {
651981
652082
  throw new Error("appium is not installed. Run `doc-detective install runtime appium` to install it.");
651982
652083
  }
651983
- const appium = (0, import_node_child_process14.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(appiumPort)], {
652084
+ const appium = (0, import_node_child_process15.spawn)(process.execPath, [appiumEntry, "-a", "127.0.0.1", "-p", String(appiumPort)], {
651984
652085
  windowsHide: true,
651985
- cwd: import_node_path25.default.join(__dirname5, "../..")
652086
+ cwd: import_node_path26.default.join(__dirname5, "../..")
651986
652087
  });
651987
652088
  appium.on("error", (err) => {
651988
652089
  log(config, "warning", `Appium process error: ${err?.stack ?? err?.message ?? String(err)}`);