agent-device 0.12.9 → 0.13.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/README.md +24 -1
- package/dist/src/1974.js +2 -2
- package/dist/src/320.js +1 -1
- package/dist/src/3918.js +29 -28
- package/dist/src/7651.js +1 -1
- package/dist/src/8564.js +1 -1
- package/dist/src/8656.js +1 -0
- package/dist/src/9076.js +1 -1
- package/dist/src/9542.js +2 -2
- package/dist/src/backend.js +1 -1
- package/dist/src/bin.js +37 -37
- package/dist/src/contracts.d.ts +12 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon.js +18 -15
- package/dist/src/index.d.ts +34 -1
- package/dist/src/metro-companion.js +1 -1
- package/dist/src/metro.d.ts +21 -0
- package/dist/src/metro.js +1 -1
- package/package.json +12 -3
- package/skills/agent-device/SKILL.md +4 -1
- package/skills/agent-device/references/bootstrap-install.md +26 -6
- package/skills/agent-device/references/debugging.md +3 -1
- package/skills/agent-device/references/exploration.md +15 -2
- package/skills/agent-device/references/remote-tenancy.md +39 -19
- package/skills/agent-device/references/verification.md +3 -2
- package/skills/dogfood/SKILL.md +1 -0
- package/skills/react-devtools/SKILL.md +55 -0
- package/skills/react-devtools/references/commands.md +91 -0
- package/skills/react-devtools/references/profiling.md +74 -0
- package/dist/src/3883.js +0 -1
- package/dist/src/4993.js +0 -1
- package/dist/src/8164.js +0 -1
- package/dist/src/9323.js +0 -5
package/dist/src/index.d.ts
CHANGED
|
@@ -145,6 +145,7 @@ export declare type AgentDeviceClient = {
|
|
|
145
145
|
};
|
|
146
146
|
metro: {
|
|
147
147
|
prepare: (options: MetroPrepareOptions) => Promise<MetroPrepareResult>;
|
|
148
|
+
reload: (options?: MetroReloadOptions) => Promise<MetroReloadResult>;
|
|
148
149
|
};
|
|
149
150
|
capture: {
|
|
150
151
|
snapshot: (options?: CaptureSnapshotOptions) => Promise<CaptureSnapshotResult>;
|
|
@@ -1412,7 +1413,18 @@ declare type DaemonInstallSource = {
|
|
|
1412
1413
|
} | {
|
|
1413
1414
|
kind: 'path';
|
|
1414
1415
|
path: string;
|
|
1415
|
-
}
|
|
1416
|
+
} | ({
|
|
1417
|
+
kind: 'github-actions-artifact';
|
|
1418
|
+
owner: string;
|
|
1419
|
+
repo: string;
|
|
1420
|
+
} & ({
|
|
1421
|
+
artifactId: number;
|
|
1422
|
+
} | {
|
|
1423
|
+
runId: number;
|
|
1424
|
+
artifactName: string;
|
|
1425
|
+
} | {
|
|
1426
|
+
artifactName: string;
|
|
1427
|
+
}));
|
|
1416
1428
|
|
|
1417
1429
|
declare type DaemonLockPolicy = 'reject' | 'strip';
|
|
1418
1430
|
|
|
@@ -1933,6 +1945,15 @@ export declare type MetroPrepareOptions = {
|
|
|
1933
1945
|
|
|
1934
1946
|
export declare type MetroPrepareResult = PrepareMetroRuntimeResult;
|
|
1935
1947
|
|
|
1948
|
+
export declare type MetroReloadOptions = {
|
|
1949
|
+
metroHost?: string;
|
|
1950
|
+
metroPort?: number;
|
|
1951
|
+
bundleUrl?: string;
|
|
1952
|
+
timeoutMs?: number;
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
export declare type MetroReloadResult = ReloadMetroResult;
|
|
1956
|
+
|
|
1936
1957
|
/** Re-export of {@link SessionRuntimeHints} under the Metro-specific alias used by public API consumers. */
|
|
1937
1958
|
declare type MetroRuntimeHints = SessionRuntimeHints;
|
|
1938
1959
|
|
|
@@ -2153,6 +2174,13 @@ declare type RefTarget_2 = {
|
|
|
2153
2174
|
selector?: never;
|
|
2154
2175
|
};
|
|
2155
2176
|
|
|
2177
|
+
declare type ReloadMetroResult = {
|
|
2178
|
+
reloaded: true;
|
|
2179
|
+
reloadUrl: string;
|
|
2180
|
+
status: number;
|
|
2181
|
+
body: string;
|
|
2182
|
+
};
|
|
2183
|
+
|
|
2156
2184
|
declare type RepeatedPressOptions = {
|
|
2157
2185
|
count?: number;
|
|
2158
2186
|
intervalMs?: number;
|
|
@@ -2164,11 +2192,13 @@ declare type RepeatedPressOptions = {
|
|
|
2164
2192
|
export declare type ReplayRunOptions = AgentDeviceRequestOverrides & {
|
|
2165
2193
|
path: string;
|
|
2166
2194
|
update?: boolean;
|
|
2195
|
+
env?: string[];
|
|
2167
2196
|
};
|
|
2168
2197
|
|
|
2169
2198
|
export declare type ReplayTestOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
|
|
2170
2199
|
paths: string[];
|
|
2171
2200
|
update?: boolean;
|
|
2201
|
+
env?: string[];
|
|
2172
2202
|
failFast?: boolean;
|
|
2173
2203
|
timeoutMs?: number;
|
|
2174
2204
|
retries?: number;
|
|
@@ -2452,6 +2482,9 @@ declare type SessionRuntimeHints = {
|
|
|
2452
2482
|
export declare type SettingsUpdateOptions = (ClientCommandBaseOptions & {
|
|
2453
2483
|
setting: 'wifi' | 'airplane' | 'location';
|
|
2454
2484
|
state: 'on' | 'off';
|
|
2485
|
+
}) | (ClientCommandBaseOptions & {
|
|
2486
|
+
setting: 'animations';
|
|
2487
|
+
state: 'on' | 'off';
|
|
2455
2488
|
}) | (ClientCommandBaseOptions & {
|
|
2456
2489
|
setting: 'appearance';
|
|
2457
2490
|
state: 'light' | 'dark' | 'toggle';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:fs";import{setTimeout as r}from"node:timers/promises";import{normalizeBaseUrl as t,
|
|
1
|
+
import e from"node:fs";import{setTimeout as r}from"node:timers/promises";import{normalizeBaseUrl as t,ENV_REGISTER_PATH as s,ENV_STATE_PATH as o,ENV_LOCAL_BASE_URL as a,ENV_SESSION as n,ENV_UNREGISTER_PATH as i,ENV_BEARER_TOKEN as c,METRO_COMPANION_RUN_ARG as f,ENV_SERVER_BASE_URL as l,ENV_LAUNCH_URL as d,ENV_SCOPE_TENANT_ID as u,ENV_SCOPE_RUN_ID as m,ENV_SCOPE_LEASE_ID as p,REACT_DEVTOOLS_COMPANION_RUN_ARG as g,ENV_DEVICE_PORT as y}from"./320.js";function w(e,r){return{authorization:`Bearer ${r}`,"content-type":"application/json",...e.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}}function h(e){return{...e.bridgeScope,...e.session?{session:e.session}:{},local_base_url:t(e.localBaseUrl),...e.devicePort?{device_port:e.devicePort}:{},...e.launchUrl?{launch_url:e.launchUrl}:{}}}async function b(e){let r,s,o=e.registerPath??"/api/metro/companion/register";try{r=await fetch(`${t(e.serverBaseUrl)}${o}`,{method:"POST",headers:w(e.serverBaseUrl,e.bearerToken),body:JSON.stringify(h(e)),signal:AbortSignal.timeout(5e3)})}catch(r){if(r instanceof Error&&"TimeoutError"===r.name)throw Error(`${o} timed out after 5000ms calling ${t(e.serverBaseUrl)}${o}`);throw r}let a=await r.text();try{s=a?JSON.parse(a):{}}catch{let e;throw Error(`Failed to register companion (${r.status}): invalid JSON response: ${(e=a.replaceAll(/\s+/g," ").trim()).length>300?`${e.slice(0,300)}...`:e}`)}if(!r.ok||!0!==s.ok||"string"!=typeof s.data?.ws_url)throw Error(`Failed to register companion (${r.status}): ${JSON.stringify(s)}`);return{wsUrl:s.data.ws_url}}async function v(e){let r=e.unregisterPath??null;if(r)try{await fetch(`${t(e.serverBaseUrl)}${r}`,{method:"POST",headers:w(e.serverBaseUrl,e.bearerToken),body:JSON.stringify(h(e)),signal:AbortSignal.timeout(2e3)})}catch(e){console.error(e instanceof Error?e.message:String(e))}}async function S(e){return"string"==typeof e?Buffer.from(e,"utf8"):e instanceof ArrayBuffer?Buffer.from(e):ArrayBuffer.isView(e)?Buffer.from(e.buffer,e.byteOffset,e.byteLength):"u">typeof Blob&&e instanceof Blob?Buffer.from(await e.arrayBuffer()):Buffer.from(String(e),"utf8")}async function E(e){return JSON.parse((await S(e.data)).toString("utf8"))}function I(e,r){1===e.readyState&&e.send(JSON.stringify(r))}async function B(e,r){1!==e.readyState&&await new Promise((t,s)=>{let o=()=>{i(),t()},a=()=>{i(),s(Error(`${r} WebSocket failed before opening.`))},n=()=>{i(),s(Error(`${r} WebSocket closed before opening.`))},i=()=>{e.removeEventListener("open",o),e.removeEventListener("error",a),e.removeEventListener("close",n)};e.addEventListener("open",o,{once:!0}),e.addEventListener("error",a,{once:!0}),e.addEventListener("close",n,{once:!0})})}async function k(e){e.readyState>=WebSocket.CLOSING||await new Promise(r=>{let t=()=>{s(),r()},s=()=>{e.removeEventListener("close",t),e.removeEventListener("error",t)};e.addEventListener("close",t,{once:!0}),e.addEventListener("error",t,{once:!0}),e.readyState>=WebSocket.CLOSING&&t()})}function L(e,r,t){try{e.close(1e3===r||r>=3e3&&r<=4999?r:3001,t)}catch{}}function U(r){return!r.statePath||e.existsSync(r.statePath)}async function $(e,r,s,o){var a,n;switch(r.type){case"ping":return void I(e,{type:"pong",timestamp:r.timestamp});case"http-request":try{let o=await fetch(new URL(r.path,`${t(s.localBaseUrl)}/`),{method:r.method,headers:r.headers,...r.bodyBase64?{body:Buffer.from(r.bodyBase64,"base64")}:{}}),a=Buffer.from(await o.arrayBuffer());I(e,{type:"http-response",requestId:r.requestId,status:o.status,headers:Object.fromEntries(o.headers.entries()),...a.length>0?{bodyBase64:a.toString("base64")}:{}})}catch(t){I(e,{type:"http-error",requestId:r.requestId,message:t instanceof Error?t.message:String(t)})}return;case"ws-open":{let n,i=new WebSocket((a=s.localBaseUrl,(n=new URL(r.path,`${t(a)}/`)).protocol="https:"===n.protocol?"wss:":"ws:",n.toString()));i.binaryType="arraybuffer";let c=!1;i.addEventListener("message",t=>{(async()=>{if(!c)return;let s=await S(t.data);I(e,{type:"ws-frame",streamId:r.streamId,dataBase64:s.toString("base64"),binary:"string"!=typeof t.data})})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),i.addEventListener("close",t=>{o.delete(r.streamId),c&&I(e,{type:"ws-close",streamId:r.streamId,code:t.code,reason:t.reason})}),i.addEventListener("error",()=>{c&&I(e,{type:"ws-close",streamId:r.streamId,code:1011,reason:"Upstream WebSocket error."})}),o.set(r.streamId,i);try{await B(i,"Upstream"),c=!0,I(e,{type:"ws-open-result",streamId:r.streamId,success:!0,headers:{}})}catch(t){o.delete(r.streamId),L(i,1011,"open failed"),I(e,{type:"ws-open-result",streamId:r.streamId,success:!1,error:t instanceof Error?t.message:String(t)})}return}case"ws-frame":{let e=o.get(r.streamId);if(!e||1!==e.readyState)return;let t=Buffer.from(r.dataBase64,"base64");e.send(r.binary?t:t.toString("utf8"));return}case"ws-close":{let e=o.get(r.streamId);if(!e)return;o.delete(r.streamId),L(e,"number"==typeof(n=r.code)&&Number.isInteger(n)&&(1e3===n||n>=3e3&&n<=4999||n>=1001&&n<=1015&&1004!==n&&1005!==n&&1006!==n)?n:1011,r.reason??"bridge requested close");return}}}async function P(e){let t=new Map,s=!1,o=null,a=!1,n=()=>{s||(s=!0,a&&v(e).finally(()=>process.exit(0)),o&&L(o,1e3,"companion stopping"),setTimeout(()=>process.exit(0),900).unref())};process.once("SIGTERM",n),process.once("SIGINT",n);let i=setInterval(()=>{U(e)||process.exit(0)},250);for(i.unref();!s&&U(e);){let n=!1;try{a=!1;let r=await b(e);if(n=!0,a=!0,s||!U(e)){await v(e),n=!1,a=!1;break}let i=new WebSocket(r.wsUrl);o=i,i.binaryType="arraybuffer";try{await B(i,"Bridge"),i.addEventListener("message",r=>{(async()=>{let s=await E(r);await $(i,s,e,t)})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),await k(i)}finally{o=null,a=!1,t.forEach(e=>L(e,1012,"bridge disconnected")),t.clear(),n&&(await v(e),n=!1)}}catch(r){if(o=null,a=!1,n&&(await v(e),n=!1),s||!U(e))break;console.error(r instanceof Error?r.message:String(r))}if(s||!U(e))break;await r(1e3)}clearInterval(i)}(async function(e,r){let t=function(e,r){let t=e[0];if(t!==f&&t!==g)return null;let w=r[l]?.trim(),h=r[c]?.trim(),b=r[a]?.trim();if(!w||!h||!b)throw Error("Metro companion worker is missing required environment configuration.");let v=r[u]?.trim(),S=r[m]?.trim(),E=r[p]?.trim();if(!v||!S||!E)throw Error("Metro companion worker is missing required bridge scope configuration.");return{serverBaseUrl:w,bearerToken:h,localBaseUrl:b,bridgeScope:{tenantId:v,runId:S,leaseId:E},launchUrl:r[d]?.trim()||void 0,statePath:r[o]?.trim()||void 0,registerPath:r[s]?.trim()||void 0,unregisterPath:r[i]?.trim()||void 0,devicePort:function(e){if(!e?.trim())return;let r=Number.parseInt(e,10);if(!Number.isInteger(r)||r<1||r>65535)throw Error("Companion worker received invalid device port configuration.");return r}(r[y]),session:r[n]?.trim()||void 0}}(e,r);return!!t&&(await P(t),!0)})(process.argv.slice(2),process.env).catch(e=>{if(e instanceof Error&&e.message.includes("missing required environment")){console.error(e.message),process.exitCode=1;return}console.error(e instanceof Error?e.stack??e.message:String(e)),process.exitCode=1});
|
package/dist/src/metro.d.ts
CHANGED
|
@@ -187,6 +187,27 @@ export declare type PrepareRemoteMetroResult = {
|
|
|
187
187
|
logPath: string;
|
|
188
188
|
};
|
|
189
189
|
|
|
190
|
+
declare type ReloadMetroOptions = {
|
|
191
|
+
metroHost?: string;
|
|
192
|
+
metroPort?: number | string;
|
|
193
|
+
bundleUrl?: string;
|
|
194
|
+
runtime?: MetroRuntimeHints;
|
|
195
|
+
timeoutMs?: number | string;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
declare type ReloadMetroResult = {
|
|
199
|
+
reloaded: true;
|
|
200
|
+
reloadUrl: string;
|
|
201
|
+
status: number;
|
|
202
|
+
body: string;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export declare function reloadRemoteMetro(options?: ReloadRemoteMetroOptions): Promise<ReloadRemoteMetroResult>;
|
|
206
|
+
|
|
207
|
+
export declare type ReloadRemoteMetroOptions = ReloadMetroOptions;
|
|
208
|
+
|
|
209
|
+
export declare type ReloadRemoteMetroResult = ReloadMetroResult;
|
|
210
|
+
|
|
190
211
|
export declare function resolveRuntimeTransport(runtime: SessionRuntimeHints | undefined): {
|
|
191
212
|
host: string;
|
|
192
213
|
port: number;
|
package/dist/src/metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildMetroRuntimeHints as e,ensureMetroCompanion as t,
|
|
1
|
+
import{buildMetroRuntimeHints as e,ensureMetroCompanion as t,reloadMetro as r,stopMetroCompanion as o,prepareMetroRuntime as n}from"./1974.js";import{resolveRuntimeTransportHints as i}from"./8656.js";function s(e){return i(e)}async function a(e){let t=await n({projectRoot:e.projectRoot,kind:e.kind,publicBaseUrl:e.publicBaseUrl,proxyBaseUrl:e.proxyBaseUrl,proxyBearerToken:e.proxyBearerToken,bridgeScope:e.bridgeScope,launchUrl:e.launchUrl,companionProfileKey:e.profileKey,companionConsumerKey:e.consumerKey,metroPort:e.port,listenHost:e.listenHost,statusHost:e.statusHost,startupTimeoutMs:e.startupTimeoutMs,probeTimeoutMs:e.probeTimeoutMs,reuseExisting:e.reuseExisting,installDependenciesIfNeeded:e.installDependenciesIfNeeded,runtimeFilePath:e.runtimeFilePath,logPath:e.logPath,env:e.env});return{iosRuntime:t.iosRuntime,androidRuntime:t.androidRuntime,bridge:t.bridge,started:t.started,reused:t.reused,logPath:t.logPath}}async function u(e){let r=await t(e);return{pid:r.pid,started:r.spawned,logPath:r.logPath}}async function l(e){await o(e)}async function d(e={}){return await r(e)}function p(t){return e(t,"ios")}function m(t){return e(t,"android")}export{buildBundleUrl,normalizeBaseUrl}from"./320.js";export{m as buildAndroidRuntimeHints,p as buildIosRuntimeHints,u as ensureMetroTunnel,a as prepareRemoteMetro,d as reloadRemoteMetro,s as resolveRuntimeTransport,l as stopMetroTunnel};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-device",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.13.1",
|
|
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
7
|
"homepage": "https://agent-device.dev/",
|
|
@@ -128,11 +128,20 @@
|
|
|
128
128
|
"agent",
|
|
129
129
|
"device",
|
|
130
130
|
"cli",
|
|
131
|
+
"automation",
|
|
131
132
|
"adb",
|
|
132
133
|
"simctl",
|
|
133
134
|
"devicectl",
|
|
134
135
|
"ios",
|
|
135
|
-
"android"
|
|
136
|
+
"android",
|
|
137
|
+
"tvos",
|
|
138
|
+
"macos",
|
|
139
|
+
"react-native",
|
|
140
|
+
"observability",
|
|
141
|
+
"diagnostics",
|
|
142
|
+
"network",
|
|
143
|
+
"profiling",
|
|
144
|
+
"performance"
|
|
136
145
|
],
|
|
137
146
|
"dependencies": {
|
|
138
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,
|
|
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
|
|
@@ -16,6 +16,7 @@ Use this skill as a router with mandatory defaults. Read this file first. For no
|
|
|
16
16
|
- Prefer `diff snapshot` after a nearby mutation when you only need to know what changed.
|
|
17
17
|
- Avoid speculative mutations. You may take the smallest reversible UI action needed to unblock inspection or complete the requested task, such as dismissing a popup, closing an alert, or clearing an unintended surface.
|
|
18
18
|
- In React Native dev or debug builds, check early for visible warning or error overlays, tooltips, and toasts that can steal focus or intercept taps. If they are not part of the requested behavior, dismiss them and continue. If you saw them, report them in the final summary.
|
|
19
|
+
- In Metro-backed React Native dev loops, use `agent-device metro reload` for a JS app reload before falling back to `open <app> --relaunch`. It mirrors pressing `r` in the Metro terminal and preserves the native app process.
|
|
19
20
|
- Do not browse the web or use external sources unless the user explicitly asks.
|
|
20
21
|
- Re-snapshot after meaningful UI changes instead of reusing stale refs.
|
|
21
22
|
- Treat refs in default snapshot output as actionable-now, not durable identities. If a target appears only in an off-screen summary, use `scroll <direction>` and re-snapshot until the target is visible.
|
|
@@ -60,6 +61,7 @@ Use this skill as a router with mandatory defaults. Read this file first. For no
|
|
|
60
61
|
- If there is no simulator, no app install, or no open app session yet, switch to `bootstrap-install.md` instead of improvising setup steps.
|
|
61
62
|
- Use the smallest unblock action first when transient UI blocks inspection, but do not navigate, search, or enter new text just to make the UI reveal data unless the user asked for that interaction.
|
|
62
63
|
- In React Native dev or debug apps, treat visible warning or error overlays as transient blockers unless the user is explicitly asking you to diagnose them. Dismiss them when safe, then continue the requested flow.
|
|
64
|
+
- For React Native code changes where the app is already connected to Metro, prefer `agent-device metro reload`, then wait and re-snapshot. Use `open <app> --relaunch` only when Metro reload does not reconnect or native startup state must reset.
|
|
63
65
|
- Do not use external lookups to compensate for missing on-screen data unless the user asked for them.
|
|
64
66
|
- If the needed information is not exposed on screen, say that plainly instead of compensating with extra navigation, text entry, or web search.
|
|
65
67
|
- Prefer `@ref` or selector targeting over raw coordinates.
|
|
@@ -71,3 +73,4 @@ Use this skill as a router with mandatory defaults. Read this file first. For no
|
|
|
71
73
|
- Need desktop surfaces, menu bar behavior, or macOS-specific interaction rules: [references/macos-desktop.md](references/macos-desktop.md)
|
|
72
74
|
- Need remote HTTP transport, `connect --remote-config`, or tenant leases on a remote macOS host: [references/remote-tenancy.md](references/remote-tenancy.md)
|
|
73
75
|
This includes remote React Native runs where `agent-device` now prepares Metro locally and manages the local Metro companion tunnel automatically.
|
|
76
|
+
- 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).
|
|
@@ -18,6 +18,7 @@ Use this exact order when you are not sure about the installed app identifier. O
|
|
|
18
18
|
|
|
19
19
|
- `install` or `reinstall`
|
|
20
20
|
- `install-from-source` when the artifact already exists at a URL the daemon can reach
|
|
21
|
+
- `install-from-source --github-actions-artifact` when a compatible remote daemon should resolve a GitHub Actions artifact
|
|
21
22
|
|
|
22
23
|
## Most common mistake to avoid
|
|
23
24
|
|
|
@@ -35,8 +36,6 @@ After setup is confirmed or completed, move to `exploration.md` before doing UI
|
|
|
35
36
|
- If `open <app>` fails, run `agent-device apps` and retry with a discovered app name before considering install steps.
|
|
36
37
|
- Do not install or reinstall on the first attempt unless the user explicitly asks for installation or provides a concrete artifact path or URL.
|
|
37
38
|
- When installation is required from a known location, prefer a checked-in shell script or other deterministic bootstrap command over ad hoc path guessing.
|
|
38
|
-
|
|
39
|
-
- If `open <app>` fails, or you are not sure which app name is available on the target, run `agent-device apps` first and choose from the discovered app list instead of guessing.
|
|
40
39
|
- Use `apps --platform <platform>` together with `--device`, `--udid`, or `--serial` when target selection matters.
|
|
41
40
|
- Once you have the correct app name, retry `open` with that exact discovered value.
|
|
42
41
|
|
|
@@ -64,8 +63,27 @@ agent-device install com.example.app ./build/MyApp.app --platform ios --device "
|
|
|
64
63
|
```bash
|
|
65
64
|
ARTIFACT_URL="<trusted-artifact-url>"
|
|
66
65
|
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Daemon-resolved GitHub Actions artifacts:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
agent-device install-from-source \
|
|
72
|
+
--github-actions-artifact ORG/REPO:1234567890 \
|
|
73
|
+
--platform android
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Project config can provide an artifact name instead:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"platform": "android",
|
|
81
|
+
"installSource": {
|
|
82
|
+
"type": "github-actions-artifact",
|
|
83
|
+
"repo": "ORG/REPO",
|
|
84
|
+
"artifact": "app-debug"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
69
87
|
```
|
|
70
88
|
|
|
71
89
|
## Install guidance
|
|
@@ -73,6 +91,7 @@ agent-device install-from-source "$GITHUB_ARTIFACT_URL" --platform ios --header
|
|
|
73
91
|
- Use `install <app> <path>` when the app may already be installed and you do not need a fresh-state reset.
|
|
74
92
|
- Use `reinstall <app> <path>` when you explicitly need uninstall plus install as one deterministic step.
|
|
75
93
|
- Use `install-from-source <url>` only when an existing artifact URL is trusted, operator-approved, and reachable by the daemon.
|
|
94
|
+
- Use `--github-actions-artifact <org>/<repo>:<artifact>` when a compatible remote daemon should resolve a GitHub Actions artifact. Numeric artifacts are IDs; non-numeric artifacts are names.
|
|
76
95
|
- Local `.apk`, `.aab`, `.app`, and `.ipa` paths go through `install` or `reinstall`; existing reachable URLs go through `install-from-source`.
|
|
77
96
|
- Do not download, re-zip, publish temporary GitHub releases, or move CI artifacts elsewhere just to make an install command work.
|
|
78
97
|
- Keep install and open as separate phases. Do not turn them into one default command flow.
|
|
@@ -80,10 +99,10 @@ agent-device install-from-source "$GITHUB_ARTIFACT_URL" --platform ios --header
|
|
|
80
99
|
- Android: `.apk` and `.aab`
|
|
81
100
|
- iOS: `.app` and `.ipa`
|
|
82
101
|
- Android URL sources can be direct `.apk` or `.aab` files.
|
|
83
|
-
- Trusted artifact service URLs
|
|
102
|
+
- Trusted artifact service URLs may point at archive-backed downloads that contain one installable artifact. Prefer `--github-actions-artifact` for GitHub Actions artifacts that a compatible remote daemon can resolve with its own credentials.
|
|
84
103
|
- If a trusted artifact archive contains multiple installables, stop and ask for the intended artifact instead of guessing.
|
|
85
104
|
- `.aab` still requires `bundletool` in `PATH`, or `AGENT_DEVICE_BUNDLETOOL_JAR=<absolute-path-to-bundletool-all.jar>` with `java` in `PATH`, when the daemon installs the materialized artifact.
|
|
86
|
-
- For
|
|
105
|
+
- For `.ipa` archives with multiple app bundles, `<app>` is the bundle id or bundle name selection hint.
|
|
87
106
|
- After install or reinstall, later use `open <app>` with the exact discovered or known package/bundle identifier, not the artifact path.
|
|
88
107
|
|
|
89
108
|
## Choose the right starting point
|
|
@@ -115,6 +134,7 @@ agent-device --session auth snapshot -i
|
|
|
115
134
|
- Use semantic session names when you need multiple concurrent runs.
|
|
116
135
|
- Use `--save-script=<path>` on `close` when you want to keep a replay script.
|
|
117
136
|
- For dev loops where state can linger, prefer `open <app> --relaunch`.
|
|
137
|
+
- For Metro-backed React Native JS changes with the app already running, prefer `metro reload` instead of `open <app> --relaunch`; it asks Metro to reload connected apps without restarting the native process.
|
|
118
138
|
- In iOS sessions, use `open <app>` for the app itself. Use `open <url>` for deep links, and `open <app> <url>` when you need to launch the app and deep link in one step.
|
|
119
139
|
- On iOS, `appstate` is session-scoped and requires the matching active session on the target device.
|
|
120
140
|
|
|
@@ -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
|
|
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,8 @@ 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
|
|
24
|
+
- User asks to reload a Metro-backed React Native app after JS changes: `agent-device metro reload`, then wait briefly and re-run `snapshot` or `snapshot -i`
|
|
23
25
|
- 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
26
|
- 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
27
|
- UI does not expose the answer: say so plainly; do not browse or force the app into a new state unless asked
|
|
@@ -49,8 +51,9 @@ Open this file when the app or screen is already running and you need to discove
|
|
|
49
51
|
**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
52
|
|
|
51
53
|
1. Trust the screenshot as visual truth.
|
|
52
|
-
2. Take one fresh `snapshot -i`. Android retries
|
|
54
|
+
2. Take one fresh `snapshot -i`. Android retries suspicious trees for a short post-action deadline after navigation-sensitive actions.
|
|
53
55
|
3. If the tree still disagrees with the screenshot, wait briefly, then take one more fresh snapshot. Do not loop snapshots immediately.
|
|
56
|
+
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
57
|
|
|
55
58
|
**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
59
|
|
|
@@ -58,6 +61,16 @@ Open this file when the app or screen is already running and you need to discove
|
|
|
58
61
|
- Blocking or recurring: switch to [debugging.md](debugging.md) and collect evidence.
|
|
59
62
|
- Seen at any point: mention in the final summary even if dismissed.
|
|
60
63
|
|
|
64
|
+
**React Native Metro reload.** When a dev app is already running and connected to Metro, prefer a Metro reload over restarting the native app process:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
agent-device metro reload
|
|
68
|
+
agent-device wait 1000
|
|
69
|
+
agent-device snapshot -i
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use `--metro-host`, `--metro-port`, or `--bundle-url` only when the active connection does not already carry the right runtime hints. Fall back to `open <app> --relaunch` when the app is not connected to Metro, Metro reload fails, or native startup state needs a clean process.
|
|
73
|
+
|
|
61
74
|
## Common example loops
|
|
62
75
|
|
|
63
76
|
These are examples, not required exact sequences. Adapt them to the app, state, and task at hand.
|
|
@@ -222,7 +235,7 @@ Preferred mapping:
|
|
|
222
235
|
Notes:
|
|
223
236
|
|
|
224
237
|
- `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
|
|
238
|
+
- 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
239
|
|
|
227
240
|
Anti-hallucination rules:
|
|
228
241
|
|
|
@@ -8,7 +8,9 @@ Open this file for remote daemon HTTP flows that let an agent running in a Linux
|
|
|
8
8
|
|
|
9
9
|
- `agent-device connect --remote-config <path>`
|
|
10
10
|
- `agent-device install-from-source <url> --remote-config <path> --platform android`
|
|
11
|
+
- `agent-device install-from-source --github-actions-artifact <org>/<repo>:<artifact> --remote-config <path> --platform android`
|
|
11
12
|
- `agent-device open <package> --remote-config <path> --relaunch`
|
|
13
|
+
- `agent-device metro reload --remote-config <path>`
|
|
12
14
|
- `agent-device snapshot --remote-config <path> -i`
|
|
13
15
|
- `agent-device disconnect --remote-config <path>`
|
|
14
16
|
- `agent-device connection status`
|
|
@@ -36,6 +38,7 @@ agent-device connect --remote-config ./remote-config.json
|
|
|
36
38
|
ARTIFACT_URL="<trusted-artifact-url>"
|
|
37
39
|
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
38
40
|
agent-device open com.example.app --relaunch
|
|
41
|
+
agent-device metro reload
|
|
39
42
|
agent-device snapshot -i
|
|
40
43
|
agent-device fill @e3 "test@example.com"
|
|
41
44
|
agent-device disconnect
|
|
@@ -73,6 +76,7 @@ The first command that needs a lease or Metro runtime prepares and persists it.
|
|
|
73
76
|
- `connect` stores local non-secret connection state and defers tenant lease allocation plus Metro preparation until a later command needs them.
|
|
74
77
|
- Commands such as `install-from-source`, `open`, `snapshot`, and `apps` allocate or refresh the lease when needed.
|
|
75
78
|
- `open` prepares Metro runtime hints when the remote profile has Metro fields and no compatible runtime is already saved.
|
|
79
|
+
- `metro reload` reuses saved Metro runtime hints and asks Metro to reload connected React Native apps without restarting the native process.
|
|
76
80
|
- `batch` also prepares Metro when any step opens an app and that step does not provide its own runtime.
|
|
77
81
|
- `disconnect` closes the session when possible, stops the Metro companion owned by the connection, releases the lease when one was allocated, and removes local connection state.
|
|
78
82
|
|
|
@@ -82,12 +86,11 @@ Remote install examples:
|
|
|
82
86
|
agent-device install com.example.app ./app.apk
|
|
83
87
|
ARTIFACT_URL="<trusted-artifact-url>"
|
|
84
88
|
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
85
|
-
GITHUB_ARTIFACT_URL="<trusted-github-actions-artifact-api-url>"
|
|
86
|
-
agent-device install-from-source "$GITHUB_ARTIFACT_URL" --platform ios --header "authorization: Bearer TOKEN"
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
- Use `install` or `reinstall` for local paths; remote daemons upload local artifacts automatically.
|
|
90
92
|
- Use `install-from-source` only for trusted, operator-approved artifact URLs the remote daemon can reach. Do not fetch arbitrary user-supplied URLs.
|
|
93
|
+
- Use `install-from-source --github-actions-artifact <org>/<repo>:<artifact>` when the remote daemon has repository credentials and supports daemon-resolved GitHub Actions artifacts.
|
|
91
94
|
- For local-path versus URL artifact rules, follow [bootstrap-install.md](bootstrap-install.md).
|
|
92
95
|
|
|
93
96
|
Use `agent-device connection status --session adc-android` to inspect the active connection without reading JSON state manually. Status output must not include auth tokens.
|
|
@@ -135,30 +138,47 @@ Optional overrides stay available for advanced cases:
|
|
|
135
138
|
- Start the daemon in HTTP mode with `AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual` on the host.
|
|
136
139
|
- Point the profile or env at the remote host with `daemonBaseUrl` or `AGENT_DEVICE_DAEMON_BASE_URL=http(s)://host:port[/base-path]`.
|
|
137
140
|
- For non-loopback remote hosts, set `AGENT_DEVICE_DAEMON_AUTH_TOKEN` or `--daemon-auth-token`. The client rejects non-loopback remote daemon URLs without auth.
|
|
138
|
-
- Direct JSON-RPC callers can authenticate with request params, `Authorization: Bearer <token>`, or `x-agent-device-token`.
|
|
139
141
|
- Prefer an auth hook such as `AGENT_DEVICE_HTTP_AUTH_HOOK` when the host needs caller validation or tenant injection.
|
|
140
142
|
|
|
141
|
-
##
|
|
143
|
+
## Lease debug fallback
|
|
142
144
|
|
|
143
|
-
The main agent flow should use `connect
|
|
145
|
+
The main agent flow should use `connect` and `connection status`. For daemon-side auth, scope, or lease debugging, inspect host-side daemon logs and operator tooling instead of issuing raw daemon RPC from the agent shell.
|
|
146
|
+
|
|
147
|
+
## GitHub Actions artifact install
|
|
148
|
+
|
|
149
|
+
Use this when a compatible remote daemon resolves GitHub Actions artifacts server-side. Do not download CI artifacts locally or add a local `GITHUB_TOKEN` just to install CI output.
|
|
150
|
+
|
|
151
|
+
Artifact ID shape:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
agent-device install-from-source \
|
|
155
|
+
--github-actions-artifact OWNER/REPO:1234567890 \
|
|
156
|
+
--remote-config ./remote-config.json \
|
|
157
|
+
--platform android
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Artifact-name shape:
|
|
144
161
|
|
|
145
162
|
```bash
|
|
146
|
-
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
agent-device install-from-source \
|
|
164
|
+
--github-actions-artifact OWNER/REPO:app-debug \
|
|
165
|
+
--remote-config ./remote-config.json \
|
|
166
|
+
--platform ios
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Config shape:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"installSource": {
|
|
174
|
+
"type": "github-actions-artifact",
|
|
175
|
+
"repo": "OWNER/REPO",
|
|
176
|
+
"artifact": "app-debug"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
159
179
|
```
|
|
160
180
|
|
|
161
|
-
|
|
181
|
+
Numeric artifacts are passed as artifact IDs. Non-numeric artifacts are passed as artifact names.
|
|
162
182
|
|
|
163
183
|
## Failure semantics and trust notes
|
|
164
184
|
|
|
@@ -129,5 +129,6 @@ agent-device perf --json
|
|
|
129
129
|
- `startup` is command round-trip timing around `open`.
|
|
130
130
|
- It is not true first-frame or first-interactive telemetry.
|
|
131
131
|
- Android app sessions also expose `memory` (`dumpsys meminfo`) and `cpu` (`dumpsys cpuinfo`) snapshots when the session has an app package context.
|
|
132
|
-
- Apple app sessions on macOS and iOS
|
|
133
|
-
- `
|
|
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.
|
package/skills/dogfood/SKILL.md
CHANGED
|
@@ -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,55 @@
|
|
|
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
|
+
- For Android sessions connected through `agent-device connect --remote-config`, run `agent-device react-devtools ...` normally. The CLI registers a bridge companion tunnel to the local DevTools daemon on `127.0.0.1:8097` and unregisters it when the command exits.
|
|
48
|
+
- Remote Android React DevTools assumes the React Native-bundled DevTools behavior in React Native 0.83+. Do not assume older browser/Chromium DevTools workflows exist in remote sandboxes. For Expo apps, verify the SDK's bundled React Native version and runtime behavior first; no Expo SDK version is separately verified by this skill.
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
|
|
52
|
+
| File | When to read |
|
|
53
|
+
| --------------------------------------- | --------------------------------------------- |
|
|
54
|
+
| [commands.md](references/commands.md) | Command reference and common inspection flows |
|
|
55
|
+
| [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
|
+
```
|