react-native-ai-devtools 1.4.4 → 1.4.6
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/__tests__/integration/tap-strategies.test.js +4 -4
- package/build/__tests__/unit/burst.test.d.ts +2 -0
- package/build/__tests__/unit/burst.test.d.ts.map +1 -0
- package/build/__tests__/unit/burst.test.js +50 -0
- package/build/__tests__/unit/burst.test.js.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts +2 -0
- package/build/__tests__/unit/imageBuffer.test.d.ts.map +1 -0
- package/build/__tests__/unit/imageBuffer.test.js +128 -0
- package/build/__tests__/unit/imageBuffer.test.js.map +1 -0
- package/build/__tests__/unit/tap.test.js +39 -3
- package/build/__tests__/unit/tap.test.js.map +1 -1
- package/build/core/imageBuffer.d.ts +37 -0
- package/build/core/imageBuffer.d.ts.map +1 -0
- package/build/core/imageBuffer.js +58 -0
- package/build/core/imageBuffer.js.map +1 -0
- package/build/core/index.d.ts +3 -1
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +3 -1
- package/build/core/index.js.map +1 -1
- package/build/core/state.d.ts +2 -0
- package/build/core/state.d.ts.map +1 -1
- package/build/core/state.js +3 -0
- package/build/core/state.js.map +1 -1
- package/build/index.js +120 -1
- package/build/index.js.map +1 -1
- package/build/pro/tap.d.ts +24 -0
- package/build/pro/tap.d.ts.map +1 -1
- package/build/pro/tap.js +194 -10
- package/build/pro/tap.js.map +1 -1
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -12,7 +12,7 @@ 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";
|
|
15
|
-
import { logBuffers, networkBuffers, getLogBuffer, getNetworkBuffer, getTotalLogCount, getConnectedAppByDevice, LogBuffer, NetworkBuffer, bundleErrorBuffer, connectedApps, scanMetroPorts, fetchDevices, selectMainDevice, filterBridgelessDevices, connectToDevice, getConnectedApps, executeInApp, listDebugGlobals, inspectGlobal, reloadApp,
|
|
15
|
+
import { logBuffers, networkBuffers, getLogBuffer, getNetworkBuffer, getTotalLogCount, getConnectedAppByDevice, LogBuffer, NetworkBuffer, bundleErrorBuffer, imageBuffer, connectedApps, scanMetroPorts, fetchDevices, selectMainDevice, filterBridgelessDevices, connectToDevice, getConnectedApps, executeInApp, listDebugGlobals, inspectGlobal, reloadApp,
|
|
16
16
|
// React Component Inspection
|
|
17
17
|
getComponentTree, getScreenLayout, inspectComponent, findComponents, inspectAtPoint, toggleElementInspector, isInspectorActive, getInspectorSelection, getFirstConnectedApp, getLogs, searchLogs, getLogSummary, getNetworkRequests, searchNetworkRequests, getNetworkStats, formatRequestDetails,
|
|
18
18
|
// Connection state
|
|
@@ -1464,6 +1464,15 @@ registerToolWithTelemetry("tap", {
|
|
|
1464
1464
|
.optional()
|
|
1465
1465
|
.describe("Run before/after screenshot diff to detect if the tap had a meaningful visual effect. " +
|
|
1466
1466
|
"Default: true for coordinate/accessibility/ocr strategies, false for fiber. Requires screenshot=true."),
|
|
1467
|
+
burst: z
|
|
1468
|
+
.boolean()
|
|
1469
|
+
.optional()
|
|
1470
|
+
.default(false)
|
|
1471
|
+
.describe("Enable burst screenshot capture for enhanced verification. " +
|
|
1472
|
+
"Captures 4 rapid screenshots (~150ms intervals) after the tap to detect transient visual feedback " +
|
|
1473
|
+
"(press animations, highlights, ripples) that may settle before a standard after-screenshot. " +
|
|
1474
|
+
"Results are stored in the image buffer (use get_images to inspect individual frames). " +
|
|
1475
|
+
"Default: false."),
|
|
1467
1476
|
},
|
|
1468
1477
|
}, async (args) => {
|
|
1469
1478
|
const result = await tap({
|
|
@@ -1479,6 +1488,7 @@ registerToolWithTelemetry("tap", {
|
|
|
1479
1488
|
platform: args.platform,
|
|
1480
1489
|
screenshot: args.screenshot,
|
|
1481
1490
|
verify: args.verify,
|
|
1491
|
+
burst: args.burst,
|
|
1482
1492
|
});
|
|
1483
1493
|
const { screenshot: screenshotData, ...resultWithoutScreenshot } = result;
|
|
1484
1494
|
const text = JSON.stringify(resultWithoutScreenshot, null, 2);
|
|
@@ -2132,6 +2142,68 @@ registerToolWithTelemetry("clear_network", {
|
|
|
2132
2142
|
]
|
|
2133
2143
|
};
|
|
2134
2144
|
});
|
|
2145
|
+
// Tool: Get images from shared image buffer
|
|
2146
|
+
registerToolWithTelemetry("get_images", {
|
|
2147
|
+
description: "Access the shared image buffer containing screenshots from all tools (ios_screenshot, android_screenshot, ocr_screenshot, tap verification). Returns metadata only by default — use id or groupId+frameIndex to retrieve actual image data. Tap burst verification stores frame groups here when burst=true is used.",
|
|
2148
|
+
inputSchema: {
|
|
2149
|
+
list: z.boolean().optional().describe("List all entries and groups (metadata only, no image data)"),
|
|
2150
|
+
id: z.string().optional().describe("Retrieve a specific image by ID (returns image data)"),
|
|
2151
|
+
groupId: z.string().optional().describe("List frames in a group (metadata only), or combine with frameIndex to retrieve a specific frame"),
|
|
2152
|
+
frameIndex: z.coerce.number().optional().describe("Retrieve a specific frame from a group (requires groupId)"),
|
|
2153
|
+
last: z.coerce.number().optional().describe("Return the N most recent entries (metadata only)"),
|
|
2154
|
+
source: z.string().optional().describe("Filter entries by source"),
|
|
2155
|
+
clear: z.boolean().optional().describe("Clear the buffer")
|
|
2156
|
+
}
|
|
2157
|
+
}, async ({ id, groupId, frameIndex, last, source, clear }) => {
|
|
2158
|
+
if (clear) {
|
|
2159
|
+
const count = imageBuffer.clear();
|
|
2160
|
+
return {
|
|
2161
|
+
content: [{ type: "text", text: `Cleared ${count} images from buffer.` }]
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
if (id) {
|
|
2165
|
+
const entry = imageBuffer.getById(id);
|
|
2166
|
+
if (!entry) {
|
|
2167
|
+
return {
|
|
2168
|
+
content: [{ type: "text", text: `No image found with id "${id}".` }],
|
|
2169
|
+
isError: true
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
const { image, ...meta } = entry;
|
|
2173
|
+
return {
|
|
2174
|
+
content: [
|
|
2175
|
+
{ type: "text", text: JSON.stringify(meta, null, 2) },
|
|
2176
|
+
{ type: "image", data: image.toString("base64"), mimeType: "image/png" }
|
|
2177
|
+
]
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
if (groupId !== undefined && frameIndex !== undefined) {
|
|
2181
|
+
const entry = imageBuffer.getByGroupFrame(groupId, frameIndex);
|
|
2182
|
+
if (!entry) {
|
|
2183
|
+
return {
|
|
2184
|
+
content: [{ type: "text", text: `No frame ${frameIndex} found in group "${groupId}".` }],
|
|
2185
|
+
isError: true
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
const { image, ...meta } = entry;
|
|
2189
|
+
return {
|
|
2190
|
+
content: [
|
|
2191
|
+
{ type: "text", text: JSON.stringify(meta, null, 2) },
|
|
2192
|
+
{ type: "image", data: image.toString("base64"), mimeType: "image/png" }
|
|
2193
|
+
]
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
const entries = imageBuffer.listEntries({ source, groupId, last });
|
|
2197
|
+
const groups = imageBuffer.listGroups();
|
|
2198
|
+
return {
|
|
2199
|
+
content: [
|
|
2200
|
+
{
|
|
2201
|
+
type: "text",
|
|
2202
|
+
text: JSON.stringify({ entries, groups, total: imageBuffer.size }, null, 2)
|
|
2203
|
+
}
|
|
2204
|
+
]
|
|
2205
|
+
};
|
|
2206
|
+
});
|
|
2135
2207
|
// Tool: Reload the app
|
|
2136
2208
|
registerToolWithTelemetry("reload_app", {
|
|
2137
2209
|
description: "Reload the React Native app (triggers JavaScript bundle reload like pressing 'r' in Metro). Will auto-connect to Metro if no connection exists. Note: After reload, the app may take a few seconds to fully restart and become responsive — wait before running other tools. IMPORTANT: React Native has Fast Refresh enabled by default - code changes are automatically applied without needing reload. Only use when: (1) logs/behavior don't reflect code changes after a few seconds, (2) app is in broken/error state, or (3) need to reset app state completely (navigation stack, context, etc.).",
|
|
@@ -2417,6 +2489,18 @@ registerToolWithTelemetry("android_screenshot", {
|
|
|
2417
2489
|
infoText += `\n • tap(x=<px>, y=<px>) — tap at coordinates from this screenshot`;
|
|
2418
2490
|
infoText += `\n • android_describe_all — get full UI tree with exact tap coordinates`;
|
|
2419
2491
|
infoText += `\n • android_find_element(text="...") — find element coordinates without tapping`;
|
|
2492
|
+
imageBuffer.add({
|
|
2493
|
+
id: `android-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
2494
|
+
image: result.data,
|
|
2495
|
+
timestamp: Date.now(),
|
|
2496
|
+
source: "android_screenshot",
|
|
2497
|
+
metadata: {
|
|
2498
|
+
width: result.originalWidth || 0,
|
|
2499
|
+
height: result.originalHeight || 0,
|
|
2500
|
+
scaleFactor: result.scaleFactor || 1,
|
|
2501
|
+
platform: "android",
|
|
2502
|
+
},
|
|
2503
|
+
});
|
|
2420
2504
|
return {
|
|
2421
2505
|
content: [
|
|
2422
2506
|
{
|
|
@@ -2947,6 +3031,18 @@ registerToolWithTelemetry("ios_screenshot", {
|
|
|
2947
3031
|
infoText += `\n • tap(x=<px>, y=<px>) — tap at coordinates from this screenshot`;
|
|
2948
3032
|
infoText += `\n • ios_describe_all — get full UI tree with exact tap coordinates`;
|
|
2949
3033
|
infoText += `\n • ios_find_element(label="...") — find element coordinates without tapping`;
|
|
3034
|
+
imageBuffer.add({
|
|
3035
|
+
id: `ios-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
3036
|
+
image: result.data,
|
|
3037
|
+
timestamp: Date.now(),
|
|
3038
|
+
source: "ios_screenshot",
|
|
3039
|
+
metadata: {
|
|
3040
|
+
width: result.originalWidth || 0,
|
|
3041
|
+
height: result.originalHeight || 0,
|
|
3042
|
+
scaleFactor: result.scaleFactor || 1,
|
|
3043
|
+
platform: "ios",
|
|
3044
|
+
},
|
|
3045
|
+
});
|
|
2950
3046
|
return {
|
|
2951
3047
|
content: [
|
|
2952
3048
|
{
|
|
@@ -3033,6 +3129,29 @@ registerToolWithTelemetry("ocr_screenshot", {
|
|
|
3033
3129
|
elements,
|
|
3034
3130
|
note: "tapX/tapY are ready to use with tap commands (already converted for platform)"
|
|
3035
3131
|
};
|
|
3132
|
+
// Capture screenshot and store in image buffer
|
|
3133
|
+
try {
|
|
3134
|
+
const screenshotResult = platform === "android"
|
|
3135
|
+
? await androidScreenshot(undefined, deviceId)
|
|
3136
|
+
: await iosScreenshot(undefined, deviceId);
|
|
3137
|
+
if (screenshotResult.success && screenshotResult.data) {
|
|
3138
|
+
imageBuffer.add({
|
|
3139
|
+
id: `ocr-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
3140
|
+
image: screenshotResult.data,
|
|
3141
|
+
timestamp: Date.now(),
|
|
3142
|
+
source: "ocr_screenshot",
|
|
3143
|
+
metadata: {
|
|
3144
|
+
width: screenshotResult.originalWidth || 0,
|
|
3145
|
+
height: screenshotResult.originalHeight || 0,
|
|
3146
|
+
scaleFactor: screenshotResult.scaleFactor || 1,
|
|
3147
|
+
platform,
|
|
3148
|
+
},
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
catch {
|
|
3153
|
+
// Non-fatal: image buffer write failure should not break OCR response
|
|
3154
|
+
}
|
|
3036
3155
|
return {
|
|
3037
3156
|
content: [
|
|
3038
3157
|
{
|