@yoqa/runner 0.3.25 → 0.3.27

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 +51 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16816,7 +16816,7 @@ function getCatalogDb() {
16816
16816
  // package.json
16817
16817
  var package_default = {
16818
16818
  name: "@yoqa/runner",
16819
- version: "0.3.25",
16819
+ version: "0.3.27",
16820
16820
  description: "Yoqa local runner \u2014 Appium + catalog HTTP API (Bun). Start with yoqa serve or the yoqa-runner bin.",
16821
16821
  license: "UNLICENSED",
16822
16822
  type: "module",
@@ -17591,6 +17591,41 @@ async function listDevices(platform, options = {}) {
17591
17591
  return listAndroidDevices(options);
17592
17592
  }
17593
17593
 
17594
+ // src/domains/devices/keyboard.ts
17595
+ function isUnsupportedCommandError(error) {
17596
+ const message = error instanceof Error ? error.message : String(error);
17597
+ return /unknown command|unknown method|not (yet )?(been )?implemented|not (yet )?supported|does not support/i.test(message);
17598
+ }
17599
+ var W3C_RETURN_KEY = "\uE007";
17600
+ function w3cKeyActions(text2) {
17601
+ const actions = [];
17602
+ for (const ch of text2) {
17603
+ const value = ch === `
17604
+ ` || ch === "\r" ? W3C_RETURN_KEY : ch;
17605
+ actions.push({ type: "keyDown", value }, { type: "keyUp", value });
17606
+ }
17607
+ return [{ type: "key", id: "keyboard", actions }];
17608
+ }
17609
+ async function w3cType(browser, text2) {
17610
+ await browser.performActions(w3cKeyActions(text2));
17611
+ try {
17612
+ await browser.releaseActions();
17613
+ } catch {}
17614
+ }
17615
+ async function typeText(browser, text2) {
17616
+ if (text2.length === 0)
17617
+ return "noop";
17618
+ try {
17619
+ await browser.execute("mobile: type", { text: text2 });
17620
+ return "mobile";
17621
+ } catch (error) {
17622
+ if (!isUnsupportedCommandError(error))
17623
+ throw error;
17624
+ }
17625
+ await w3cType(browser, text2);
17626
+ return "w3c";
17627
+ }
17628
+
17594
17629
  // src/domains/devices/session.ts
17595
17630
  var YOQA_ROOT4 = join7(homedir6(), ".yoqa");
17596
17631
  var DEFAULT_MJPEG_PORT = Number(process.env.YOQA_MJPEG_PORT ?? "9100");
@@ -18087,7 +18122,7 @@ async function createDeviceSession(options) {
18087
18122
  const type = async (text2) => {
18088
18123
  await gate.withLock(async () => {
18089
18124
  await guard(async () => {
18090
- await browser.keys(text2.split(""));
18125
+ await typeText(browser, text2);
18091
18126
  });
18092
18127
  });
18093
18128
  };
@@ -96466,7 +96501,7 @@ function prefersScreenshotTap(decision) {
96466
96501
  return false;
96467
96502
  return decision.x != null && decision.y != null;
96468
96503
  }
96469
- var SYSTEM_PROMPT = `You are a mobile QA agent controlling an app via screenshots.
96504
+ var SYSTEM_PROMPT = `You are a mobile QA agent controlling an app using BOTH visual screenshots and screen snapshots (accessibility tree).
96470
96505
  A screenshot of the current device screen is ALWAYS attached to the user message as an image. You can see it. Never claim that no screenshot was provided, missing, blank, or unavailable.
96471
96506
 
96472
96507
  Your entire reply MUST be a single strict JSON object (double quotes only \u2014 never single quotes) and nothing else \u2014 no markdown fences, no commentary before or after.
@@ -96501,12 +96536,21 @@ Valid shapes:
96501
96536
  Coordinates use a 0\u20131000 normalized grid (0,0 top-left of the attached screenshot). The user message also includes a screen snapshot (cleaned accessibility tree) with the same grid \u2014 x,y is each element's TOP-LEFT, not centre. Centre = x + width/2, y + height/2.
96502
96537
 
96503
96538
  Use BOTH the screenshot and the screen snapshot:
96504
- - Prefer snapshot "id=\u2026" when present (same as yoqa action tap --id).
96539
+ - Visual context (screenshot): Observe visual layout, colors, icons, canvas controls, modal overlays, and soft keyboard visibility.
96540
+ - Structural context (screen snapshot): Inspect accessibility ids ("id=..."), element boundaries, and text labels.
96541
+ - Decide whether to target by "id" or "x,y":
96542
+ * Use "id" when the snapshot provides a clean, unique, and unambiguous identifier for the element.
96543
+ * Use "x,y" coordinates (centre of the control on the screenshot grid) when controls lack IDs, are custom-drawn icons/canvas, or when coordinates are more direct and reliable than broad container IDs.
96505
96544
  - System permission / notification dialogs: {"type":"tap","label":"Allow"} or {"type":"alert","alertAction":"accept"}. Never guess coordinates for these.
96506
- - For other in-app controls, tap screenshot x,y of the visible control if there is no id.
96507
- - If the snapshot is empty or the control is only drawn (no label/id), use the screenshot.
96508
96545
  - If a previous action failed (see Last action error), pick a different target from the snapshot + screenshot \u2014 do not repeat the same id/label/point.
96509
96546
 
96547
+ Textfield input and keyboard handling:
96548
+ - Typing into a textfield brings up the virtual soft keyboard on the bottom of the screen (typically covering y ~ 550\u20131000), which may obscure buttons (like Submit, Login, Next) or lower inputs.
96549
+ - When typing inside a textfield or when the keyboard is open:
96550
+ 1. Dismiss keyboard by tapping away: Emit a tap on an empty, neutral background area outside textfields and above the keyboard (e.g. tap neutral header space or empty background) to dismiss the keyboard.
96551
+ 2. Nextline / Return on keyboard: Tap the Return / Done / Next / Search key on the virtual keyboard itself (using its x,y coordinates or label/id if present), or append "\\n" to your input text.
96552
+ 3. Dismiss then use app buttons: If an app button you need is obscured or covered by the soft keyboard, dismiss the keyboard first (by tapping away or pressing Return) so the button is revealed, then tap the app button on the subsequent step.
96553
+
96510
96554
  Swipe direction is the FINGER movement (same as Inspector):
96511
96555
  - "down" (finger down, y 200\u2192800): scroll UP \u2014 reveal content above
96512
96556
  - "up" (finger up, y 800\u2192200): scroll DOWN \u2014 reveal content below / to the bottom
@@ -96650,7 +96694,7 @@ ${formatRecentActions(input.recentActions ?? [])}`,
96650
96694
  `Last action error: ${input.lastError || "(none)"}`,
96651
96695
  "Screen snapshot (cleaned accessibility tree, 0\u20131000 grid, x,y is top-left):",
96652
96696
  input.screenSnapshot || "(unavailable)",
96653
- "Look at the attached screenshot image AND the screen snapshot and decide the next action. A screenshot is attached.",
96697
+ "Look at the attached screenshot image AND the screen snapshot and decide the next action. Decide whether to use x,y coordinates or an id based on both sources. A screenshot is attached.",
96654
96698
  'Reply with ONLY the JSON action object, including non-empty "reason" and "thoughts".'
96655
96699
  ].join(`
96656
96700
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoqa/runner",
3
- "version": "0.3.25",
3
+ "version": "0.3.27",
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",