react-native-ai-devtools 1.4.31 → 1.4.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1603,7 +1603,7 @@ registerToolWithTelemetry("tap", {
1603
1603
  "- tap(text=\"Submit\") — finds and taps element with matching text\n" +
1604
1604
  "- tap(testID=\"login-btn\") — finds by testID\n" +
1605
1605
  "- tap(component=\"HamburgerIcon\") — finds by React component name\n" +
1606
- "- tap(x=300, y=600) — taps at pixel coordinates (LAST RESORT — only use if text/testID/component strategies all fail)\n" +
1606
+ "- tap(x=300, y=600) — taps at pixel coordinates; use coordinates from the pressable elements list returned by ios_screenshot/android_screenshot for reliable icon and ambiguous-element taps\n" +
1607
1607
  "- tap(text=\"Menu\", strategy=\"ocr\") — forces OCR strategy only\n" +
1608
1608
  "- tap(x=300, y=600, native=true, platform=\"android\") — taps directly via ADB/simctl without React Native connection\n\n" +
1609
1609
  "Returns a post-tap screenshot by default (set screenshot=false to disable). " +
@@ -2781,7 +2781,7 @@ registerToolWithTelemetry("list_android_devices", {
2781
2781
  });
2782
2782
  // Tool: Android screenshot
2783
2783
  registerToolWithTelemetry("android_screenshot", {
2784
- description: "Take a screenshot from an Android device/emulator. Returns the image and a screen layout overlay showing visible React components with names, text content, hierarchy, and tap-ready pixel coordinates. Use component names for inspect_component/find_components. Use tap(text=...) for interaction — only fall back to tap(x,y) coordinates from the layout if all tap strategies fail.",
2784
+ description: "Take a screenshot from an Android device/emulator. Returns the image plus two lists: (1) pressable elements — the tappable components on screen with ready-to-use pixel tap coordinates, testIDs, and labels; (2) screen layout — all visible React components for context. Prefer tap(text=\"...\") when text is exact and unique; otherwise use tap(x, y) with coordinates from the pressables list — this is the most reliable way to tap icons or visually-identified elements. Use component names from the layout for inspect_component/find_components.",
2785
2785
  inputSchema: {
2786
2786
  outputPath: z
2787
2787
  .string()
@@ -2848,6 +2848,26 @@ registerToolWithTelemetry("android_screenshot", {
2848
2848
  catch {
2849
2849
  // Non-fatal: screenshot works without layout enrichment
2850
2850
  }
2851
+ // Enrich with pressable elements (filtered list of tappable components, converted to screenshot pixel coords)
2852
+ let pressablesText = null;
2853
+ try {
2854
+ const pressables = await getPressableElements({});
2855
+ if (pressables.success && pressables.parsedElements && pressables.parsedElements.length > 0) {
2856
+ const screenshotScale = result.scaleFactor || 1;
2857
+ pressablesText = pressables.parsedElements.map((el) => {
2858
+ const px = Math.round((el.center.x * androidPixelRatio) / screenshotScale);
2859
+ const py = Math.round((el.center.y * androidPixelRatio) / screenshotScale);
2860
+ const label = el.accessibilityLabel || el.text || el.testID || el.component;
2861
+ const idPart = el.testID ? ` testID="${el.testID}"` : "";
2862
+ const kindPart = el.isInput ? " [input]" : "";
2863
+ const wrapPart = el.isWrapper ? " [wrapper — skip]" : "";
2864
+ return ` (${px}, ${py}) ${el.component}: "${label}"${idPart}${kindPart}${wrapPart}`;
2865
+ }).join("\n");
2866
+ }
2867
+ }
2868
+ catch {
2869
+ // Non-fatal: screenshot works without pressables enrichment
2870
+ }
2851
2871
  infoText += `\n📱 Android uses PIXELS for all coordinates`;
2852
2872
  if (result.scaleFactor && result.scaleFactor > 1) {
2853
2873
  infoText += `\n🖼️ Image was scaled down to fit API limits (scale: ${result.scaleFactor.toFixed(3)})`;
@@ -2858,14 +2878,20 @@ registerToolWithTelemetry("android_screenshot", {
2858
2878
  }
2859
2879
  infoText += `\n⚠️ Status bar: ${statusBarPixels}px (${statusBarDp}dp) from top - app content starts below this`;
2860
2880
  infoText += `\n📊 Display density: ${densityDpi}dpi`;
2881
+ if (pressablesText) {
2882
+ infoText += `\n\n🎯 Pressable elements (ready-to-tap, coordinates in screenshot pixels):`;
2883
+ infoText += `\n${pressablesText}`;
2884
+ }
2861
2885
  if (layoutText) {
2862
- infoText += `\n\n📋 Screen Layout (components with tap coordinates in pixels):`;
2886
+ infoText += `\n\n📋 Screen Layout (all components, tap coordinates in pixels):`;
2863
2887
  infoText += `\n${layoutText}`;
2888
+ }
2889
+ if (pressablesText || layoutText) {
2864
2890
  infoText += `\n\n💡 Next steps:`;
2865
- infoText += `\n • tap(text="Button Label") — tap element by visible text (preferred)`;
2866
- infoText += `\n • tap(testID="id") or tap(component="Name") — tap by testID or component name`;
2867
- infoText += `\n • tap(x=<px>, y=<px>) — use tap coordinates from layout above ONLY if text/testID/component tap fails`;
2868
- infoText += `\n • inspect_component("ComponentName") — inspect a component from the layout above`;
2891
+ infoText += `\n • tap(text="Button Label") — when text is exact and unique`;
2892
+ infoText += `\n • tap(testID="id") or tap(component="Name") — when you know the identifier`;
2893
+ infoText += `\n • tap(x=<px>, y=<px>) — use coordinates from the pressable elements list above (reliable for icons and ambiguous elements)`;
2894
+ infoText += `\n • inspect_component("ComponentName") — inspect a component from the layout`;
2869
2895
  }
2870
2896
  else {
2871
2897
  infoText += `\n\n💡 Next steps:`;
@@ -3343,7 +3369,7 @@ registerToolWithTelemetry("list_ios_simulators", {
3343
3369
  });
3344
3370
  // Tool: iOS screenshot
3345
3371
  registerToolWithTelemetry("ios_screenshot", {
3346
- description: "Take a screenshot from an iOS simulator. Returns the image and a screen layout overlay showing visible React components with names, text content, hierarchy, and tap-ready pixel coordinates. Use component names for inspect_component/find_components. Use tap(text=...) for interaction — only fall back to tap(x,y) coordinates from the layout if all tap strategies fail.",
3372
+ description: "Take a screenshot from an iOS simulator. Returns the image plus two lists: (1) pressable elements — the tappable components on screen with ready-to-use pixel tap coordinates, testIDs, and labels; (2) screen layout — all visible React components for context. Prefer tap(text=\"...\") when text is exact and unique; otherwise use tap(x, y) with coordinates from the pressables list — this is the most reliable way to tap icons or visually-identified elements. Use component names from the layout for inspect_component/find_components.",
3347
3373
  inputSchema: {
3348
3374
  outputPath: z
3349
3375
  .string()
@@ -3435,6 +3461,26 @@ registerToolWithTelemetry("ios_screenshot", {
3435
3461
  catch {
3436
3462
  // Non-fatal: screenshot works without layout enrichment
3437
3463
  }
3464
+ // Enrich with pressable elements (filtered list of tappable components, converted to screenshot pixel coords)
3465
+ let pressablesText = null;
3466
+ try {
3467
+ const pressables = await getPressableElements({});
3468
+ if (pressables.success && pressables.parsedElements && pressables.parsedElements.length > 0) {
3469
+ const screenshotScale = result.scaleFactor || 1;
3470
+ pressablesText = pressables.parsedElements.map((el) => {
3471
+ const px = Math.round((el.center.x * scaleFactor) / screenshotScale);
3472
+ const py = Math.round((el.center.y * scaleFactor) / screenshotScale);
3473
+ const label = el.accessibilityLabel || el.text || el.testID || el.component;
3474
+ const idPart = el.testID ? ` testID="${el.testID}"` : "";
3475
+ const kindPart = el.isInput ? " [input]" : "";
3476
+ const wrapPart = el.isWrapper ? " [wrapper — skip]" : "";
3477
+ return ` (${px}, ${py}) ${el.component}: "${label}"${idPart}${kindPart}${wrapPart}`;
3478
+ }).join("\n");
3479
+ }
3480
+ }
3481
+ catch {
3482
+ // Non-fatal: screenshot works without pressables enrichment
3483
+ }
3438
3484
  let infoText = `Screenshot captured (${pixelWidth}x${pixelHeight} pixels)`;
3439
3485
  infoText += `\n📱 iOS screen: ${pointWidth}x${pointHeight} points (${scaleFactor}x scale)`;
3440
3486
  infoText += `\n📐 tap() handles pixel-to-point conversion automatically — pass pixel coords from this image directly`;
@@ -3442,14 +3488,20 @@ registerToolWithTelemetry("ios_screenshot", {
3442
3488
  if (result.scaleFactor && result.scaleFactor > 1) {
3443
3489
  infoText += `\n🖼️ Image was scaled down to fit API limits (scale: ${result.scaleFactor.toFixed(3)})`;
3444
3490
  }
3491
+ if (pressablesText) {
3492
+ infoText += `\n\n🎯 Pressable elements (ready-to-tap, coordinates in screenshot pixels):`;
3493
+ infoText += `\n${pressablesText}`;
3494
+ }
3445
3495
  if (layoutText) {
3446
- infoText += `\n\n📋 Screen Layout (components with tap coordinates in pixels):`;
3496
+ infoText += `\n\n📋 Screen Layout (all components, tap coordinates in pixels):`;
3447
3497
  infoText += `\n${layoutText}`;
3498
+ }
3499
+ if (pressablesText || layoutText) {
3448
3500
  infoText += `\n\n💡 Next steps:`;
3449
- infoText += `\n • tap(text="Button Label") — tap element by visible text (preferred)`;
3450
- infoText += `\n • tap(testID="id") or tap(component="Name") — tap by testID or component name`;
3451
- infoText += `\n • tap(x=<px>, y=<px>) — use tap coordinates from layout above ONLY if text/testID/component tap fails`;
3452
- infoText += `\n • inspect_component("ComponentName") — inspect a component from the layout above`;
3501
+ infoText += `\n • tap(text="Button Label") — when text is exact and unique`;
3502
+ infoText += `\n • tap(testID="id") or tap(component="Name") — when you know the identifier`;
3503
+ infoText += `\n • tap(x=<px>, y=<px>) — use coordinates from the pressable elements list above (reliable for icons and ambiguous elements)`;
3504
+ infoText += `\n • inspect_component("ComponentName") — inspect a component from the layout`;
3453
3505
  }
3454
3506
  else {
3455
3507
  infoText += `\n\n💡 Next steps:`;