react-native-ai-devtools 1.3.11 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -8,7 +8,7 @@ import { getGuideOverview, getGuideByTopic, getAvailableTopics } from "./core/gu
8
8
  import { getLicenseStatus, getDashboardUrl, getUsageInfo } from "./core/license.js";
9
9
  import { API_BASE_URL } from "./core/config.js";
10
10
  import { getPostHogClient, identifyIfDevMode, shutdownPostHog } from "./core/posthog.js";
11
- import { getInstallationId } from "./core/telemetry.js";
11
+ import { getInstallationId, getServerVersion } from "./core/telemetry.js";
12
12
  import { isSDKInstalled, querySDKNetwork, getSDKNetworkEntry, getSDKNetworkStats, clearSDKNetwork, querySDKConsole, getSDKConsoleStats, clearSDKConsole } from "./core/sdkBridge.js";
13
13
  import { tap } from "./pro/tap.js";
14
14
  import { getActivateLicenseConfig, handleActivateLicense, getDeleteAccountConfig, handleDeleteAccount, } from "./tools/accountTools.js";
@@ -177,6 +177,8 @@ function registerToolWithTelemetry(toolName, config, handler, emptyResultDetecto
177
177
  let inputTokens;
178
178
  let outputTokens;
179
179
  let emptyResult;
180
+ let meaningful;
181
+ let changeRate;
180
182
  try {
181
183
  inputTokens = Math.ceil(JSON.stringify(args).length / 4);
182
184
  }
@@ -202,6 +204,11 @@ function registerToolWithTelemetry(toolName, config, handler, emptyResultDetecto
202
204
  // Detector failure should never affect tool execution
203
205
  }
204
206
  }
207
+ // Extract meaningfulness data if provided (tap tool verification)
208
+ if (result?._meaningful !== undefined)
209
+ meaningful = result._meaningful;
210
+ if (result?._changeRate !== undefined)
211
+ changeRate = result._changeRate;
205
212
  if (Array.isArray(result?.content)) {
206
213
  let totalTokens = 0;
207
214
  for (const item of result.content) {
@@ -220,18 +227,19 @@ function registerToolWithTelemetry(toolName, config, handler, emptyResultDetecto
220
227
  catch (error) {
221
228
  success = false;
222
229
  errorMessage = error instanceof Error ? error.message : String(error);
223
- getPostHogClient()?.captureException(error, getInstallationId(), { tool: toolName });
230
+ getPostHogClient()?.captureException(error, getInstallationId(), { tool: toolName, server_version: getServerVersion() });
224
231
  throw error;
225
232
  }
226
233
  finally {
227
234
  const duration = Date.now() - startTime;
228
- trackToolInvocation(toolName, success, duration, errorMessage, errorContext, inputTokens, outputTokens, getTargetPlatform(), emptyResult);
235
+ trackToolInvocation(toolName, success, duration, errorMessage, errorContext, inputTokens, outputTokens, getTargetPlatform(), emptyResult, meaningful, changeRate);
229
236
  getPostHogClient()?.capture({
230
237
  distinctId: getInstallationId(),
231
238
  event: toolName,
232
239
  properties: {
233
240
  success,
234
241
  duration,
242
+ server_version: getServerVersion(),
235
243
  ...(errorMessage && { error: errorMessage.substring(0, 200) }),
236
244
  ...(getTargetPlatform() && { platform: getTargetPlatform() }),
237
245
  },
@@ -1395,7 +1403,9 @@ registerToolWithTelemetry("tap", {
1395
1403
  "- tap(component=\"HamburgerIcon\") — finds by React component name\n" +
1396
1404
  "- tap(x=300, y=600) — taps at pixel coordinates from screenshot (conversion handled internally)\n" +
1397
1405
  "- tap(text=\"Menu\", strategy=\"ocr\") — forces OCR strategy only\n" +
1398
- "- tap(x=300, y=600, native=true, platform=\"android\") — taps directly via ADB/simctl without React Native connection",
1406
+ "- tap(x=300, y=600, native=true, platform=\"android\") — taps directly via ADB/simctl without React Native connection\n\n" +
1407
+ "Returns a post-tap screenshot by default (set screenshot=false to disable). " +
1408
+ "For coordinate/accessibility/OCR taps, automatically verifies the tap had a visual effect via before/after screenshot diff (set verify=false to disable).",
1399
1409
  inputSchema: {
1400
1410
  text: z
1401
1411
  .string()
@@ -1441,6 +1451,16 @@ registerToolWithTelemetry("tap", {
1441
1451
  .enum(["ios", "android"])
1442
1452
  .optional()
1443
1453
  .describe("Target platform. Required when both iOS and Android devices are connected. Auto-detected if only one platform is available."),
1454
+ screenshot: z
1455
+ .boolean()
1456
+ .optional()
1457
+ .default(true)
1458
+ .describe("Capture and return a post-tap screenshot. Enabled by default. Set to false for fastest execution (no screenshots)."),
1459
+ verify: z
1460
+ .boolean()
1461
+ .optional()
1462
+ .describe("Run before/after screenshot diff to detect if the tap had a meaningful visual effect. " +
1463
+ "Default: true for coordinate/accessibility/ocr strategies, false for fiber. Requires screenshot=true."),
1444
1464
  },
1445
1465
  }, async (args) => {
1446
1466
  const result = await tap({
@@ -1454,19 +1474,34 @@ registerToolWithTelemetry("tap", {
1454
1474
  maxTraversalDepth: args.maxTraversalDepth,
1455
1475
  native: args.native,
1456
1476
  platform: args.platform,
1477
+ screenshot: args.screenshot,
1478
+ verify: args.verify,
1457
1479
  });
1458
- const text = JSON.stringify(result, null, 2);
1480
+ const { screenshot: screenshotData, ...resultWithoutScreenshot } = result;
1481
+ const text = JSON.stringify(resultWithoutScreenshot, null, 2);
1459
1482
  // Pack strategy mode + attempted strategies into errorContext for telemetry
1460
1483
  // e.g. "s=ocr|fiber:no_pressable|ocr:no_match" or "s=auto|fiber:no_pressable|accessibility:not_found|ocr:no_match"
1461
1484
  const stratPrefix = args.strategy && args.strategy !== "auto" ? `s=${args.strategy}|` : "";
1462
1485
  const errorContext = result.attempted?.length
1463
1486
  ? stratPrefix + result.attempted.map(a => `${a.strategy}:${a.reason.slice(0, 40)}`).join("|")
1464
1487
  : undefined;
1488
+ const content = [
1489
+ { type: "text", text },
1490
+ ];
1491
+ if (screenshotData) {
1492
+ content.push({
1493
+ type: "image",
1494
+ data: screenshotData.image,
1495
+ mimeType: "image/jpeg",
1496
+ });
1497
+ }
1465
1498
  return {
1466
- content: [{ type: "text", text }],
1499
+ content,
1467
1500
  isError: !result.success,
1468
1501
  _errorMessage: result.error,
1469
1502
  _errorContext: errorContext,
1503
+ _meaningful: result.verification?.meaningful,
1504
+ _changeRate: result.verification?.changeRate,
1470
1505
  };
1471
1506
  });
1472
1507
  // Tool: Toggle Element Inspector programmatically