@yoqa/runner 0.3.16 → 0.3.17

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 (2) hide show
  1. package/dist/index.js +98 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16801,7 +16801,7 @@ function getCatalogDb() {
16801
16801
  // package.json
16802
16802
  var package_default = {
16803
16803
  name: "@yoqa/runner",
16804
- version: "0.3.16",
16804
+ version: "0.3.17",
16805
16805
  description: "Yoqa local runner \u2014 Appium + catalog HTTP API (Bun). Start with yoqa serve or the yoqa-runner bin.",
16806
16806
  license: "UNLICENSED",
16807
16807
  type: "module",
@@ -17020,8 +17020,11 @@ function mergeCapabilities(appCaps, caseCaps) {
17020
17020
  function looksLikePhysicalIosUdid(udid) {
17021
17021
  return /^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{16}$/.test(udid.trim());
17022
17022
  }
17023
+ var PHYSICAL_IOS_SESSION_TIMEOUT_MS = 60000;
17024
+ var SIMULATOR_WDA_SESSION_TIMEOUT_MS = 600000;
17025
+ var SIMULATOR_WDA_DERIVED_DATA = join6(YOQA_ROOT4, "wda-sim");
17023
17026
  function iosSessionCreateTimeoutMs(deviceId) {
17024
- return looksLikePhysicalIosUdid(deviceId) ? 60000 : 240000;
17027
+ return looksLikePhysicalIosUdid(deviceId) ? PHYSICAL_IOS_SESSION_TIMEOUT_MS : SIMULATOR_WDA_SESSION_TIMEOUT_MS;
17025
17028
  }
17026
17029
  async function buildW3cCapabilities(options, mjpegPort) {
17027
17030
  const merged = mergeCapabilities(options.appCaps, options.caseCaps);
@@ -17071,6 +17074,10 @@ async function buildW3cCapabilities(options, mjpegPort) {
17071
17074
  if (caps["appium:waitForIdleTimeout"] === undefined) {
17072
17075
  caps["appium:waitForIdleTimeout"] = 0;
17073
17076
  }
17077
+ if (!physical && caps["appium:derivedDataPath"] === undefined) {
17078
+ await mkdir3(SIMULATOR_WDA_DERIVED_DATA, { recursive: true });
17079
+ caps["appium:derivedDataPath"] = SIMULATOR_WDA_DERIVED_DATA;
17080
+ }
17074
17081
  }
17075
17082
  return caps;
17076
17083
  }
@@ -23551,13 +23558,24 @@ var caseFlowStepSchema = exports_external.object({
23551
23558
  flowId: exports_external.string().min(1).nullable().optional()
23552
23559
  });
23553
23560
  var caseRunStatusSchema = exports_external.union([exports_external.literal("passed"), exports_external.literal("errored")]);
23554
- var caseScriptActionSchema = exports_external.discriminatedUnion("type", [
23555
- exports_external.object({
23556
- type: exports_external.literal("tap"),
23557
- x: exports_external.number().min(0).max(1000),
23558
- y: exports_external.number().min(0).max(1000),
23559
- reason: exports_external.string().optional()
23560
- }),
23561
+ var caseScriptTapSchema = exports_external.object({
23562
+ type: exports_external.literal("tap"),
23563
+ x: exports_external.number().min(0).max(1000).optional(),
23564
+ y: exports_external.number().min(0).max(1000).optional(),
23565
+ label: exports_external.string().min(1).optional(),
23566
+ id: exports_external.string().min(1).optional(),
23567
+ reason: exports_external.string().optional()
23568
+ }).superRefine((value, ctx) => {
23569
+ const hasCoords = value.x != null && value.y != null;
23570
+ if (!hasCoords && !value.label && !value.id) {
23571
+ ctx.addIssue({
23572
+ code: exports_external.ZodIssueCode.custom,
23573
+ message: "tap requires x/y or label or id"
23574
+ });
23575
+ }
23576
+ });
23577
+ var caseScriptActionSchema = exports_external.union([
23578
+ caseScriptTapSchema,
23561
23579
  exports_external.object({
23562
23580
  type: exports_external.literal("type"),
23563
23581
  text: exports_external.string(),
@@ -23567,6 +23585,13 @@ var caseScriptActionSchema = exports_external.discriminatedUnion("type", [
23567
23585
  type: exports_external.literal("wait"),
23568
23586
  ms: exports_external.number().min(0).max(1e4),
23569
23587
  reason: exports_external.string().optional()
23588
+ }),
23589
+ exports_external.object({
23590
+ type: exports_external.literal("assert"),
23591
+ assertion: exports_external.union([exports_external.literal("visible"), exports_external.literal("not-visible")]).default("visible"),
23592
+ text: exports_external.string().min(1),
23593
+ timeoutMs: exports_external.number().min(0).max(120000).optional(),
23594
+ reason: exports_external.string().optional()
23570
23595
  })
23571
23596
  ]);
23572
23597
  var caseScriptSchema = exports_external.object({
@@ -23975,6 +24000,9 @@ var createBuildRequestSchema = exports_external.object({
23975
24000
  var listBuildsResponseSchema = exports_external.object({
23976
24001
  builds: exports_external.array(buildSchema)
23977
24002
  });
24003
+
24004
+ // ../../packages/runner-client/src/wait-for-run.ts
24005
+ var DEFAULT_WAIT_FOR_RUN_TIMEOUT_MS = 30 * 60 * 1000;
23978
24006
  // ../../packages/runner-client/src/shell-script.ts
23979
24007
  var DEFAULT_SHELL_SCRIPT_HEADER = [
23980
24008
  "#!/usr/bin/env bash",
@@ -23984,6 +24012,16 @@ var DEFAULT_SHELL_SCRIPT_HEADER = [
23984
24012
  ""
23985
24013
  ].join(`
23986
24014
  `);
24015
+ function screenHasText(elements, text2) {
24016
+ const needle = text2.trim().toLowerCase();
24017
+ if (!needle)
24018
+ return false;
24019
+ return (elements ?? []).some((el) => {
24020
+ const label = el.label?.toLowerCase() ?? "";
24021
+ const type = el.type?.toLowerCase() ?? "";
24022
+ return label.includes(needle) || type.includes(needle);
24023
+ });
24024
+ }
23987
24025
  function findElementByLabel(elements, label) {
23988
24026
  const needle = label.trim().toLowerCase();
23989
24027
  if (!needle)
@@ -97429,6 +97467,10 @@ var defaultClock = {
97429
97467
  };
97430
97468
  async function executeScriptCase(deps) {
97431
97469
  const perform = deps.performAction ?? performAction;
97470
+ const readScreen = deps.readScreen ?? (async (session) => {
97471
+ const screen = await getScreen(session, { full: false });
97472
+ return { elements: screen.elements };
97473
+ });
97432
97474
  const clock = deps.clock ?? defaultClock;
97433
97475
  const settleMs = deps.settleMs ?? POST_ACTION_SETTLE_MS;
97434
97476
  let stepIdx = 0;
@@ -97446,7 +97488,16 @@ async function executeScriptCase(deps) {
97446
97488
  return "cancelled";
97447
97489
  }
97448
97490
  if (action.type === "tap") {
97449
- await perform(deps.session, { kind: "tap", x: action.x, y: action.y });
97491
+ const tapBody = { kind: "tap" };
97492
+ if (action.label)
97493
+ tapBody.label = action.label;
97494
+ if (action.id)
97495
+ tapBody.id = action.id;
97496
+ if (action.x != null)
97497
+ tapBody.x = action.x;
97498
+ if (action.y != null)
97499
+ tapBody.y = action.y;
97500
+ await perform(deps.session, tapBody);
97450
97501
  await clock.sleep(settleMs);
97451
97502
  await deps.appendStep({
97452
97503
  idx: stepIdx,
@@ -97454,13 +97505,15 @@ async function executeScriptCase(deps) {
97454
97505
  type: "tap",
97455
97506
  x: action.x,
97456
97507
  y: action.y,
97508
+ label: action.label,
97509
+ id: action.id,
97457
97510
  reason: action.reason ?? "Replayed saved script tap",
97458
97511
  thoughts: "Replaying the saved script without calling the AI agent."
97459
97512
  },
97460
97513
  screenshotUri: shot.path,
97461
97514
  ok: true,
97462
97515
  latencyMs,
97463
- detail: action.reason ?? null
97516
+ detail: action.reason ?? action.label ?? action.id ?? null
97464
97517
  });
97465
97518
  } else if (action.type === "type") {
97466
97519
  await perform(deps.session, { kind: "input", text: action.text });
@@ -97478,6 +97531,40 @@ async function executeScriptCase(deps) {
97478
97531
  latencyMs,
97479
97532
  detail: action.reason ?? null
97480
97533
  });
97534
+ } else if (action.type === "assert") {
97535
+ const timeoutMs = action.timeoutMs ?? 5000;
97536
+ const assertion = action.assertion;
97537
+ const deadline = clock.now() + timeoutMs;
97538
+ for (;; ) {
97539
+ if (deps.isAborted()) {
97540
+ return "cancelled";
97541
+ }
97542
+ const screen = await readScreen(deps.session);
97543
+ const found = screenHasText(screen.elements, action.text);
97544
+ if (assertion === "visible" && found)
97545
+ break;
97546
+ if (assertion === "not-visible" && !found)
97547
+ break;
97548
+ if (clock.now() >= deadline) {
97549
+ throw new Error(assertion === "visible" ? `Expected visible text not found within ${Math.round(timeoutMs / 1000)}s: ${action.text}` : `Unexpected text still visible after ${Math.round(timeoutMs / 1000)}s: ${action.text}`);
97550
+ }
97551
+ await clock.sleep(400);
97552
+ }
97553
+ await deps.appendStep({
97554
+ idx: stepIdx,
97555
+ action: {
97556
+ type: "assert",
97557
+ assertion,
97558
+ text: action.text,
97559
+ timeoutMs,
97560
+ reason: action.reason ?? `Assert ${assertion}: ${action.text}`,
97561
+ thoughts: "Replaying the saved script without calling the AI agent."
97562
+ },
97563
+ screenshotUri: shot.path,
97564
+ ok: true,
97565
+ latencyMs,
97566
+ detail: action.reason ?? `${assertion}: ${action.text}`
97567
+ });
97481
97568
  } else {
97482
97569
  const waitMs = Math.min(3000, Math.max(500, action.ms));
97483
97570
  await clock.sleep(waitMs);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoqa/runner",
3
- "version": "0.3.16",
3
+ "version": "0.3.17",
4
4
  "description": "Yoqa local runner — Appium + catalog HTTP API (Bun). Start with yoqa serve or the yoqa-runner bin.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",