agent-device 0.12.8 → 0.13.0

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.
@@ -414,7 +414,7 @@ export declare class AppError extends Error {
414
414
  constructor(code: AppErrorCode, message: string, details?: AppErrorDetails, cause?: unknown);
415
415
  }
416
416
 
417
- export declare type AppErrorCode = 'INVALID_ARGS' | 'DEVICE_NOT_FOUND' | 'TOOL_MISSING' | 'APP_NOT_INSTALLED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_OPERATION' | 'NOT_IMPLEMENTED' | 'COMMAND_FAILED' | 'SESSION_NOT_FOUND' | 'UNAUTHORIZED' | 'UNKNOWN';
417
+ export declare type AppErrorCode = KnownAppErrorCode | (string & {});
418
418
 
419
419
  declare type AppErrorDetails = Record<string, unknown> & {
420
420
  hint?: string;
@@ -1053,6 +1053,7 @@ export declare type CaptureScreenshotOptions = AgentDeviceRequestOverrides & {
1053
1053
  path?: string;
1054
1054
  overlayRefs?: boolean;
1055
1055
  fullscreen?: boolean;
1056
+ maxSize?: number;
1056
1057
  surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
1057
1058
  };
1058
1059
 
@@ -1082,6 +1083,8 @@ export declare type CaptureSnapshotResult = {
1082
1083
 
1083
1084
  export declare function centerOfRect(rect: Rect): Point;
1084
1085
 
1086
+ declare type ClickButton = 'primary' | 'secondary' | 'middle';
1087
+
1085
1088
  declare type ClickCommandOptions = PressCommandOptions;
1086
1089
 
1087
1090
  export declare type ClickOptions = ClientCommandBaseOptions & SelectorSnapshotCommandOptions & InteractionTarget & RepeatedPressOptions & {
@@ -1645,8 +1648,6 @@ declare type FindBaseOptions = ClientCommandBaseOptions & FindSnapshotCommandOpt
1645
1648
 
1646
1649
  export declare type FindLocator = 'any' | 'text' | 'label' | 'value' | 'role' | 'id';
1647
1650
 
1648
- declare type FindLocator_2 = 'any' | 'text' | 'label' | 'value' | 'role' | 'id';
1649
-
1650
1651
  export declare type FindOptions = (FindBaseOptions & {
1651
1652
  action?: 'click' | 'focus' | 'exists' | 'getText' | 'getAttrs';
1652
1653
  }) | (FindBaseOptions & {
@@ -1658,7 +1659,7 @@ export declare type FindOptions = (FindBaseOptions & {
1658
1659
  });
1659
1660
 
1660
1661
  declare type FindReadCommandOptions = CommandContext & {
1661
- locator?: FindLocator_2;
1662
+ locator?: FindLocator;
1662
1663
  query: string;
1663
1664
  action: Extract<FindAction['kind'], 'exists' | 'wait' | 'get_text' | 'get_attrs'>;
1664
1665
  timeoutMs?: number;
@@ -1796,6 +1797,8 @@ export declare type KeyboardCommandResult = DaemonResponseData & {
1796
1797
  attempts?: number;
1797
1798
  };
1798
1799
 
1800
+ declare type KnownAppErrorCode = 'INVALID_ARGS' | 'DEVICE_NOT_FOUND' | 'DEVICE_IN_USE' | 'TOOL_MISSING' | 'APP_NOT_INSTALLED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_OPERATION' | 'NOT_IMPLEMENTED' | 'COMMAND_FAILED' | 'SESSION_NOT_FOUND' | 'UNAUTHORIZED' | 'AMBIGUOUS_MATCH' | 'UNKNOWN';
1801
+
1799
1802
  declare type Lease = {
1800
1803
  leaseId: string;
1801
1804
  tenantId: string;
@@ -1899,19 +1902,21 @@ declare type MetroBridgeResult = {
1899
1902
  };
1900
1903
  };
1901
1904
 
1905
+ declare type MetroBridgeScope = {
1906
+ tenantId: string;
1907
+ runId: string;
1908
+ leaseId: string;
1909
+ };
1910
+
1902
1911
  declare type MetroPrepareKind = 'auto' | 'react-native' | 'expo';
1903
1912
 
1904
1913
  export declare type MetroPrepareOptions = {
1905
1914
  projectRoot?: string;
1906
1915
  kind?: MetroPrepareKind;
1907
- publicBaseUrl: string;
1916
+ publicBaseUrl?: string;
1908
1917
  proxyBaseUrl?: string;
1909
1918
  bearerToken?: string;
1910
- bridgeScope?: {
1911
- tenantId: string;
1912
- runId: string;
1913
- leaseId: string;
1914
- };
1919
+ bridgeScope?: MetroBridgeScope;
1915
1920
  launchUrl?: string;
1916
1921
  companionProfileKey?: string;
1917
1922
  companionConsumerKey?: string;
@@ -2030,7 +2035,7 @@ declare type PrepareMetroRuntimeResult = {
2030
2035
 
2031
2036
  declare type PressCommandOptions = CommandContext & {
2032
2037
  target: InteractionTarget_2;
2033
- button?: 'primary' | 'secondary' | 'middle';
2038
+ button?: ClickButton;
2034
2039
  count?: number;
2035
2040
  intervalMs?: number;
2036
2041
  holdMs?: number;
@@ -2159,11 +2164,13 @@ declare type RepeatedPressOptions = {
2159
2164
  export declare type ReplayRunOptions = AgentDeviceRequestOverrides & {
2160
2165
  path: string;
2161
2166
  update?: boolean;
2167
+ env?: string[];
2162
2168
  };
2163
2169
 
2164
2170
  export declare type ReplayTestOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
2165
2171
  paths: string[];
2166
2172
  update?: boolean;
2173
+ env?: string[];
2167
2174
  failFast?: boolean;
2168
2175
  timeoutMs?: number;
2169
2176
  retries?: number;
@@ -2244,6 +2251,7 @@ declare type ScreenshotCommandOptions = CommandContext & {
2244
2251
  out?: FileOutputRef;
2245
2252
  fullscreen?: boolean;
2246
2253
  overlayRefs?: boolean;
2254
+ maxSize?: number;
2247
2255
  appId?: string;
2248
2256
  appBundleId?: string;
2249
2257
  surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
@@ -2446,6 +2454,9 @@ declare type SessionRuntimeHints = {
2446
2454
  export declare type SettingsUpdateOptions = (ClientCommandBaseOptions & {
2447
2455
  setting: 'wifi' | 'airplane' | 'location';
2448
2456
  state: 'on' | 'off';
2457
+ }) | (ClientCommandBaseOptions & {
2458
+ setting: 'animations';
2459
+ state: 'on' | 'off';
2449
2460
  }) | (ClientCommandBaseOptions & {
2450
2461
  setting: 'appearance';
2451
2462
  state: 'light' | 'dark' | 'toggle';
@@ -11,11 +11,7 @@ export declare type EnsureMetroTunnelOptions = {
11
11
  serverBaseUrl: string;
12
12
  bearerToken: string;
13
13
  localBaseUrl: string;
14
- bridgeScope: {
15
- tenantId: string;
16
- runId: string;
17
- leaseId: string;
18
- };
14
+ bridgeScope: MetroBridgeScope;
19
15
  launchUrl?: string;
20
16
  profileKey?: string;
21
17
  consumerKey?: string;
@@ -79,6 +75,12 @@ export declare type MetroBridgeRuntimePayload = {
79
75
  launch_url?: string;
80
76
  };
81
77
 
78
+ declare type MetroBridgeScope = {
79
+ tenantId: string;
80
+ runId: string;
81
+ leaseId: string;
82
+ };
83
+
82
84
  /** Re-export of {@link SessionRuntimeHints} under the Metro-specific alias used by public API consumers. */
83
85
  export declare type MetroRuntimeHints = SessionRuntimeHints;
84
86
 
@@ -157,14 +159,10 @@ export declare function prepareRemoteMetro(options: PrepareRemoteMetroOptions):
157
159
  export declare type PrepareRemoteMetroOptions = {
158
160
  projectRoot: string;
159
161
  kind: 'auto' | 'react-native' | 'expo';
160
- publicBaseUrl: string;
162
+ publicBaseUrl?: string;
161
163
  proxyBaseUrl?: string;
162
164
  proxyBearerToken?: string;
163
- bridgeScope?: {
164
- tenantId: string;
165
- runId: string;
166
- leaseId: string;
167
- };
165
+ bridgeScope?: MetroBridgeScope;
168
166
  launchUrl?: string;
169
167
  profileKey?: string;
170
168
  consumerKey?: string;
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "agent-device",
3
- "version": "0.12.8",
4
- "description": "Unified control plane for physical and virtual devices via an agent-driven CLI.",
3
+ "version": "0.13.0",
4
+ "description": "Agent-driven CLI for mobile UI automation, network inspection, and performance diagnostics across iOS, Android, tvOS, and macOS.",
5
5
  "license": "MIT",
6
6
  "author": "Callstack",
7
+ "homepage": "https://agent-device.dev/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/callstackincubator/agent-device.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/callstackincubator/agent-device/issues"
14
+ },
7
15
  "type": "module",
8
16
  "main": "dist/src/index.js",
9
17
  "types": "dist/src/index.d.ts",
@@ -120,11 +128,20 @@
120
128
  "agent",
121
129
  "device",
122
130
  "cli",
131
+ "automation",
123
132
  "adb",
124
133
  "simctl",
125
134
  "devicectl",
126
135
  "ios",
127
- "android"
136
+ "android",
137
+ "tvos",
138
+ "macos",
139
+ "react-native",
140
+ "observability",
141
+ "diagnostics",
142
+ "network",
143
+ "profiling",
144
+ "performance"
128
145
  ],
129
146
  "dependencies": {
130
147
  "fast-xml-parser": "^5.5.10",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-device
3
- description: Automates interactions for Apple-platform apps (iOS, tvOS, macOS) and Android devices. Use when navigating apps, taking snapshots/screenshots, tapping, typing, scrolling, or extracting UI info across mobile, TV, and desktop targets.
3
+ description: Automates interactions for Apple-platform apps (iOS, tvOS, macOS) and Android devices. Use when navigating apps, taking snapshots/screenshots, tapping, typing, scrolling, extracting UI info, or collecting logs, network inspection, and perf snapshots across mobile, TV, and desktop targets.
4
4
  ---
5
5
 
6
6
  # agent-device
@@ -71,3 +71,4 @@ Use this skill as a router with mandatory defaults. Read this file first. For no
71
71
  - Need desktop surfaces, menu bar behavior, or macOS-specific interaction rules: [references/macos-desktop.md](references/macos-desktop.md)
72
72
  - Need remote HTTP transport, `connect --remote-config`, or tenant leases on a remote macOS host: [references/remote-tenancy.md](references/remote-tenancy.md)
73
73
  This includes remote React Native runs where `agent-device` now prepares Metro locally and manages the local Metro companion tunnel automatically.
74
+ - Need the React Native component tree, props, state, hooks, or render profiling: use `agent-device react-devtools ...` and the [react-devtools skill](../react-devtools/SKILL.md).
@@ -4,6 +4,8 @@
4
4
 
5
5
  Open this file when the task turns into failure triage, logs, network inspection, permission prompts, setup trouble, or unstable session behavior.
6
6
 
7
+ If the debugging task needs the React Native component tree, props, state, hooks, or render profiling, use `agent-device react-devtools ...` and the `skills/react-devtools` workflow instead of trying to infer those internals from the accessibility tree or app logs alone.
8
+
7
9
  ## Main commands to reach for first
8
10
 
9
11
  - `logs clear --restart`
@@ -111,7 +113,7 @@ agent-device alert accept
111
113
  - `snapshot` returns 0 nodes: the app may no longer be foregrounded or the UI is not stable yet. Re-open the app or retry when state settles.
112
114
  - Logs are empty: confirm you opened an app session before `logs clear --restart`.
113
115
  - Android logs look stale after relaunch: retry the repro window after the process rebinds.
114
- - Android accessibility snapshots can lag behind visible screen transitions. The next snapshot now retries briefly after navigation-sensitive actions, but if the tree still looks stale, use `screenshot` as visual truth, wait briefly, then re-run `snapshot -i`.
116
+ - Android accessibility snapshots can lag behind visible screen transitions. The next snapshot retries suspicious trees for a short post-action deadline after navigation-sensitive actions, and `@ref` actions refresh while that window is active. If the tree still looks stale, use `screenshot` as visual truth, wait briefly, then re-run `snapshot -i`. For animation-heavy runs, try `settings animations off` and restore with `settings animations on`.
115
117
  - React Native dev warnings or errors keep reappearing: treat them as part of the app state, not as disposable chrome. Capture one clean repro and include them in the summary.
116
118
  - Permission prompts block the flow: wait for the alert and handle it explicitly.
117
119
  - If snapshots keep returning 0 nodes on an iOS simulator, restart Simulator and re-open the app.
@@ -20,6 +20,7 @@ Open this file when the app or screen is already running and you need to discove
20
20
  - User asks what is visible on screen: `snapshot`
21
21
  - User asks for exact text from a known target: `get text`
22
22
  - User asks you to tap, type, or choose an element: `snapshot -i`, then act
23
+ - User asks for the React Native component tree, props/state/hooks, or render profiling: use `agent-device react-devtools ...` and the `skills/react-devtools` workflow
23
24
  - React Native dev or debug build shows warning/error UI: capture enough evidence to identify it, dismiss it if it is not the requested behavior, then continue the flow and report it in the summary
24
25
  - The on-screen keyboard is blocking the next step: `keyboard dismiss`; on iOS do this only while an app session is active, and use `keyboard status|get` only on Android
25
26
  - UI does not expose the answer: say so plainly; do not browse or force the app into a new state unless asked
@@ -49,8 +50,9 @@ Open this file when the app or screen is already running and you need to discove
49
50
  **Android AX tree lag.** After submits, route changes, or composer transitions, the accessibility tree can lag behind the visible UI. If `snapshot -i` and `screenshot` disagree:
50
51
 
51
52
  1. Trust the screenshot as visual truth.
52
- 2. Take one fresh `snapshot -i`. Android retries briefly after navigation-sensitive actions.
53
+ 2. Take one fresh `snapshot -i`. Android retries suspicious trees for a short post-action deadline after navigation-sensitive actions.
53
54
  3. If the tree still disagrees with the screenshot, wait briefly, then take one more fresh snapshot. Do not loop snapshots immediately.
55
+ 4. For animation-heavy Android runs, use `settings animations off` as an opt-in stabilizer and restore with `settings animations on` after the run.
54
56
 
55
57
  **React Native dev overlays.** In dev or debug builds, warning or error overlays can block taps, change focus, or hide the real UI. Check for them near app open and after major transitions.
56
58
 
@@ -222,7 +224,7 @@ Preferred mapping:
222
224
  Notes:
223
225
 
224
226
  - `wait text` is useful for synchronizing on text presence, but it is not the same as `is visible`.
225
- - After a nearby navigation or submit on Android, prefer `screenshot`, then `wait 500` or `wait 1000`, then one fresh `snapshot -i` if the accessibility tree seems stale.
227
+ - After a nearby navigation or submit on Android, prefer `screenshot`, then one fresh `snapshot -i`; `@ref` interactions refresh while the Android freshness window is active.
226
228
 
227
229
  Anti-hallucination rules:
228
230
 
@@ -338,6 +340,7 @@ Common batch error categories:
338
340
  - `SESSION_NOT_FOUND`: open or select the correct session, then retry.
339
341
  - `UNSUPPORTED_OPERATION`: switch to a supported command or surface.
340
342
  - `AMBIGUOUS_MATCH`: refine the selector or locator, then retry the failed step.
343
+ - `DEVICE_IN_USE`: the device is held by another session — close or reuse the existing session before retrying.
341
344
  - `COMMAND_FAILED`: add sync guards and retry from the failing step.
342
345
 
343
346
  ## Stop conditions
@@ -103,8 +103,8 @@ Example `remote-config.json` shape:
103
103
  "tenant": "acme",
104
104
  "runId": "run-123",
105
105
  "sessionIsolation": "tenant",
106
- "platform": "android",
107
- "metroPublicBaseUrl": "http://127.0.0.1:8081"
106
+ "platform": "ios",
107
+ "metroProxyBaseUrl": "https://bridge.example.com"
108
108
  }
109
109
  ```
110
110
 
@@ -112,11 +112,11 @@ Optional overrides stay available for advanced cases:
112
112
 
113
113
  ```json
114
114
  {
115
- "session": "adc-android",
116
- "leaseBackend": "android-instance",
115
+ "session": "adc-ios",
116
+ "leaseBackend": "ios-instance",
117
117
  "metroProjectRoot": ".",
118
118
  "metroKind": "expo",
119
- "metroProxyBaseUrl": "https://bridge.example.com/metro/acme/run-123"
119
+ "metroPublicBaseUrl": "http://127.0.0.1:8081"
120
120
  }
121
121
  ```
122
122
 
@@ -124,7 +124,10 @@ Optional overrides stay available for advanced cases:
124
124
  - Omit Metro fields for non-React Native flows.
125
125
  - Put `tenant`, `runId`, and `sessionIsolation` in the remote profile so agents can run `agent-device connect --remote-config ./remote-config.json` without extra scope flags. Add `platform`, `leaseBackend`, `session`, or Metro overrides only when the default inference is not enough for that flow.
126
126
  - Explicit command-line flags override connected defaults. Use them intentionally when switching session, platform, target, tenant, run, or lease scope.
127
- - For React Native Metro runs with `metroProxyBaseUrl`, `agent-device >= 0.11.12` can manage the local companion tunnel, but Metro itself still needs to be running locally.
127
+ - For React Native Metro runs with `metroProxyBaseUrl`, `agent-device >= 0.11.12` can manage the local companion tunnel, but Metro itself still needs to be running locally. `metroProxyBaseUrl` is the bridge origin, not a prebuilt `/api/metro/...` route.
128
+ - For cloud stock React Native iOS, use the bridge descriptor's wildcard HTTPS Metro hints directly; do not install or launch the XCTest runner just to make Metro reachable.
129
+ - Android keeps using bridge-provided `/api/metro/runtimes/<runtimeId>/...` Metro routes.
130
+ - `metroPublicBaseUrl` is only needed for direct/non-bridge bundle hints. Bridged profiles can omit it.
128
131
  - Use a lease backend that matches the bridge target platform, for example `android-instance`, `ios-instance`, or an explicit `--lease-backend` override.
129
132
 
130
133
  ## Transport prerequisites
@@ -46,7 +46,10 @@ agent-device diff snapshot -i
46
46
 
47
47
  Use `screenshot` when the proof needs a rendered image instead of a structural tree.
48
48
 
49
+ - Add `--max-size 1024` when a full-resolution screenshot is too large for an agent, model, or chat attachment.
49
50
  - Add `--overlay-refs` when you want the saved PNG to show fresh `@eN` refs burned into the screenshot.
51
+ - Combine them as `screenshot /tmp/proof.png --max-size 1024 --overlay-refs` when you need a smaller visual proof that still includes tappable refs.
52
+ - Avoid very small `--max-size` values when text, icons, or labels need to remain readable.
50
53
 
51
54
  ## Visual regression with diff screenshot
52
55
 
@@ -126,5 +129,6 @@ agent-device perf --json
126
129
  - `startup` is command round-trip timing around `open`.
127
130
  - It is not true first-frame or first-interactive telemetry.
128
131
  - Android app sessions also expose `memory` (`dumpsys meminfo`) and `cpu` (`dumpsys cpuinfo`) snapshots when the session has an app package context.
129
- - Apple app sessions on macOS and iOS simulators also expose `memory` and `cpu` process snapshots when the session has an app bundle ID.
130
- - `fps` is still unavailable, and physical iOS devices still leave `memory` and `cpu` unavailable in this release.
132
+ - Apple app sessions on macOS, iOS simulators, and physical iOS devices also expose `memory` and `cpu` process snapshots when the session has an app bundle ID.
133
+ - On physical iOS devices, sampling uses a short `xcrun xctrace` Activity Monitor capture, so keep the device unlocked, connected, and the app active in the foreground while sampling.
134
+ - `fps` is still unavailable in this release.
@@ -166,6 +166,7 @@ agent-device --session {SESSION} close
166
166
  - Re-snapshot after any mutation (navigation, modal, list update, form submit).
167
167
  - Use `fill` for clear-then-type semantics; use `type` for incremental typing behavior checks.
168
168
  - Keep logs optional and targeted: enable/read app logs only when useful for diagnosis.
169
+ - If the issue appears rooted in React Native internals rather than device/app runtime behavior, use `agent-device react-devtools ...` and the `skills/react-devtools` workflow for component-tree or render-profiling inspection.
169
170
  - Never read source code of the app under test; findings must come from observed runtime behavior.
170
171
  - Write each issue immediately to avoid losing evidence.
171
172
  - Never delete screenshots/videos/report artifacts during a session.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: react-devtools
3
+ description: Inspect and profile React Native component trees from agent-device. Use when debugging React Native props, state, hooks, render causes, slow components, excessive re-renders, or questions like why a component re-rendered.
4
+ ---
5
+
6
+ # react-devtools
7
+
8
+ Use this skill when the task needs React Native internals that are not visible in the accessibility tree: component hierarchy, props, state, hooks, render causes, or profiling data.
9
+
10
+ Run commands through `agent-device react-devtools`. The command dynamically runs pinned `agent-react-devtools@0.4.0` and passes arguments through 1:1.
11
+
12
+ The first run may download the pinned package from npm. `agent-device` global flags work before or after `react-devtools`; use `--` before downstream flags only when they intentionally share an `agent-device` global flag name.
13
+
14
+ ## Default flow
15
+
16
+ 1. Use `agent-device` to open the React Native app and verify the visible state when needed.
17
+ 2. Check `agent-device react-devtools status`.
18
+ 3. If no app is connected, start or wait for the devtools daemon, then reload or relaunch the app.
19
+ 4. Inspect with `get tree`, `find`, and `get component`.
20
+ 5. Profile only around the interaction being investigated.
21
+ 6. Verify the fix with the same command sequence and interaction.
22
+
23
+ For cross-platform validation with explicit `--device`, `--udid`, or `--serial` selectors, prefer an isolated `--state-dir` over separate named sessions. Named sessions enable bound-session locks during setup. Restart `agent-device react-devtools` between iOS and Android runs so `status`, `get tree`, and profiling clearly refer to the currently launched app.
24
+
25
+ ## Main commands
26
+
27
+ ```bash
28
+ agent-device react-devtools status
29
+ agent-device react-devtools wait --connected
30
+ agent-device react-devtools get tree --depth 3
31
+ agent-device react-devtools find <ComponentName>
32
+ agent-device react-devtools get component @c5
33
+ agent-device react-devtools profile start
34
+ agent-device react-devtools profile stop
35
+ agent-device react-devtools profile slow --limit 5
36
+ agent-device react-devtools profile rerenders --limit 5
37
+ ```
38
+
39
+ ## Decision rules
40
+
41
+ - Need current UI text, refs, screenshots, logs, network, or device metrics: use the `agent-device` skill.
42
+ - Need props, state, hooks, component ownership, render causes, or React profiler data: use this skill.
43
+ - Start component-tree reads with `get tree --depth 3` or `find <name>` to keep output bounded.
44
+ - Labels like `@c5` reset when the app reloads or components remount. After reload, run `wait --connected` and inspect again.
45
+ - Profiling only captures renders between `profile start` and `profile stop`.
46
+ - On Android, set `adb reverse tcp:8097 tcp:8097` for React DevTools. If Metro is local, also set `adb reverse tcp:8081 tcp:8081`.
47
+
48
+ ## References
49
+
50
+ | File | When to read |
51
+ | --------------------------------------- | --------------------------------------------- |
52
+ | [commands.md](references/commands.md) | Command reference and common inspection flows |
53
+ | [profiling.md](references/profiling.md) | Render profiling workflow and interpretation |
@@ -0,0 +1,91 @@
1
+ # React DevTools Commands
2
+
3
+ All commands are run through `agent-device react-devtools`.
4
+
5
+ ## Connection
6
+
7
+ ```bash
8
+ agent-device react-devtools start
9
+ agent-device react-devtools stop
10
+ agent-device react-devtools status
11
+ agent-device react-devtools wait --connected --timeout 30
12
+ agent-device react-devtools wait --component <ComponentName> --timeout 30
13
+ ```
14
+
15
+ - `status` shows the daemon port, connected apps, component count, profiling state, uptime, and last connection event.
16
+ - Most commands auto-start the daemon, but `start` is useful before launching or reloading the app.
17
+ - React Native development builds connect to the daemon on port 8097. For Android emulators or physical devices, use `adb reverse tcp:8097 tcp:8097` if the app cannot reach the host. If the app also uses local Metro, set `adb reverse tcp:8081 tcp:8081`.
18
+
19
+ ## Validation Notes
20
+
21
+ - When validating the same app across iOS and Android with explicit `--device`, `--udid`, or `--serial` selectors, prefer an isolated `--state-dir` over separate named sessions. A named `--session` enables bound-session lock behavior, so setup commands with explicit target selectors can be rejected.
22
+ - Restart the React DevTools daemon between platforms so `status`, `get tree`, and profiling output belong to the currently launched app.
23
+ - Verify the app is visibly loaded with `snapshot` before collecting React internals. Use `react-devtools` for component state and profiling, not for proving the device/app surface is open.
24
+
25
+ ## Component Inspection
26
+
27
+ ```bash
28
+ agent-device react-devtools get tree --depth 3
29
+ agent-device react-devtools get component @c5
30
+ agent-device react-devtools find Button
31
+ agent-device react-devtools find Button --exact
32
+ agent-device react-devtools count
33
+ agent-device react-devtools errors
34
+ ```
35
+
36
+ - `get tree` prints a component hierarchy with labels like `@c1`, `@c2`.
37
+ - Use `--depth` on large apps. Start at `--depth 3` or `--depth 4`.
38
+ - `get component` accepts a label or numeric React fiber id and shows props, state, and hooks.
39
+ - `find` searches by display name. Use `--exact` when fuzzy results are noisy.
40
+ - `errors` lists components with React-tracked warnings or errors.
41
+
42
+ ## Profiling
43
+
44
+ ```bash
45
+ agent-device react-devtools profile start "interaction name"
46
+ agent-device react-devtools profile stop
47
+ agent-device react-devtools profile slow --limit 5
48
+ agent-device react-devtools profile rerenders --limit 5
49
+ agent-device react-devtools profile report @c5
50
+ agent-device react-devtools profile timeline --limit 20
51
+ agent-device react-devtools profile commit 3
52
+ agent-device react-devtools profile export profile.json
53
+ agent-device react-devtools profile diff before.json after.json --limit 10
54
+ ```
55
+
56
+ - `profile slow` ranks components by average render duration.
57
+ - `profile rerenders` ranks components by render count.
58
+ - `profile report @cN` shows render causes and changed props/state/hooks for one component.
59
+ - `profile timeline` lists commits. Use `--limit` and `--offset` for long sessions.
60
+ - `profile export` writes React DevTools Profiler JSON that can be diffed later.
61
+
62
+ ## Common Flows
63
+
64
+ Inspect a component:
65
+
66
+ ```bash
67
+ agent-device react-devtools status
68
+ agent-device react-devtools get tree --depth 3
69
+ agent-device react-devtools find SearchScreen
70
+ agent-device react-devtools get component @c12
71
+ ```
72
+
73
+ Profile a slow interaction:
74
+
75
+ ```bash
76
+ agent-device react-devtools profile start "slow search"
77
+ # Trigger the interaction with agent-device or ask the user to perform it.
78
+ agent-device react-devtools profile stop
79
+ agent-device react-devtools profile slow --limit 5
80
+ agent-device react-devtools profile rerenders --limit 5
81
+ ```
82
+
83
+ Verify a render fix:
84
+
85
+ ```bash
86
+ agent-device react-devtools profile start "after fix"
87
+ # Repeat the same interaction.
88
+ agent-device react-devtools profile stop
89
+ agent-device react-devtools profile slow --limit 5
90
+ agent-device react-devtools profile rerenders --limit 5
91
+ ```
@@ -0,0 +1,74 @@
1
+ # React Native Profiling
2
+
3
+ Use this workflow when the user reports slow interactions, excessive re-renders, unstable props, or unclear render causes.
4
+
5
+ ## Baseline
6
+
7
+ ```bash
8
+ agent-device react-devtools status
9
+ agent-device react-devtools count
10
+ agent-device react-devtools get tree --depth 3
11
+ ```
12
+
13
+ If the app is not connected, run:
14
+
15
+ ```bash
16
+ agent-device react-devtools start
17
+ agent-device react-devtools wait --connected
18
+ ```
19
+
20
+ Then reload or relaunch the React Native app if needed.
21
+
22
+ ## Capture One Interaction
23
+
24
+ ```bash
25
+ agent-device react-devtools profile start "short label"
26
+ # Trigger exactly the interaction being investigated.
27
+ agent-device react-devtools profile stop
28
+ ```
29
+
30
+ Keep the profiling window narrow. Extra navigation, warm-up work, or unrelated gestures make the report harder to interpret.
31
+
32
+ ## Identify Suspects
33
+
34
+ ```bash
35
+ agent-device react-devtools profile slow --limit 5
36
+ agent-device react-devtools profile rerenders --limit 5
37
+ ```
38
+
39
+ - A component with high average render time is a slow-render suspect.
40
+ - A component with high render count is a re-render suspect.
41
+ - A component can be both.
42
+
43
+ ## Drill In
44
+
45
+ ```bash
46
+ agent-device react-devtools profile report @c12
47
+ agent-device react-devtools get component @c12
48
+ ```
49
+
50
+ Use `profile report` to identify render causes and changed keys. Use `get component` to inspect current props, state, and hooks.
51
+
52
+ Common interpretations:
53
+
54
+ | Signal | Meaning | Typical follow-up |
55
+ | ------------------------------------------ | ----------------------------------- | ---------------------------------------------- |
56
+ | `props-changed` with function props | Parent may pass unstable callbacks | Check whether the parent can use `useCallback` |
57
+ | `props-changed` with object or array props | Parent may pass unstable references | Check whether the parent can use `useMemo` |
58
+ | `parent-rendered` with many child renders | Child has no bailout | Check whether `React.memo` is appropriate |
59
+ | `state-changed` | Component state caused the render | Check whether the state update is necessary |
60
+ | `hooks-changed` | Hook value or dependency changed | Inspect hook values and dependencies |
61
+
62
+ ## Verify
63
+
64
+ After making a change, repeat the same interaction:
65
+
66
+ ```bash
67
+ agent-device react-devtools profile start "after fix"
68
+ # Repeat the same interaction.
69
+ agent-device react-devtools profile stop
70
+ agent-device react-devtools profile slow --limit 5
71
+ agent-device react-devtools profile rerenders --limit 5
72
+ ```
73
+
74
+ Compare render counts, average durations, changed keys, and commit counts against the baseline.