@swmansion/argent 0.28.1-next.9 → 0.29.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.
- package/agents/argent-environment-inspector.md +7 -7
- package/agents/references/quality-control-checklist.md +14 -14
- package/assets/manifest.json +2 -2
- package/bin/argent-android-devtools-0.3.0.apk +0 -0
- package/bin/darwin/ax-service +0 -0
- package/bin/darwin/simulator-server +0 -0
- package/bin/darwin/tvos-ax-service +0 -0
- package/bin/darwin/tvos-hid-daemon +0 -0
- package/bin/linux/simulator-server +0 -0
- package/bin/linux-arm64/simulator-server +0 -0
- package/bin/tcp/ax-service +0 -0
- package/bin/win32/simulator-server.exe +0 -0
- package/dist/cli-cmds.mjs +4 -1
- package/dist/client.d.ts +18 -0
- package/dist/client.js +3 -0
- package/dist/installer.mjs +9 -2
- package/dist/mcp-server.mjs +13 -1
- package/dist/tool-args.generated.d.ts +87 -77
- package/dist/tool-server.cjs +947 -370
- package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/libKeyboardPatch.dylib +0 -0
- package/dylibs/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
- package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
- package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
- package/package.json +1 -1
- package/rules/argent.md +16 -16
- package/skills/argent-android-emulator-setup/SKILL.md +9 -9
- package/skills/argent-create-flow/references/flow-yaml.md +11 -11
- package/skills/argent-create-flow/references/live-authoring.md +11 -11
- package/skills/argent-create-flow/references/reliability-and-recovery.md +13 -13
- package/skills/argent-device-interact/SKILL.md +47 -47
- package/skills/argent-device-interact/references/chromium.md +1 -1
- package/skills/argent-device-interact/references/gesture-examples.md +7 -7
- package/skills/argent-device-interact/references/secrets.md +6 -6
- package/skills/argent-lens/SKILL.md +21 -21
- package/skills/argent-metro-debugger/SKILL.md +24 -24
- package/skills/argent-metro-debugger/references/failure-scenarios.md +11 -11
- package/skills/argent-metro-debugger/references/source-maps.md +4 -4
- package/skills/argent-native-profiler/SKILL.md +13 -13
- package/skills/argent-qa-flows/SKILL.md +3 -3
- package/skills/argent-react-native-app-workflow/SKILL.md +18 -18
- package/skills/argent-react-native-optimization/SKILL.md +12 -12
- package/skills/argent-react-native-optimization/references/fix-reference.md +10 -10
- package/skills/argent-react-native-optimization/references/lint-rules.md +1 -1
- package/skills/argent-react-native-profiler/SKILL.md +25 -25
- package/skills/argent-react-native-profiler/references/diagnostic-tools.md +19 -19
- package/skills/argent-screen-recording/SKILL.md +14 -14
- package/skills/argent-test-ui-flow/SKILL.md +9 -9
- package/skills/argent-tv-interact/SKILL.md +19 -19
- package/bin/argent-android-devtools-0.2.0.apk +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Failure Scenarios: Recovery Steps
|
|
2
2
|
|
|
3
|
-
When a debugger tool fails, use **`debugger-status`** first to diagnose. Note: `debugger-status` and `debugger-log-registry` do **not** fail when the debugger is simply unreachable
|
|
3
|
+
When a debugger tool fails, use **`debugger-status`** first to diagnose. Note: `debugger-status` and `debugger-log-registry` do **not** fail when the debugger is simply unreachable: they return `{ status: "not_connected", reason, detail, guidance }` (the `detail` field carries the same error text other tools throw). Do not retry the same failing tool repeatedly without following the recovery steps.
|
|
4
4
|
|
|
5
|
-
| Scenario | Error or situation | What to do
|
|
6
|
-
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
-
| **Metro not running** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 is not running (got: ...)` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "metro_not_running", guidance }` here instead of erroring; other debugger tools still throw. **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status` once
|
|
8
|
-
| **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless
|
|
9
|
-
| **App not connected** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "no_app_connected", guidance }` here instead of erroring; other debugger tools still throw. 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status` once. Do **not** use `debugger-reload-metro` to fix this
|
|
10
|
-
| **Wrong device id** | `debugger-status` / `debugger-log-registry` return `reason: "device_mismatch"`, or `debugger-connect` fails with `DEBUGGER_TARGET_DEVICE_MISMATCH` | The `device_id` matches no debugger target on this Metro. Re-target with the `logicalDeviceId` listed in the `detail` / error message, or give the device its own Metro port. Do not retry with the same `device_id
|
|
11
|
-
| **Stale connection** | `debugger-status` returns `reason: "stale_connection"` | The cached debugger connection was no longer open; `debugger-status` has already discarded it. Use `restart-app` if the app is not running, then call `debugger-connect
|
|
12
|
-
| **Reconnecting** | `debugger-status` / `debugger-log-registry` return `reason: "reconnecting"` | A reconnect is in flight
|
|
13
|
-
| **Runtime unresponsive** | `reason: "runtime_unresponsive"`, or another debugger tool fails with `DEBUGGER_CDP_REQUEST_TIMEOUT` | Follow the `guidance` / error text
|
|
14
|
-
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls.
|
|
5
|
+
| Scenario | Error or situation | What to do |
|
|
6
|
+
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
7
|
+
| **Metro not running** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 is not running (got: ...)` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "metro_not_running", guidance }` here instead of erroring; other debugger tools still throw. **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status` once, not in a loop. If you cannot determine the project root, ask the user. A non-Metro server occupying the port lands here too; the `got:` text shows what answered. |
|
|
8
|
+
| **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless; do not restart Metro to "fix" it. |
|
|
9
|
+
| **App not connected** | Error (or `not_connected` `detail`) contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | `debugger-status` / `debugger-log-registry` return `{ status: "not_connected", reason: "no_app_connected", guidance }` here instead of erroring; other debugger tools still throw. 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status` once. Do **not** use `debugger-reload-metro` to fix this; it also requires at least one target. |
|
|
10
|
+
| **Wrong device id** | `debugger-status` / `debugger-log-registry` return `reason: "device_mismatch"`, or `debugger-connect` fails with `DEBUGGER_TARGET_DEVICE_MISMATCH` | The `device_id` matches no debugger target on this Metro. Re-target with the `logicalDeviceId` listed in the `detail` / error message, or give the device its own Metro port. Do not retry with the same `device_id`; the result will not change. |
|
|
11
|
+
| **Stale connection** | `debugger-status` returns `reason: "stale_connection"` | The cached debugger connection was no longer open; `debugger-status` has already discarded it. Use `restart-app` if the app is not running, then call `debugger-connect`; the next call reconnects fresh. |
|
|
12
|
+
| **Reconnecting** | `debugger-status` / `debugger-log-registry` return `reason: "reconnecting"` | A reconnect is in flight: the previous connection was just torn down, or (Chromium) a tab switch is in progress. Transient: wait a moment and retry once. Do **not** restart the app for this. |
|
|
13
|
+
| **Runtime unresponsive** | `reason: "runtime_unresponsive"`, or another debugger tool fails with `DEBUGGER_CDP_REQUEST_TIMEOUT` | Follow the `guidance` / error text; it explains the state and the recovery. Each attempt waits out the full CDP timeout, so never retry in a loop. |
|
|
14
|
+
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls. |
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
`debugger-inspect-element` tries to resolve each component in the hierarchy to its source file and line. It uses a fallback chain:
|
|
4
4
|
|
|
5
|
-
1. **`_debugStack`** (React fiber property)
|
|
6
|
-
2. **`_debugSource`** (React fiber property)
|
|
7
|
-
3. **Neither available
|
|
5
|
+
1. **`_debugStack`** (React fiber property): a stack trace string from the bundled code. When available, the tool symbolicates it via Metro's `/symbolicate` endpoint to resolve to the original source file, then reads a code fragment from disk. Set `resolveSourceMaps: false` to skip symbolication and return raw bundled locations instead.
|
|
6
|
+
2. **`_debugSource`** (React fiber property): contains `{ fileName, lineNumber, columnNumber }` pointing directly to the original source file. No symbolication needed. The tool reads the code fragment from disk automatically.
|
|
7
|
+
3. **Neither available**: the tool returns the component hierarchy with `source: null` and `code: null` for all items. The hierarchy (component names) is still useful.
|
|
8
8
|
|
|
9
9
|
## When Source Info Is Missing
|
|
10
10
|
|
|
@@ -24,4 +24,4 @@ module.exports = function (api) {
|
|
|
24
24
|
};
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
After adding the plugin, restart Metro (`npx react-native start --reset-cache` or `npx expo start --clear`) and reload the app. No extra `npm install` needed
|
|
27
|
+
After adding the plugin, restart Metro (`npx react-native start --reset-cache` or `npx expo start --clear`) and reload the app. No extra `npm install` needed; the plugin ships with `babel-preset-expo` and `@babel/preset-env`.
|
|
@@ -5,11 +5,11 @@ description: Native profiling for CPU hotspots, UI hangs, memory issues. iOS via
|
|
|
5
5
|
|
|
6
6
|
## 1. Tools
|
|
7
7
|
|
|
8
|
-
- `native-profiler-start
|
|
9
|
-
- `native-profiler-stop
|
|
10
|
-
- `native-profiler-analyze
|
|
11
|
-
- `profiler-stack-query
|
|
12
|
-
- `profiler-load
|
|
8
|
+
- `native-profiler-start`: start profiling on a booted device. iOS: xctrace recording for CPU, hangs, and leaks.
|
|
9
|
+
- `native-profiler-stop`: stop the profiler and export trace data to timestamped XML files.
|
|
10
|
+
- `native-profiler-analyze`: parse exported trace data and return a structured bottleneck payload.
|
|
11
|
+
- `profiler-stack-query`: drill into parsed data: hang stacks, function callers, thread breakdown, leak details.
|
|
12
|
+
- `profiler-load`: list and reload previous trace sessions from disk for re-investigation.
|
|
13
13
|
- Physical iPhone: not supported; use a simulator.
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -28,7 +28,7 @@ After `native-profiler-analyze` surfaces findings, use `profiler-stack-query` to
|
|
|
28
28
|
- **Hang detected** → `profiler-stack-query` mode=`hang_stacks` for full native call chains → mode=`function_callers` for the suspected function → read native source.
|
|
29
29
|
- **CPU hotspot** → `profiler-stack-query` mode=`thread_breakdown` for per-thread distribution → mode=`function_callers` for the dominant function.
|
|
30
30
|
- **Memory leak** → `profiler-stack-query` mode=`leak_stacks` filtered by `object_type` for responsible frames and libraries.
|
|
31
|
-
- iOS: if leaks come back unattributed (responsible frame `<Call stack limit reached>`), re-run `native-profiler-start` with `malloc_stack_logging: true`. This cold-launches the app with Malloc Stack Logging so leaks carry a real allocation backtrace (responsible frame + library). It restarts the app and adds overhead, so use it only when you need leak attribution
|
|
31
|
+
- iOS: if leaks come back unattributed (responsible frame `<Call stack limit reached>`), re-run `native-profiler-start` with `malloc_stack_logging: true`. This cold-launches the app with Malloc Stack Logging so leaks carry a real allocation backtrace (responsible frame + library). It restarts the app and adds overhead, so use it only when you need leak attribution, not for CPU/hang passes.
|
|
32
32
|
|
|
33
33
|
After presenting findings, ask the user whether to investigate further, implement fixes, or stop. After applying fixes, always re-profile the same scenario and compare with `profiler-load`. Report honestly whether the target metric improved, regressed, or stayed flat. If the fix showed no net benefit or introduced regressions elsewhere, say so and reconsider.
|
|
34
34
|
|
|
@@ -40,12 +40,12 @@ After presenting findings, ask the user whether to investigate further, implemen
|
|
|
40
40
|
|
|
41
41
|
## 4. Workflow
|
|
42
42
|
|
|
43
|
-
**Complete all steps in order
|
|
43
|
+
**Complete all steps in order; do not break mid-flow.**
|
|
44
44
|
|
|
45
45
|
### Step 0: Ensure the target app is running
|
|
46
46
|
|
|
47
47
|
The `native-profiler-start` tool **auto-detects** the running app on the device.
|
|
48
|
-
You do not need to derive `app_process` manually
|
|
48
|
+
You do not need to derive `app_process` manually; just make sure the app is launched.
|
|
49
49
|
|
|
50
50
|
1. If the app is already running on the device, skip to Step 1 (do not pass `app_process`).
|
|
51
51
|
2. If the app is not running, use `launch-app` with the correct bundle ID first.
|
|
@@ -60,7 +60,7 @@ Let the user interact with the app or drive interaction via simulator tools (see
|
|
|
60
60
|
|
|
61
61
|
### Step 2: Stop and export
|
|
62
62
|
|
|
63
|
-
Call `native-profiler-stop` with `device_id`. iOS sends SIGINT to xctrace, waits for trace packaging, and exports CPU, hangs, and leaks data to XML
|
|
63
|
+
Call `native-profiler-stop` with `device_id`. iOS sends SIGINT to xctrace, waits for trace packaging, and exports CPU, hangs, and leaks data to XML; check `exportDiagnostics` for any export warnings. Android sends SIGTERM to the on-device perfetto daemon, polls `/proc/<pid>` until it exits, then `adb pull`s the `.pftrace` to the host.
|
|
64
64
|
|
|
65
65
|
### Step 3: Analyze
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ Call `native-profiler-analyze` with `device_id`. Returns a markdown report with
|
|
|
68
68
|
|
|
69
69
|
### Step 4: Present findings and ask about next steps
|
|
70
70
|
|
|
71
|
-
Present a concise summary of the key findings. Then follow the "After analysis" guideline
|
|
71
|
+
Present a concise summary of the key findings. Then follow the "After analysis" guideline: ask whether to investigate further with query tools, implement fixes, or stop.
|
|
72
72
|
|
|
73
73
|
### Step 5: Drill-down investigation
|
|
74
74
|
|
|
@@ -89,13 +89,13 @@ To revisit a previous trace:
|
|
|
89
89
|
Bottlenecks are categorized by severity:
|
|
90
90
|
|
|
91
91
|
- **RED**: CPU functions taking >15% of total time, all UI hangs, and **attributed** memory leaks (those with a resolved responsible frame). These require immediate attention.
|
|
92
|
-
- **YELLOW**: CPU functions taking 3-15% of total time, and **unattributed** memory leaks (`<Call stack limit reached>`, no library
|
|
92
|
+
- **YELLOW**: CPU functions taking 3-15% of total time, and **unattributed** memory leaks (`<Call stack limit reached>`, no library; see the memory-leaks caveat below). Worth investigating but may be acceptable.
|
|
93
93
|
|
|
94
94
|
Each bottleneck type indicates a different class of problem:
|
|
95
95
|
|
|
96
96
|
- **CPU hotspots**: Native functions consuming excessive CPU time. Look for tight loops, expensive computations, or redundant work.
|
|
97
97
|
- **UI hangs**: Main thread blocked long enough to cause visible jank or unresponsiveness. Often caused by synchronous I/O, heavy layout passes, or lock contention.
|
|
98
|
-
- **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers. Argent records via `xctrace --attach`, which has no malloc-stack history, so on the simulator most leaks come back **unattributed** (`<Call stack limit reached>`, no library) and are dominated by benign system allocations
|
|
98
|
+
- **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers. Argent records via `xctrace --attach`, which has no malloc-stack history, so on the simulator most leaks come back **unattributed** (`<Call stack limit reached>`, no library) and are dominated by benign system allocations; these are reported as a low-confidence YELLOW summary, not confirmed RED leaks. For attributed stacks, capture with malloc stack logging enabled at launch.
|
|
99
99
|
|
|
100
100
|
---
|
|
101
101
|
|
|
@@ -103,6 +103,6 @@ Each bottleneck type indicates a different class of problem:
|
|
|
103
103
|
|
|
104
104
|
- **Simulator vs device**: Simulator profiling reflects host Mac performance, not real device hardware. Use device profiling for accurate CPU timings and memory behavior.
|
|
105
105
|
- **xctrace availability (iOS)**: Requires Xcode command-line tools installed. Verify with `xcrun xctrace version`.
|
|
106
|
-
- **Profiler overhead**: xctrace instrumentation adds CPU load. If `JSLexer`, `JSONEmitter`, or Hermes runtime internals dominate the JS thread in CPU hotspot results, those reflect profiler overhead
|
|
106
|
+
- **Profiler overhead**: xctrace instrumentation adds CPU load. If `JSLexer`, `JSONEmitter`, or Hermes runtime internals dominate the JS thread in CPU hotspot results, those reflect profiler overhead, not app work. Discount those entries when evaluating findings.
|
|
107
107
|
- **Run-to-run variance**: Small fluctuations in CPU percentages between runs are normal. Treat only consistent directional changes (across 2+ runs or >15% delta) as actionable signal.
|
|
108
108
|
- **Live data variability**: If the app fetches live API data, different responses between runs change rendering workload independently of code changes. Note when data-dependent screens show variance.
|
|
@@ -106,9 +106,9 @@ After the last edit and audit, set the streak to zero:
|
|
|
106
106
|
|
|
107
107
|
1. Choose one runner for both passes. Use `flow-execute` locally or `argent flow run <name> --platform <platform>` for CI. Switching runners resets the streak.
|
|
108
108
|
2. Seed, review, and freeze snapshot baselines. Baseline updates do not count as passes.
|
|
109
|
-
3. Before mobile pass 1, recycle Argent services for this flow's device: two warm passes are correlated evidence, because a fixed timing margin can pass twice simply because environment speed did not change. Scope `stop-all-simulator-servers` to `devices: [<device>]`. Never omit the scope
|
|
110
|
-
4. Run from the flow's launch and setup without baseline-update mode. Count a pass only when `ok: true` and every acceptance check executed. A false `when:` can skip optional setup only. An errored step does not advance the streak, and the count mixes two kinds
|
|
111
|
-
5. Resolve every passing-step warning before completion. Also resolve recorded-wait warnings from `flow-finish-recording`. Follow [Live waits and checks](../argent-create-flow/references/live-authoring.md#live-waits-and-checks). For runner warnings, `await: { idle: true }` raises [six different warnings](../argent-create-flow/references/flow-yaml.md#idle-readiness), so read which one it is first. Two say the screen was moving. One says the wait ran out mid-hold and needs a larger `timeout:`. One says the tree stayed empty. One
|
|
109
|
+
3. Before mobile pass 1, recycle Argent services for this flow's device: two warm passes are correlated evidence, because a fixed timing margin can pass twice simply because environment speed did not change. Scope `stop-all-simulator-servers` to `devices: [<device>]`. Never omit the scope: a bare call is the machine-wide sweep, and step 7 restarts this proof often enough to reap every other agent's devices repeatedly. Use the MCP call for `flow-execute`, or `argent run stop-all-simulator-servers --devices <device>` from the standalone runner's install. The reset must not change app or account data. For Chromium, let the runner boot the declared app and omit `device`. Vega owns no recyclable Argent services, so the teardown is a no-op there and both passes are warm.
|
|
110
|
+
4. Run from the flow's launch and setup without baseline-update mode. Count a pass only when `ok: true` and every acceptance check executed. A false `when:` can skip optional setup only. An errored step does not advance the streak, and the count mixes two kinds: read each reason. One that could not run (an unreadable tree under `idle`, an unresolvable `run:` target) is environment: fix it and rerun. **A failed `launch:` also scores `errored`, and it is a verdict about the app**; an app that no longer installs or starts is the regression this test exists to catch, so report it instead of rerunning.
|
|
111
|
+
5. Resolve every passing-step warning before completion. Also resolve recorded-wait warnings from `flow-finish-recording`. Follow [Live waits and checks](../argent-create-flow/references/live-authoring.md#live-waits-and-checks). For runner warnings, `await: { idle: true }` raises [six different warnings](../argent-create-flow/references/flow-yaml.md#idle-readiness), so read which one it is first. Two say the screen was moving. One says the wait ran out mid-hold and needs a larger `timeout:`. One says the tree stayed empty. One, **settled on the UI tree alone**, says the hierarchy did hold still and only the screenshot pairs were missing, so inspect the capture path rather than the app's rendering. One says the step ended with no evidence either way. Inspect the screen, disclose the cause, and verify that surrounding acceptance checks use stable elements rather than stillness. A [selector-less gesture](../argent-create-flow/references/flow-yaml.md#directives) (a coordinate `tap`/`long-press`/`swipe`, or a `pinch`/`rotate` with no `on:`) warns in a different shape: a tree-source outage left it unsettled, so it dispatched blind and the green says only that the gesture was sent. Restore the tree source, usually by relaunching the app so the instrumentation loads, and rerun. Accepting that warning needs an app that serves no tree, which cannot satisfy this contract anyway.
|
|
112
112
|
6. Run the same YAML again immediately with the same runner. Do not manually reset app or account data.
|
|
113
113
|
7. Reset the streak after any failure, edit, re-recording, baseline update, or state-changing manual recovery. Repair through `argent-create-flow`, audit again, and restart with fresh services.
|
|
114
114
|
|
|
@@ -7,13 +7,13 @@ Physical iPhone (`kind: "device"`): Metro debugging and profiling tools reject i
|
|
|
7
7
|
|
|
8
8
|
## 1. Starting the React Native App
|
|
9
9
|
|
|
10
|
-
### 1.1 Explore Configuration (MANDATORY
|
|
10
|
+
### 1.1 Explore Configuration (MANDATORY: Do This First)
|
|
11
11
|
|
|
12
12
|
**Before running commands**, read the project's build and run configuration from the `argent-environment-inspector` subagent result.
|
|
13
13
|
|
|
14
14
|
Do NOT default to `npx react-native start` or `npx react-native run-ios` without first checking for custom scripts and workflows.
|
|
15
15
|
|
|
16
|
-
**Manual fallback** (if neither the agent nor the tool is available): read ALL `package.json` scripts
|
|
16
|
+
**Manual fallback** (if neither the agent nor the tool is available): read ALL `package.json` scripts: look for custom scripts like `start:local`, `start:dev`, `ios`, `build:ios`, flavors, etc. Custom scripts take priority over default commands. Also check `metro.config.js` for non-default port or watchFolders. For iOS builds, prefer opening `.xcworkspace` over `.xcodeproj` (CocoaPods generates the workspace).
|
|
17
17
|
|
|
18
18
|
**If the project structure is convoluted, ask the user before proceeding.**
|
|
19
19
|
|
|
@@ -37,7 +37,7 @@ Do NOT default to `npx react-native start` or `npx react-native run-ios` without
|
|
|
37
37
|
|
|
38
38
|
Optional: `npx react-native start --reset-cache` if cache issues are suspected.
|
|
39
39
|
|
|
40
|
-
1. **Verify Metro is ready**: use the `debugger-status` tool. It returns a `status` result instead of erroring: `status: "connected"` or `status: "not_connected"` with `reason: "no_app_connected"` both mean Metro is up (the app just hasn't attached yet); `reason: "metro_not_running"` means Metro is not reachable
|
|
40
|
+
1. **Verify Metro is ready**: use the `debugger-status` tool. It returns a `status` result instead of erroring: `status: "connected"` or `status: "not_connected"` with `reason: "no_app_connected"` both mean Metro is up (the app just hasn't attached yet); `reason: "metro_not_running"` means Metro is not reachable; follow the result's `guidance`.
|
|
41
41
|
|
|
42
42
|
1. **Projects with flavors or custom configs**: Use project-specific start script if present (e.g. `npm run start:local`), and start Metro **before** running the app.
|
|
43
43
|
|
|
@@ -47,7 +47,7 @@ In a **separate** terminal (Metro keeps running in the first):
|
|
|
47
47
|
|
|
48
48
|
**Use the project's custom build/run script if one exists** (e.g. `npm run ios`, `npm run android`, `yarn ios:debug`). Only fall back to the defaults below if no custom scripts are defined.
|
|
49
49
|
|
|
50
|
-
**Pass the target device explicitly
|
|
50
|
+
**Pass the target device explicitly**: derive it from `list-devices` (see `<device_selection_rule>`):
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
53
|
npx react-native run-ios --simulator="<name>" # iOS (or --udid <UDID>)
|
|
@@ -78,7 +78,7 @@ lsof -i :PORT
|
|
|
78
78
|
- **No output** → Port free; safe to start Metro.
|
|
79
79
|
- **Output with PID** → Another process is using the port.
|
|
80
80
|
|
|
81
|
-
Use the `debugger-status` tool to check whether the process on that port is actually a Metro server
|
|
81
|
+
Use the `debugger-status` tool to check whether the process on that port is actually a Metro server: it returns a structured result, not an error. `status: "connected"` or `reason: "no_app_connected"` → the process is Metro. `reason: "metro_not_running"` while `lsof` shows a listener → the port is occupied by something that is **not** Metro; the result's `detail` field shows what the process answered (`Metro at port ... is not running (got: ...)`). In that case ask the user whether you may kill the process.
|
|
82
82
|
|
|
83
83
|
To kill a Metro process, use the `stop-metro` tool (requires user confirmation).
|
|
84
84
|
|
|
@@ -87,7 +87,7 @@ To kill a Metro process, use the `stop-metro` tool (requires user confirmation).
|
|
|
87
87
|
- **App must point at the same host/port as the running Metro.** Default: same machine, port 8081.
|
|
88
88
|
- **iOS Simulator:** By default uses localhost; no extra config needed for same-machine Metro.
|
|
89
89
|
|
|
90
|
-
**Verify Metro is reachable:** use the `debugger-status` tool. `reason: "metro_not_running"` means Metro did not answer on that port
|
|
90
|
+
**Verify Metro is reachable:** use the `debugger-status` tool. `reason: "metro_not_running"` means Metro did not answer on that port: start it (§2.1); `"no_app_connected"` means Metro answered but the app has not attached (§2.3). Any other reason: follow the result's `guidance` (it does not by itself prove Metro is up).
|
|
91
91
|
|
|
92
92
|
### 2.3 Reload the App (Ensure New Bundle)
|
|
93
93
|
|
|
@@ -139,17 +139,17 @@ Once you discover the correct build/run workflow for a project, **save it to pro
|
|
|
139
139
|
|
|
140
140
|
### 3.5 Device Control
|
|
141
141
|
|
|
142
|
-
| Action | Tool / Command
|
|
143
|
-
| -------------------------- |
|
|
144
|
-
| List devices | `list-devices` tool (iOS + Android)
|
|
145
|
-
| Boot an iOS simulator | `boot-device` tool with `udid`
|
|
146
|
-
| Boot an Android emulator | `boot-device` tool with `avdName`
|
|
147
|
-
| Launch an app | `launch-app` tool (pass device id + bundle id / package name)
|
|
148
|
-
| Restart an app | `restart-app` tool (pass device id + bundle id / package name)
|
|
149
|
-
| Open a URL / deep link | `open-url` tool (pass device id + URL)
|
|
150
|
-
| Rotate device | `rotate` tool
|
|
151
|
-
| Stop simulator server | `stop-simulator-server` tool (iOS UDID or Android serial
|
|
152
|
-
| Stop all simulator servers | `stop-all-simulator-servers` tool
|
|
142
|
+
| Action | Tool / Command |
|
|
143
|
+
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| List devices | `list-devices` tool (iOS + Android) |
|
|
145
|
+
| Boot an iOS simulator | `boot-device` tool with `udid` |
|
|
146
|
+
| Boot an Android emulator | `boot-device` tool with `avdName` |
|
|
147
|
+
| Launch an app | `launch-app` tool (pass device id + bundle id / package name) |
|
|
148
|
+
| Restart an app | `restart-app` tool (pass device id + bundle id / package name) |
|
|
149
|
+
| Open a URL / deep link | `open-url` tool (pass device id + URL) |
|
|
150
|
+
| Rotate device | `rotate` tool |
|
|
151
|
+
| Stop simulator server | `stop-simulator-server` tool (iOS UDID or Android serial, one device) |
|
|
152
|
+
| Stop all simulator servers | `stop-all-simulator-servers` tool: pass `devices: [...]` to scope the teardown to this session's devices (an unscoped call also tears down other agents' devices; use it only for a machine-wide cleanup) |
|
|
153
153
|
|
|
154
154
|
For full simulator setup workflow, refer to the `argent-ios-simulator-setup` skill.
|
|
155
155
|
|
|
@@ -161,7 +161,7 @@ For full simulator setup workflow, refer to the `argent-ios-simulator-setup` ski
|
|
|
161
161
|
|
|
162
162
|
| Problem type | Tool / Where to look |
|
|
163
163
|
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
164
|
-
| **JavaScript errors / logs** | Use `debugger-log-registry` to get a summary and log file path, then `Grep` to search. If it returns `status: "not_connected"`, no log file is returned
|
|
164
|
+
| **JavaScript errors / logs** | Use `debugger-log-registry` to get a summary and log file path, then `Grep` to search. If it returns `status: "not_connected"`, no log file is returned; follow its `guidance` to reconnect first. |
|
|
165
165
|
| **React component hierarchy** | Use `debugger-component-tree` tool for a text tree, or `debugger-inspect-element` at specific logical pixel coordinates (not normalized 0-1). |
|
|
166
166
|
| **Visual state of the app** | Use `screenshot` tool to capture the current screen, but prefer `describe` or `debugger-component-tree` for actual navigation and target discovery. If a permission prompt or system-owned modal overlay is not exposed reliably, then fall back to `screenshot`. |
|
|
167
167
|
| **Evaluate JS in the app** | Use `debugger-evaluate` tool to run JavaScript in the app's runtime. |
|
|
@@ -6,16 +6,16 @@ description: Optimizes a React Native app by profiling first to find real bottle
|
|
|
6
6
|
## Rules
|
|
7
7
|
|
|
8
8
|
- Do not apply shotgun optimizations. Measure first, define what "good enough" looks like (target metric + threshold), fix the top offender, re-measure honestly.
|
|
9
|
-
- **Quick scan
|
|
10
|
-
- **Deep measure
|
|
11
|
-
- **Inspect
|
|
9
|
+
- **Quick scan**: `react-profiler-renders` for a live render count table. Identifies hot components instantly.
|
|
10
|
+
- **Deep measure**: load `argent-react-native-profiler` skill. `react-profiler-start` → interact → `react-profiler-stop` → `react-profiler-analyze`.
|
|
11
|
+
- **Inspect**: `react-profiler-component-source` per finding. `react-profiler-fiber-tree` to trace component ancestry and render cost.
|
|
12
12
|
- **Verify correctness** - before fixing, recollect information from steps above and make a logical conclusion whether the approach is worth undertaking.
|
|
13
|
-
- **Fix
|
|
14
|
-
- **Re-measure
|
|
13
|
+
- **Fix**: apply one fix. Validate with `debugger-evaluate` before committing.
|
|
14
|
+
- **Re-measure**: report whether the target metric improved, regressed, or stayed flat. Check for regressions in other areas. If no net benefit or unacceptable tradeoffs, revert.
|
|
15
15
|
- **Profile for discovery, not only verification.** Use the profiler to find issues static analysis missed, not only to confirm fixes.
|
|
16
|
-
- **One fix per cycle for architectural changes.** Mechanical batch fixes (inline styles, index keys) can be grouped
|
|
16
|
+
- **One fix per cycle for architectural changes.** Mechanical batch fixes (inline styles, index keys) can be grouped; re-profile once after the batch. When the measurement involves device interaction, record it as a flow (`argent-create-flow` skill) before the first run so all subsequent cycles replay identical steps.
|
|
17
17
|
- **React Compiler**: if `react-profiler-analyze` reports `reactCompilerEnabled: true`, do NOT propose `useCallback`/`useMemo`/`React.memo` unless you confirmed compiler bail-out via `react-profiler-fiber-tree` (absent `useMemoCache`).
|
|
18
|
-
- **Sub-agents**: Phases 1–2 dispatch sub-agents
|
|
18
|
+
- **Sub-agents**: Phases 1–2 dispatch sub-agents: one per file for lint results, one per checklist item for semantic. Sub-agents CANNOT touch the device - all profiling and E2E verification must happen in the main agent.
|
|
19
19
|
|
|
20
20
|
## Pipeline
|
|
21
21
|
|
|
@@ -25,20 +25,20 @@ Copy this checklist into your TODO list:
|
|
|
25
25
|
|
|
26
26
|
```
|
|
27
27
|
Optimization Progress:
|
|
28
|
-
- [ ] Phase 1: Lint sweep (deterministic
|
|
29
|
-
- [ ] Phase 2: Semantic sweep (judgment
|
|
28
|
+
- [ ] Phase 1: Lint sweep (deterministic: catch mechanical issues without a running app)
|
|
29
|
+
- [ ] Phase 2: Semantic sweep (judgment: memoization, lists, animations, etc.)
|
|
30
30
|
- [ ] Phase 3: Baseline profile (find real bottlenecks, fix top offenders)
|
|
31
31
|
- [ ] Phase 4: Verify no regressions (crashes, errors, red screens)
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
### Phase 1: Lint sweep
|
|
35
35
|
|
|
36
|
-
Run ESLint once at the project root with a comprehensive RN performance ruleset. Dispatch sub-agents to fix results
|
|
36
|
+
Run ESLint once at the project root with a comprehensive RN performance ruleset. Dispatch sub-agents to fix results: one per file.
|
|
37
37
|
See [references/lint-rules.md](references/lint-rules.md) for ruleset and procedure.
|
|
38
38
|
|
|
39
39
|
### Phase 2: Semantic sweep
|
|
40
40
|
|
|
41
|
-
Review each area requiring judgment
|
|
41
|
+
Review each area requiring judgment: memoization, list rendering, animations, async patterns, effect cleanup, state hygiene, context architecture. Dispatch one sub-agent per checklist item.
|
|
42
42
|
See [references/semantic-checklist.md](references/semantic-checklist.md) for full checklist.
|
|
43
43
|
|
|
44
44
|
### Phase 3: Visual profiling
|
|
@@ -51,7 +51,7 @@ See [references/semantic-checklist.md](references/semantic-checklist.md) for ful
|
|
|
51
51
|
|
|
52
52
|
### Phase 4: Verify no regressions
|
|
53
53
|
|
|
54
|
-
Navigate every screen and UI flow within scope, confirm each renders without errors. If no scope was specified, verify the entire app
|
|
54
|
+
Navigate every screen and UI flow within scope, confirm each renders without errors. If no scope was specified, verify the entire app: cover all reachable screens via `argent-device-interact`. Use `debugger-log-registry` to check for runtime errors (if it returns `status: "not_connected"` there is no log file; follow its `guidance` to reconnect first) and take screenshots to check for red/yellow error screens. Check for regressions introduced by fixes (e.g., fewer re-renders but higher CPU, or new jank in a different screen). Main agent only.
|
|
55
55
|
|
|
56
56
|
## App-wide optimization
|
|
57
57
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Match profiler findings and semantic sweep results to concrete fixes.
|
|
4
4
|
|
|
5
|
-
| Finding | Fix | Detail
|
|
6
|
-
| -------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
7
|
-
| Re-renders with same props | `React.memo(Comp)` | **Skip if React Compiler active
|
|
8
|
-
| Expensive recomputation / unstable callbacks | `useMemo(fn, [deps])` / `useCallback(fn, [deps])` | `useCallback` must pair with `React.memo` on child
|
|
9
|
-
| Inline objects/arrays in JSX | `StyleSheet.create()` / module-level const | New reference every render breaks shallow equality
|
|
10
|
-
| List jank | `removeClippedSubviews`, `maxToRenderPerBatch`, `windowSize`, `getItemLayout` | Or migrate to `@shopify/flash-list` with `estimatedItemSize`
|
|
11
|
-
| JS-thread animation jank | `useNativeDriver: true` or `react-native-reanimated` | `useNativeDriver` only works for `transform` and `opacity` properties
|
|
12
|
-
| Heavy work during transitions | `InteractionManager.runAfterInteractions()` | Defers execution until active animations complete
|
|
13
|
-
| Slow startup | Hermes + inline requires in `metro.config.js` | Lazy `require()` defers loading heavy modules until first use
|
|
14
|
-
| Redundant, heavy, or n+1 network calls | `view-network-logs` → `view-network-request-details` | Batch, debounce, or cache at the data layer
|
|
5
|
+
| Finding | Fix | Detail |
|
|
6
|
+
| -------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| Re-renders with same props | `React.memo(Comp)` | **Skip if React Compiler active**: `react-profiler-analyze` reports compiler status per component |
|
|
8
|
+
| Expensive recomputation / unstable callbacks | `useMemo(fn, [deps])` / `useCallback(fn, [deps])` | `useCallback` must pair with `React.memo` on child; alone it has no effect |
|
|
9
|
+
| Inline objects/arrays in JSX | `StyleSheet.create()` / module-level const | New reference every render breaks shallow equality |
|
|
10
|
+
| List jank | `removeClippedSubviews`, `maxToRenderPerBatch`, `windowSize`, `getItemLayout` | Or migrate to `@shopify/flash-list` with `estimatedItemSize` |
|
|
11
|
+
| JS-thread animation jank | `useNativeDriver: true` or `react-native-reanimated` | `useNativeDriver` only works for `transform` and `opacity` properties |
|
|
12
|
+
| Heavy work during transitions | `InteractionManager.runAfterInteractions()` | Defers execution until active animations complete |
|
|
13
|
+
| Slow startup | Hermes + inline requires in `metro.config.js` | Lazy `require()` defers loading heavy modules until first use |
|
|
14
|
+
| Redundant, heavy, or n+1 network calls | `view-network-logs` → `view-network-request-details` | Batch, debounce, or cache at the data layer |
|
|
@@ -51,5 +51,5 @@ Install missing plugins before running: `npm install --save-dev eslint-plugin-re
|
|
|
51
51
|
1. Check if the project has an existing ESLint config.
|
|
52
52
|
2a. If yes, extend it with missing rules from above.
|
|
53
53
|
2b. If no config, create a temporary `.eslintrc.json` with all rules above.
|
|
54
|
-
2. Run: `npx eslint --format json <src_dir
|
|
54
|
+
2. Run: `npx eslint --format json <src_dir>`; replace `<src_dir>` with the project's JS/TS source root (check `package.json` scripts or look for `src/`, `app/`, `lib/`)
|
|
55
55
|
3. Parse output into: `file:line -> rule -> message`.
|
|
@@ -46,11 +46,11 @@ Follow these rules throughout the profiling workflow:
|
|
|
46
46
|
|
|
47
47
|
After presenting the analysis report, always ask the user what they want to do next. Present these options:
|
|
48
48
|
|
|
49
|
-
1. **Investigate further
|
|
50
|
-
2. **Implement fixes
|
|
51
|
-
3. **Done for now
|
|
49
|
+
1. **Investigate further**: drill down into specific findings using query tools (CPU call trees, commit cascades, hang stacks, etc.) to identify root causes with confidence before making changes.
|
|
50
|
+
2. **Implement fixes**: apply changes based on the current findings, then re-profile to measure whether the metric changed (improved, regressed, or stayed flat).
|
|
51
|
+
3. **Done for now**: accept the report as-is.
|
|
52
52
|
|
|
53
|
-
Do NOT silently move on after the report. The report is the starting point, not the end
|
|
53
|
+
Do NOT silently move on after the report. The report is the starting point, not the end; query tools exist specifically to let you dig deeper into anything the report flags.
|
|
54
54
|
|
|
55
55
|
### During investigation: use query tools proactively
|
|
56
56
|
|
|
@@ -76,36 +76,36 @@ When profiling requires a specific interaction sequence (scroll a list, navigate
|
|
|
76
76
|
|
|
77
77
|
## 4. Standard Profiling Workflow
|
|
78
78
|
|
|
79
|
-
**Complete all steps in order
|
|
79
|
+
**Complete all steps in order; do not break mid-flow.**
|
|
80
80
|
|
|
81
81
|
### Step 1: Start profiling
|
|
82
82
|
|
|
83
|
-
Mind the react-native and ios-native profiler selection mentioned above when starting the session and start the tools. **Save `startedAtEpochMs` from the response
|
|
83
|
+
Mind the react-native and ios-native profiler selection mentioned above when starting the session and start the tools. **Save `startedAtEpochMs` from the response**: you will need it for annotation offsets. Every subsequent profiler/query call in this session must use the same `device_id`. Before beginning, define lightweight success criteria with the user: which metric matters most (e.g., `totalRenderMs`, specific commit duration, render count for a component) and what threshold would be meaningful. This anchors later evaluation. On success:
|
|
84
84
|
|
|
85
85
|
- if user asked you to perform the profiling, determine how to profile yourself using tools described in `argent-device-interact` skill.
|
|
86
|
-
- if the user stated they wish to perform the interaction themselves
|
|
86
|
+
- if the user stated they wish to perform the interaction themselves, suggest what interaction to perform (e.g. "scroll the list", "switch tabs") and wait for their reply.
|
|
87
87
|
If you received information about **existing profiling session** being owned by another agent:
|
|
88
88
|
- if session is marked as "stale", you may overtake it without prompting the user for allowance
|
|
89
89
|
- if session is NOT "stale" - before taking action and terminating the other session, **stop and ask user what you should do**, explaining the situation.
|
|
90
90
|
|
|
91
91
|
#### Annotate every interaction
|
|
92
92
|
|
|
93
|
-
After each `gesture-tap` or `gesture-swipe` call, record an annotation using the returned `timestampMs`. Compute `offsetMs = timestampMs - startedAtEpochMs`. Do this for _every_ interaction
|
|
93
|
+
After each `gesture-tap` or `gesture-swipe` call, record an annotation using the returned `timestampMs`. Compute `offsetMs = timestampMs - startedAtEpochMs`. Do this for _every_ interaction, including back-navigation swipes, not just the primary action. Pass all collected annotations to `react-profiler-analyze` in Step 3.
|
|
94
94
|
|
|
95
95
|
### Step 2: Stop and collect
|
|
96
96
|
|
|
97
97
|
Call `react-profiler-stop` **and** `native-profiler-stop` in parallel. Only skip `native-profiler-stop` if you did not start it in Step 1. Note `duration_ms` and `fiber_renders_captured`.
|
|
98
|
-
If `fiber_renders_captured: 0`, warn the user
|
|
98
|
+
If `fiber_renders_captured: 0`, warn the user: React commit data may be missing.
|
|
99
99
|
|
|
100
100
|
### Step 3: Analyze
|
|
101
101
|
|
|
102
|
-
Call `react-profiler-analyze` with `port`, `device_id`, `project_root`, `platform`, and `rn_version`. The report includes metadata such as `reactCompilerEnabled`, `strictModeEnabled`, and `buildMode
|
|
102
|
+
Call `react-profiler-analyze` with `port`, `device_id`, `project_root`, `platform`, and `rn_version`. The report includes metadata such as `reactCompilerEnabled`, `strictModeEnabled`, and `buildMode`; check these in the returned markdown report.
|
|
103
103
|
|
|
104
|
-
If you performed interactions using `gesture-tap`/`gesture-swipe`, pass `annotations` to mark when each action occurred. Each annotation's `offsetMs` must be computed as `tapTimestampMs - startedAtEpochMs`, where `tapTimestampMs` is the `timestampMs` returned by the gesture-tap/gesture-swipe tool and `startedAtEpochMs` was returned by `react-profiler-start`. Do **not** use `Date.now()` for this calculation
|
|
104
|
+
If you performed interactions using `gesture-tap`/`gesture-swipe`, pass `annotations` to mark when each action occurred. Each annotation's `offsetMs` must be computed as `tapTimestampMs - startedAtEpochMs`, where `tapTimestampMs` is the `timestampMs` returned by the gesture-tap/gesture-swipe tool and `startedAtEpochMs` was returned by `react-profiler-start`. Do **not** use `Date.now()` for this calculation; only server-side timestamps from the tool return values.
|
|
105
105
|
|
|
106
|
-
If dual profiling, also call `native-profiler-analyze`, then **you must** call `profiler-combined-report` for the cross-correlated view
|
|
106
|
+
If dual profiling, also call `native-profiler-analyze`, then **you must** call `profiler-combined-report` for the cross-correlated view; do not skip this step when both profilers ran; the combined report surfaces correlations that individual reports miss.
|
|
107
107
|
|
|
108
|
-
The analyze report includes **CPU hotspots per commit
|
|
108
|
+
The analyze report includes **CPU hotspots per commit**, showing exactly which JS functions ran during each slow React commit. Raw data is saved to disk automatically for later reload.
|
|
109
109
|
|
|
110
110
|
### Step 4: Assess results
|
|
111
111
|
|
|
@@ -113,18 +113,18 @@ Analyze whether the results give you a proper image of what is wrong with the ap
|
|
|
113
113
|
|
|
114
114
|
### Step 5: Present findings and ask about next steps
|
|
115
115
|
|
|
116
|
-
Present a concise summary of the key findings - present whether possibilities for improvement exist and how performing further actions could affect performance. Then follow the "After analysis" guideline
|
|
116
|
+
Present a concise summary of the key findings - present whether possibilities for improvement exist and how performing further actions could affect performance. Then follow the "After analysis" guideline: ask whether to investigate further, implement fixes (if available), or stop.
|
|
117
117
|
|
|
118
118
|
### Step 6: Drill-down investigation (iterative)
|
|
119
119
|
|
|
120
120
|
Based on findings from the report, use query tools to investigate deeper:
|
|
121
121
|
|
|
122
|
-
- **Slow component?** -> `profiler-cpu-query` mode=`component_cpu` component_name=`AppNavigator
|
|
123
|
-
- **Want to see the call tree?** -> `profiler-cpu-query` mode=`call_tree` function_name=`expensiveFunction
|
|
124
|
-
- **What happened during a time window?** -> `profiler-commit-query` mode=`by_time_range
|
|
125
|
-
- **Full commit detail?** -> `profiler-commit-query` mode=`by_index` commit_index=38
|
|
126
|
-
- **Who triggered whom?** -> `profiler-commit-query` mode=`cascade_tree
|
|
127
|
-
- **iOS hang details?** -> `profiler-stack-query` mode=`hang_stacks
|
|
122
|
+
- **Slow component?** -> `profiler-cpu-query` mode=`component_cpu` component_name=`AppNavigator`: shows what JS functions ran during that component's commits.
|
|
123
|
+
- **Want to see the call tree?** -> `profiler-cpu-query` mode=`call_tree` function_name=`expensiveFunction`: shows callers and callees.
|
|
124
|
+
- **What happened during a time window?** -> `profiler-commit-query` mode=`by_time_range`: lists all commits in a range.
|
|
125
|
+
- **Full commit detail?** -> `profiler-commit-query` mode=`by_index` commit_index=38: all components, props changes, parent cascade.
|
|
126
|
+
- **Who triggered whom?** -> `profiler-commit-query` mode=`cascade_tree`: visual parent-child cascade.
|
|
127
|
+
- **iOS hang details?** -> `profiler-stack-query` mode=`hang_stacks`: native call stacks during a hang.
|
|
128
128
|
|
|
129
129
|
Repeat as needed until you identify the root cause function and file, referring to step 4 for honest evaluation. After each round of investigation, ask the user if they want to continue digging or move to fixing.
|
|
130
130
|
|
|
@@ -135,7 +135,7 @@ If you profiled multiple scenarios and need to revisit earlier data:
|
|
|
135
135
|
1. Call `profiler-load` mode=`list` to see all saved sessions with timestamps (the list now also shows Runtime / Device / Metro bundle columns to help identify the right session).
|
|
136
136
|
2. Call `profiler-load` mode=`load_react` session_id=`<timestamp>` device_id=`<UDID>` to reload React data. `device_id` scopes the reload into the `port:device_id` cache slot.
|
|
137
137
|
3. Call `profiler-load` mode=`load_native` session_id=`<timestamp>` device_id=`<UDID>` to reload native profiler data.
|
|
138
|
-
4. Query tools now operate on the reloaded session data
|
|
138
|
+
4. Query tools now operate on the reloaded session data; **pass the same `device_id` you loaded with**, otherwise they will miss the cache.
|
|
139
139
|
|
|
140
140
|
This is useful for before/after comparisons: profile, fix, re-profile, then reload the original session to compare metrics side by side.
|
|
141
141
|
|
|
@@ -153,14 +153,14 @@ If the user stated that they do not wish for changes, present the profiling repo
|
|
|
153
153
|
|
|
154
154
|
## 5. Important Caveats
|
|
155
155
|
|
|
156
|
-
- **Dev mode inflation**: `buildMode: "dev"` renders are ~3x slower than production. Prioritize high `normalizedRenderCount
|
|
157
|
-
- **Re-run after fixes**: Always re-profile after changes. Report honestly whether the metric improved, regressed, or stayed flat
|
|
156
|
+
- **Dev mode inflation**: `buildMode: "dev"` renders are ~3x slower than production. Prioritize high `normalizedRenderCount`; it scales to prod.
|
|
157
|
+
- **Re-run after fixes**: Always re-profile after changes. Report honestly whether the metric improved, regressed, or stayed flat; do not assume improvement.
|
|
158
158
|
- **`excluded` is informational**: Components in `animatedSubtrees` and `recyclerChildren` re-render by design.
|
|
159
159
|
- **Strict Mode**: Double-invokes renders. The pipeline halves `normalizedRenderCount` automatically when detected.
|
|
160
|
-
- **Debugger connection**: If interrupted, started profiling also closes. Before attempting recovery, call `react-profiler-status
|
|
160
|
+
- **Debugger connection**: If interrupted, started profiling also closes. Before attempting recovery, call `react-profiler-status`: it tells you whether the session is `active`, `taken_over`, `stopped`, or `no_react_runtime`, so you can decide whether to stop, restart, or reconnect first.
|
|
161
161
|
- **Confounders to watch for**:
|
|
162
162
|
- Live API data may differ between runs (different payload sizes, content counts), which shifts render counts and durations independently of your fix. Note when data-dependent components show variance.
|
|
163
|
-
- Profiler overhead inflates CPU measurements. If iOS Instruments shows `JSLexer`, `JSONEmitter`, or Hermes internals dominating the JS thread, that reflects profiler instrumentation cost
|
|
163
|
+
- Profiler overhead inflates CPU measurements. If iOS Instruments shows `JSLexer`, `JSONEmitter`, or Hermes internals dominating the JS thread, that reflects profiler instrumentation cost, not app work. Discount those entries.
|
|
164
164
|
- Runs are not perfectly reproducible. Small variations (under ~10-15%) in commit duration may be noise; only treat consistent, directional changes as signal.
|
|
165
165
|
|
|
166
166
|
For standalone diagnostic tools (live render stats, fiber tree, CPU summary), see `references/diagnostic-tools.md`.
|