react-native-ai-debugger 1.6.8 → 1.6.10
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/README.md +13 -13
- package/build/core/appDetection.js +2 -2
- package/build/core/appDetection.js.map +1 -1
- package/build/core/bundle.js +6 -6
- package/build/core/bundle.js.map +1 -1
- package/build/core/connection.d.ts.map +1 -1
- package/build/core/connection.js +125 -30
- package/build/core/connection.js.map +1 -1
- package/build/core/executor.d.ts.map +1 -1
- package/build/core/executor.js +123 -24
- package/build/core/executor.js.map +1 -1
- package/build/core/fingerprint.js +1 -1
- package/build/core/fingerprint.js.map +1 -1
- package/build/core/guides.d.ts.map +1 -1
- package/build/core/guides.js +10 -3
- package/build/core/guides.js.map +1 -1
- package/build/core/logbox.js +1 -1
- package/build/core/logbox.js.map +1 -1
- package/build/core/networkInterceptor.d.ts.map +1 -1
- package/build/core/networkInterceptor.js +4 -0
- package/build/core/networkInterceptor.js.map +1 -1
- package/build/core/telemetry.js +1 -1
- package/build/core/telemetry.js.map +1 -1
- package/build/core/types.d.ts +2 -0
- package/build/core/types.d.ts.map +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +59 -27
- package/build/index.js.map +1 -1
- package/package.json +2 -2
package/build/index.js
CHANGED
|
@@ -71,18 +71,28 @@ function resolveNetworkBuffer(device) {
|
|
|
71
71
|
const deviceName = app.deviceInfo.deviceName || app.deviceInfo.title || "unknown";
|
|
72
72
|
return getNetworkBuffer(deviceName);
|
|
73
73
|
}
|
|
74
|
-
// Merge all network requests into a temporary buffer for read operations
|
|
74
|
+
// Merge all network requests into a temporary buffer for read operations.
|
|
75
|
+
// Key by the request's own id so get(requestId) works — earlier this used
|
|
76
|
+
// Math.random() which made every direct lookup miss while listings still
|
|
77
|
+
// appeared correct (listings render req.requestId from the value).
|
|
78
|
+
// Multiple devices can share a request id; suffix with deviceName for
|
|
79
|
+
// collisions so we don't lose entries.
|
|
75
80
|
const merged = new NetworkBuffer(5000);
|
|
76
|
-
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
for (const [deviceName, buffer] of networkBuffers.entries()) {
|
|
77
83
|
for (const req of buffer.getAll({})) {
|
|
78
|
-
|
|
84
|
+
let key = req.requestId;
|
|
85
|
+
if (seen.has(key))
|
|
86
|
+
key = `${req.requestId}@${deviceName}`;
|
|
87
|
+
seen.add(key);
|
|
88
|
+
merged.set(key, req);
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
return merged;
|
|
82
92
|
}
|
|
83
93
|
// Create MCP server
|
|
84
94
|
const server = new McpServer({
|
|
85
|
-
name: "
|
|
95
|
+
name: "ExecBro (Mobile DevTools)",
|
|
86
96
|
version: "1.0.0"
|
|
87
97
|
}, {
|
|
88
98
|
instructions: [
|
|
@@ -311,7 +321,7 @@ function registerToolWithTelemetry(toolName, config, handler, emptyResultDetecto
|
|
|
311
321
|
if (!NON_METRO_TOOLS.has(toolName) && shouldShowFeedbackHint()) {
|
|
312
322
|
markFeedbackHintShown();
|
|
313
323
|
// Fire-and-forget — don't block the tool response
|
|
314
|
-
pushLogBox("Congratulations on your first tool call! If you encounter any issues or have ideas for improvement, ask your AI assistant to call send_feedback. Your feedback helps me make this product better for everyone. Best regards,
|
|
324
|
+
pushLogBox("Congratulations on your first tool call! If you encounter any issues or have ideas for improvement, ask your AI assistant to call send_feedback. Your feedback helps me make this product better for everyone. Best regards, ExecBro developer.", "warning", true, "logbox").catch(() => {
|
|
315
325
|
// Non-fatal — hint delivery failure should not affect tool execution
|
|
316
326
|
});
|
|
317
327
|
}
|
|
@@ -1698,7 +1708,7 @@ registerToolWithTelemetry("get_license_status", {
|
|
|
1698
1708
|
});
|
|
1699
1709
|
// Tool: Send feedback / bug report / feature request
|
|
1700
1710
|
registerToolWithTelemetry("send_feedback", {
|
|
1701
|
-
description: "Create a feedback report (bug, feature request, or general feedback) for the
|
|
1711
|
+
description: "Create a feedback report (bug, feature request, or general feedback) for the ExecBro team. " +
|
|
1702
1712
|
"Auto-collects environment info. Returns a pre-filled GitHub issue URL and formatted issue body. " +
|
|
1703
1713
|
"Ask the user to open the URL and paste the body to submit.",
|
|
1704
1714
|
inputSchema: {
|
|
@@ -2010,7 +2020,9 @@ registerToolWithTelemetry("list_debug_globals", {
|
|
|
2010
2020
|
"PURPOSE: Enumerate the app's `globalThis.*` surface so you know which stores, clients, and debug hooks you can drill into.\n" +
|
|
2011
2021
|
"WHEN TO USE: Start of a state-debugging session, or when you don't know whether the app exposes a Redux/Apollo/Zustand handle.\n" +
|
|
2012
2022
|
"WORKFLOW: list_debug_globals -> inspect_global(objectName=\"...\") -> execute_in_app for reads/mutations.\n" +
|
|
2013
|
-
"
|
|
2023
|
+
"SDK INTEGRATION: If the app uses `react-native-ai-devtools-sdk` and called `init({ stores, navigation, custom })`, the response includes an `sdk.paths` array of ready-to-use dotted paths (e.g. `__RN_AI_DEVTOOLS__.stores.redux`, `__RN_AI_DEVTOOLS__.custom.mmkv`). Pass these straight to inspect_global or execute_in_app.\n" +
|
|
2024
|
+
"OUTPUT SHAPE: { sdk: { version, capabilities, paths, hint } | null, categories: { 'Apollo Client': [...], 'Redux': [...], 'Other Debug': [...], ... } }\n" +
|
|
2025
|
+
"LIMITATIONS: Only sees variables explicitly assigned to a global (e.g., `globalThis.store = store`). Module-scoped state is invisible — expose it first or use the SDK's init().\n" +
|
|
2014
2026
|
"GOOD: list_debug_globals()\n" +
|
|
2015
2027
|
"BAD: Calling before scan_metro — needs a live connection.\n" +
|
|
2016
2028
|
"SEE ALSO: call get_usage_guide(topic=\"state\") for the full app-state playbook.",
|
|
@@ -2041,28 +2053,37 @@ registerToolWithTelemetry("list_debug_globals", {
|
|
|
2041
2053
|
});
|
|
2042
2054
|
// Tool: Inspect a global object to see its properties and types
|
|
2043
2055
|
registerToolWithTelemetry("inspect_global", {
|
|
2044
|
-
description: "Inspect a global object to see its properties, types, and whether they are callable functions. Use this BEFORE calling methods on unfamiliar objects to avoid errors.\n" +
|
|
2045
|
-
"PURPOSE: Surface the shape of a global (Apollo client, Redux store, Expo Router, etc.) — keys, types, and which members are callable — without executing arbitrary code.\n" +
|
|
2056
|
+
description: "Inspect a global object (or a dotted path into one) to see its properties, types, and whether they are callable functions. Use this BEFORE calling methods on unfamiliar objects to avoid errors.\n" +
|
|
2057
|
+
"PURPOSE: Surface the shape of a global (Apollo client, Redux store, Expo Router, SDK-registered store, etc.) — keys, types, and which members are callable — without executing arbitrary code.\n" +
|
|
2046
2058
|
"WHEN TO USE: After list_debug_globals identifies a promising global and before you try execute_in_app on it.\n" +
|
|
2047
2059
|
"WORKFLOW: list_debug_globals -> inspect_global(objectName=\"__APOLLO_CLIENT__\") -> execute_in_app(\"__APOLLO_CLIENT__.cache.extract()\").\n" +
|
|
2048
|
-
"
|
|
2049
|
-
"
|
|
2050
|
-
"
|
|
2060
|
+
"DOTTED PATHS: Pass dotted paths to drill into the SDK surface, e.g. inspect_global({ objectName: \"__RN_AI_DEVTOOLS__.stores.redux\" }) or \"__RN_AI_DEVTOOLS__.custom.mmkv\". Only identifier paths are accepted — for arbitrary expressions, use execute_in_app.\n" +
|
|
2061
|
+
"LIMITATIONS: Only reads one level deep; nested objects show as a 100-char JSON preview — re-inspect the child path. Returns an error object (not a throw) when the path doesn't resolve.\n" +
|
|
2062
|
+
"GOOD: inspect_global({ objectName: \"__APOLLO_CLIENT__\" }) | inspect_global({ objectName: \"__RN_AI_DEVTOOLS__.stores.redux\" })\n" +
|
|
2063
|
+
"BAD: inspect_global({ objectName: \"store.getState()\" }) — call expressions aren't supported; use execute_in_app.\n" +
|
|
2051
2064
|
"SEE ALSO: call get_usage_guide(topic=\"state\") for the full app-state playbook.",
|
|
2052
2065
|
inputSchema: {
|
|
2053
2066
|
objectName: z
|
|
2054
2067
|
.string()
|
|
2055
|
-
.describe("
|
|
2068
|
+
.describe("Identifier or dotted path of the global to inspect (e.g., '__APOLLO_CLIENT__', '__RN_AI_DEVTOOLS__.stores.redux', '__RN_AI_DEVTOOLS__.custom.mmkv')"),
|
|
2056
2069
|
device: z.string().optional().describe("Target device name (substring match). Omit for default device. Run get_apps to see connected devices.")
|
|
2057
2070
|
}
|
|
2058
2071
|
}, async ({ objectName, device }) => {
|
|
2059
2072
|
const result = await inspectGlobal(objectName, device);
|
|
2060
2073
|
if (!result.success) {
|
|
2061
2074
|
let errorText = `Error: ${result.error}`;
|
|
2062
|
-
// If the
|
|
2063
|
-
//
|
|
2064
|
-
|
|
2065
|
-
|
|
2075
|
+
// If the global (or path) doesn't resolve, guide the agent toward
|
|
2076
|
+
// either exposing it manually or registering it via the SDK.
|
|
2077
|
+
const looksMissing = result.error?.includes("ReferenceError") || result.error?.includes("NotFound") || result.error?.includes("not found");
|
|
2078
|
+
if (looksMissing) {
|
|
2079
|
+
const isPath = objectName.includes(".");
|
|
2080
|
+
if (isPath) {
|
|
2081
|
+
errorText += `\n\nNOTE: '${objectName}' did not resolve. Call list_debug_globals to confirm the path. If you expected the SDK to expose it, verify init({ stores, navigation, custom }) was called and check the sdk.paths array.`;
|
|
2082
|
+
}
|
|
2083
|
+
else {
|
|
2084
|
+
const suggested = objectName.replace(/^__/, "").replace(/__$/, "");
|
|
2085
|
+
errorText += `\n\nNOTE: '${objectName}' is not exposed as a global variable. Either (a) assign it in app code (\`globalThis.${objectName} = ${suggested};\`), or (b) register it via react-native-ai-devtools-sdk's init({ custom: { ${suggested}: ${suggested} } }) and access it as __RN_AI_DEVTOOLS__.custom.${suggested}. Then call list_debug_globals to confirm.`;
|
|
2086
|
+
}
|
|
2066
2087
|
}
|
|
2067
2088
|
return {
|
|
2068
2089
|
content: [
|
|
@@ -2909,7 +2930,10 @@ registerToolWithTelemetry("get_request_details", {
|
|
|
2909
2930
|
device: z.string().optional().describe("Target device name (substring match). Omit for all devices. Run get_apps to see connected devices.")
|
|
2910
2931
|
}
|
|
2911
2932
|
}, async ({ requestId, maxBodyLength, verbose, device }) => {
|
|
2912
|
-
//
|
|
2933
|
+
// Resolve once per call so a mid-call SDK socket flap can't flip
|
|
2934
|
+
// routing partway through. Try SDK first (richer data), but ALWAYS
|
|
2935
|
+
// fall back to the CDP buffer on a miss — CDP records carry numeric
|
|
2936
|
+
// ids the SDK store doesn't know about, and vice versa.
|
|
2913
2937
|
const sdkAvailable = await isSDKInstalled();
|
|
2914
2938
|
if (sdkAvailable) {
|
|
2915
2939
|
const sdkResult = await getSDKNetworkEntry(requestId);
|
|
@@ -4185,20 +4209,28 @@ async function main() {
|
|
|
4185
4209
|
if (useHttp) {
|
|
4186
4210
|
// Register dev meta-tool — proxies calls to any tool using the latest handlers
|
|
4187
4211
|
server.registerTool("dev", {
|
|
4188
|
-
description: 'Development meta-tool for hot-reload testing. Use action="list" to
|
|
4212
|
+
description: 'Development meta-tool for hot-reload testing. Use action="list" for a compact tool listing (name + first description line); pass filter to narrow by substring or verbose=true for full descriptions. ' +
|
|
4189
4213
|
'Use action="call" with tool and args to invoke any tool using the latest code after hot-reload. ' +
|
|
4190
4214
|
"This tool always reflects the latest server code without needing a session restart.",
|
|
4191
4215
|
inputSchema: {
|
|
4192
4216
|
action: z.enum(["list", "call"]).describe('"list" to see all tools, "call" to invoke a tool'),
|
|
4193
4217
|
tool: z.string().optional().describe("Tool name to call (required when action is call)"),
|
|
4194
4218
|
args: z.record(z.any()).optional().describe("Arguments to pass to the tool (optional, default {})"),
|
|
4219
|
+
filter: z.string().optional().describe("list only: case-insensitive substring filter on tool name"),
|
|
4220
|
+
verbose: z.boolean().optional().describe("list only: include full multi-line descriptions (default: first line only)"),
|
|
4195
4221
|
},
|
|
4196
|
-
}, async ({ action, tool, args }) => {
|
|
4222
|
+
}, async ({ action, tool, args, filter, verbose }) => {
|
|
4197
4223
|
if (action === "list") {
|
|
4198
|
-
const
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4224
|
+
const needle = filter?.toLowerCase();
|
|
4225
|
+
const tools = Array.from(toolRegistry.entries())
|
|
4226
|
+
.filter(([name]) => !needle || name.toLowerCase().includes(needle))
|
|
4227
|
+
.map(([name, { config }]) => {
|
|
4228
|
+
const full = config.description || "";
|
|
4229
|
+
return {
|
|
4230
|
+
name,
|
|
4231
|
+
description: verbose ? full : full.split("\n")[0],
|
|
4232
|
+
};
|
|
4233
|
+
});
|
|
4202
4234
|
return {
|
|
4203
4235
|
content: [{ type: "text", text: JSON.stringify(tools, null, 2) }],
|
|
4204
4236
|
};
|
|
@@ -4240,14 +4272,14 @@ async function main() {
|
|
|
4240
4272
|
res.end("Not found");
|
|
4241
4273
|
});
|
|
4242
4274
|
httpServer.listen(httpPort, () => {
|
|
4243
|
-
console.error(`[
|
|
4275
|
+
console.error(`[execbro] MCP HTTP server listening on http://localhost:${httpPort}/mcp`);
|
|
4244
4276
|
});
|
|
4245
4277
|
}
|
|
4246
4278
|
else {
|
|
4247
4279
|
// Stdio transport mode — default for production
|
|
4248
4280
|
const transport = new StdioServerTransport();
|
|
4249
4281
|
await server.connect(transport);
|
|
4250
|
-
console.error("[
|
|
4282
|
+
console.error("[execbro] Server started on stdio");
|
|
4251
4283
|
}
|
|
4252
4284
|
}
|
|
4253
4285
|
// Skip boot when loaded by unit tests — tests import this module purely to
|
|
@@ -4255,7 +4287,7 @@ async function main() {
|
|
|
4255
4287
|
// is a manual escape hatch. Production + dev:mcp leave both unset and boot.
|
|
4256
4288
|
if (!process.env.RN_AI_DEVTOOLS_TEST_MODE && !process.env.JEST_WORKER_ID) {
|
|
4257
4289
|
main().catch((error) => {
|
|
4258
|
-
console.error("[
|
|
4290
|
+
console.error("[execbro] Fatal error:", error);
|
|
4259
4291
|
process.exit(1);
|
|
4260
4292
|
});
|
|
4261
4293
|
}
|