rnxsim 0.1.381 → 0.1.382
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 +19 -6
- package/cli/app-fonts.ts +1 -1
- package/cli/bin.ts +118 -26
- package/cli/bridge-diagnostics.ts +1 -1
- package/cli/bridge-flow-runner.ts +9 -9
- package/cli/browser-evals.ts +3 -3
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +407 -0
- package/cli/cloud-dispatch.ts +165 -0
- package/cli/cloud-session.ts +156 -0
- package/cli/command-contract.ts +2 -2
- package/cli/command-registry.ts +9 -0
- package/cli/commands/agent-wrapper.ts +4 -4
- package/cli/commands/agent.ts +3 -3
- package/cli/commands/box/checkout-plane.ts +16 -8
- package/cli/commands/box/rnx-command.ts +2 -2
- package/cli/commands/box/search-command.ts +2 -2
- package/cli/commands/box.ts +123 -70
- package/cli/commands/config.ts +3 -2
- package/cli/commands/control.ts +6 -6
- package/cli/commands/cpu-profile.ts +2 -2
- package/cli/commands/daemon.ts +7 -7
- package/cli/commands/debug.ts +2 -2
- package/cli/commands/detox.ts +7 -7
- package/cli/commands/diagnose.ts +1 -1
- package/cli/commands/electron.ts +1 -1
- package/cli/commands/film.ts +1 -1
- package/cli/commands/flow.ts +4 -4
- package/cli/commands/inspect/core.ts +58 -7
- package/cli/commands/inspect/env.ts +5 -3
- package/cli/commands/inspect/shared.ts +2 -1
- package/cli/commands/inspect/wait-event.ts +1 -1
- package/cli/commands/inspect/wait-ready.ts +15 -5
- package/cli/commands/inspect.ts +31 -9
- package/cli/commands/install-desktop.ts +2 -2
- package/cli/commands/maestro.ts +3 -3
- package/cli/commands/permissions.ts +1 -1
- package/cli/commands/platform.ts +91 -0
- package/cli/commands/record.ts +3 -3
- package/cli/commands/report-issue.ts +1 -1
- package/cli/commands/runtime.ts +1 -1
- package/cli/commands/screenshot-mode.ts +1 -1
- package/cli/commands/screenshot.ts +25 -0
- package/cli/commands/serve.ts +1 -1
- package/cli/commands/skills.ts +1 -1
- package/cli/commands/timeline.ts +1 -1
- package/cli/commands/upgrade.ts +8 -34
- package/cli/commands/upload.ts +3 -3
- package/cli/commands/version.ts +14 -3
- package/cli/commands/what-happened.ts +2 -2
- package/cli/current-sim.ts +43 -30
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/electron.ts +1 -1
- package/cli/drivers/playwright.ts +3 -3
- package/cli/drivers/types.ts +4 -4
- package/cli/flow-file.ts +3 -3
- package/cli/help-core.ts +18 -11
- package/cli/hidden-runtime-alias.ts +1 -1
- package/cli/hints.ts +2 -2
- package/cli/maestro-js.ts +2 -2
- package/cli/outbound-endpoints.ts +40 -6
- package/cli/parse-args.ts +1 -1
- package/cli/registry.ts +1 -1
- package/cli/resolve-assets.ts +2 -2
- package/cli/secure-file.ts +31 -0
- package/cli/shell-init.ts +98 -0
- package/cli/ws-bridge.ts +18 -8
- package/detox/expectations.ts +1 -1
- package/detox/gestures.ts +3 -3
- package/detox/index.ts +3 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +15 -8
- package/dist-lib/bridge-contract-input.mjs +15 -8
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +107 -0
- package/dist-lib/capture-contract.mjs +80 -0
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +32 -0
- package/dist-lib/cloud-contract.mjs +7 -0
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +4 -4
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +9 -1
- package/dist-lib/host/bridge-host.cjs +15 -10
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +248 -73
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +44 -6
- package/dist-lib/sdk.mjs +44 -6
- package/dist-lib/skills.cjs +435 -155
- package/dist-lib/vite.cjs +1 -1
- package/package.json +20 -4
- package/scripts/dev-server-scanner.ts +3 -3
- package/skills/contrast/SKILL.md +1 -1
- package/skills/rnx-perf/SKILL.md +68 -52
- package/src/app-url.ts +2 -3
- package/src/bridge-contract-input.ts +17 -6
- package/src/bridge-contract.ts +25 -4
- package/src/capture-contract.ts +423 -0
- package/src/cloud-contract.ts +15 -0
- package/src/home-paths.ts +9 -3
- package/src/host/agent-host.ts +1 -1
- package/src/host/bridge-host.ts +13 -11
- package/src/host/plane-host.ts +2 -2
- package/src/index.ts +21 -0
- package/src/native-dev-bundle-url.ts +2 -2
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/org-deck.ts +1 -1
- package/src/settings-bundle.ts +1 -1
- package/src/sim-client.ts +4 -0
- package/src/vite-plugin-one.ts +2 -2
- package/src/vite-plugin.ts +1 -1
- package/cli/commands/box/cloud-box.ts +0 -294
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.382 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rnxsim",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.382",
|
|
4
4
|
"description": "Vite and Metro plugins, testing drivers, and SDK exports for rnx.",
|
|
5
5
|
"author": "Tamagui LLC",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"./metro-production-bundle": {
|
|
42
42
|
"types": "./src/metro-production-bundle.ts",
|
|
43
43
|
"source": "./src/metro-production-bundle.ts",
|
|
44
|
+
"bun": "./src/metro-production-bundle.ts",
|
|
44
45
|
"import": "./dist-lib/metro-production-bundle.mjs",
|
|
45
46
|
"default": "./dist-lib/metro-production-bundle.cjs"
|
|
46
47
|
},
|
|
@@ -115,6 +116,20 @@
|
|
|
115
116
|
"import": "./dist-lib/bridge-contract.mjs",
|
|
116
117
|
"default": "./dist-lib/bridge-contract.cjs"
|
|
117
118
|
},
|
|
119
|
+
"./cloud-contract": {
|
|
120
|
+
"types": "./src/cloud-contract.ts",
|
|
121
|
+
"source": "./src/cloud-contract.ts",
|
|
122
|
+
"bun": "./src/cloud-contract.ts",
|
|
123
|
+
"import": "./dist-lib/cloud-contract.mjs",
|
|
124
|
+
"default": "./dist-lib/cloud-contract.cjs"
|
|
125
|
+
},
|
|
126
|
+
"./capture-contract": {
|
|
127
|
+
"types": "./src/capture-contract.ts",
|
|
128
|
+
"source": "./src/capture-contract.ts",
|
|
129
|
+
"bun": "./src/capture-contract.ts",
|
|
130
|
+
"import": "./dist-lib/capture-contract.mjs",
|
|
131
|
+
"default": "./dist-lib/capture-contract.cjs"
|
|
132
|
+
},
|
|
118
133
|
"./bridge-constants": {
|
|
119
134
|
"source": "./src/bridge-constants.ts",
|
|
120
135
|
"default": "./dist-lib/bridge-constants.cjs"
|
|
@@ -214,12 +229,13 @@
|
|
|
214
229
|
}
|
|
215
230
|
},
|
|
216
231
|
"devDependencies": {
|
|
217
|
-
"@contrast/harness": "workspace:*",
|
|
218
232
|
"@contrast/runtime-delivery": "workspace:*",
|
|
219
233
|
"@sootsim/compat": "workspace:*",
|
|
220
|
-
"@
|
|
221
|
-
"@
|
|
234
|
+
"@rnx/box": "workspace:*",
|
|
235
|
+
"@rnx/globals": "workspace:*",
|
|
236
|
+
"@rnx/skills": "workspace:*",
|
|
222
237
|
"@types/ws": "^8.5.13",
|
|
238
|
+
"rnx-cloud-box": "workspace:*",
|
|
223
239
|
"sootsim-engine": "workspace:*",
|
|
224
240
|
"typescript": "^5.7.0",
|
|
225
241
|
"vite": "^8.2.2",
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
readAppSettingsBundle,
|
|
35
35
|
} from '../src/settings-bundle.ts'
|
|
36
36
|
import { loadOptionalDemoApps, optionalDemoAppsSync } from './optional-demo-registry.ts'
|
|
37
|
-
import type { AppSettingsSpecifier } from '@
|
|
37
|
+
import type { AppSettingsSpecifier } from '@rnx/globals'
|
|
38
38
|
|
|
39
39
|
// how long past a command's own budget we wait before deciding its exit event is
|
|
40
40
|
// never coming. generous, because this only fires when the child is already
|
|
@@ -787,7 +787,7 @@ export async function probePort(
|
|
|
787
787
|
buildIconProxyUrl?: (externalUrl: string) => string,
|
|
788
788
|
listeningProcess?: ListeningProcess,
|
|
789
789
|
): Promise<DiscoveredServer | null> {
|
|
790
|
-
// callers such as `
|
|
790
|
+
// callers such as `rnx open <port>` probe one port directly instead of
|
|
791
791
|
// going through scanDevServers. wait for the optional in-repo registry here
|
|
792
792
|
// too, or a cold CLI process can build the known app's bundle url before its
|
|
793
793
|
// runtime config is available.
|
|
@@ -1074,7 +1074,7 @@ export function __shouldReuseScannerCacheEntry(
|
|
|
1074
1074
|
return true
|
|
1075
1075
|
}
|
|
1076
1076
|
|
|
1077
|
-
// exported for tests / `
|
|
1077
|
+
// exported for tests / `rnx debug` — forces the next scan to re-probe.
|
|
1078
1078
|
export function __resetScannerCache() {
|
|
1079
1079
|
portCache.clear()
|
|
1080
1080
|
knownNonPatched.clear()
|
package/skills/contrast/SKILL.md
CHANGED
|
@@ -42,7 +42,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
42
42
|
| `rnx debug` | drive __sootsimDebug: channels, snapshots, and inspectors |
|
|
43
43
|
| `rnx what-happened` | show recent semantic events: toasts, keyboards, screens, alerts, fetches, errors |
|
|
44
44
|
| `rnx timeline` | control the semantic event timeline (enable opt-in kinds, clear, dump) |
|
|
45
|
-
| `rnx box` | start a local
|
|
45
|
+
| `rnx box` | start a local Box or create a cloud Box |
|
|
46
46
|
| `rnx ios` | start an iOS simulator |
|
|
47
47
|
| `rnx android` | start an Android simulator |
|
|
48
48
|
| `rnx open` | load a target into the current sim or open a new one |
|
package/skills/rnx-perf/SKILL.md
CHANGED
|
@@ -24,7 +24,7 @@ indict, remeasure — and every wasted week came from skipping a step.
|
|
|
24
24
|
draw call, paint boundary and raster-tier decision is in the compositor's
|
|
25
25
|
render profile, not the shell's.** `perf shell stop` prints both, labelled
|
|
26
26
|
by worker — read the compositor block for anything inside an app. for
|
|
27
|
-
months it printed only the shell's, and a
|
|
27
|
+
months it printed only the shell's, and a dense token-list fling
|
|
28
28
|
therefore reported `raster tier: 0 promotions / 0 blits` while the
|
|
29
29
|
compositor was blitting ~14 rows a frame; the giveaway was `node visits: 7`
|
|
30
30
|
next to `app:one 1014 paints`. if a render-profile block describes a
|
|
@@ -32,26 +32,25 @@ indict, remeasure — and every wasted week came from skipping a step.
|
|
|
32
32
|
are reading the wrong worker.
|
|
33
33
|
browser matters just as much: playwright's bundled headless chromium has
|
|
34
34
|
NO GPU — CanvasKit falls back to software rendering and every number lies
|
|
35
|
-
high. launch GPU-backed Chrome
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
launching it hijacks their Dock events.
|
|
35
|
+
high. launch a dedicated GPU-backed Chrome executable with a disposable
|
|
36
|
+
profile and an owning process supervisor that terminates its exact process
|
|
37
|
+
tree. never automate the user's own browser profile.
|
|
39
38
|
2. **machinery silently not engaging is the default failure mode.** the
|
|
40
39
|
raster tier compiled, gated, and did *nothing* for months — zero
|
|
41
40
|
promotions on its textbook case — until per-gate rejection counters
|
|
42
41
|
existed. the frame-demand gate was blind to commit storms. the vsync
|
|
43
42
|
pump flapped 100 msgs/s at rest. never assume a tier works because it's
|
|
44
43
|
wired; read its counter during the exact workload.
|
|
45
|
-
3. **check
|
|
46
|
-
machine mimics every perf and infra failure.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
cadence or fidelity.
|
|
44
|
+
3. **check reclaimable memory and sampled CPU before blaming code.** an OOM or
|
|
45
|
+
busy machine mimics every perf and infra failure. on macOS, read
|
|
46
|
+
`memory_pressure -Q` and take multiple `iostat -c 3` CPU samples; on Linux,
|
|
47
|
+
read `MemAvailable` from `/proc/meminfo` and sample CPU idle over time. keep
|
|
48
|
+
the busiest sample. raw macOS `freemem()` and load average are not admission
|
|
49
|
+
signals. attribute browser processes with `ps -eo pid,ppid,args` before
|
|
50
|
+
treating one as abandoned or stopping an exact pid.
|
|
51
|
+
4. **never trade animation fidelity for CPU.** perpetual sub-frame animation
|
|
52
|
+
must keep its authored cadence. attack per-frame cost (layers, caching,
|
|
53
|
+
damage), never cadence or fidelity.
|
|
55
54
|
|
|
56
55
|
## measuring
|
|
57
56
|
|
|
@@ -63,14 +62,12 @@ paths add work to the simulator or browser and can change the cadence being
|
|
|
63
62
|
measured. Record the visible window with the operating system's native screen
|
|
64
63
|
capture instead.
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
--out <artifact.mov> -- <operating-system input command>
|
|
73
|
-
```
|
|
65
|
+
Use an operating-system-owned window recorder. Target the exact browser window
|
|
66
|
+
rather than the display when the platform supports it, start recording before
|
|
67
|
+
normal user input, preserve the movie, and record the operating system and
|
|
68
|
+
recorder version. Confirm that the recorder process, not the browser or
|
|
69
|
+
simulator, owns capture and encoding. If native window capture is unavailable,
|
|
70
|
+
report the proof as blocked instead of substituting an in-page capture path.
|
|
74
71
|
|
|
75
72
|
The visual run contains only normal user input. Do not query the performance,
|
|
76
73
|
debug, or test bridge while it records. Treat that video as visual evidence of
|
|
@@ -82,15 +79,10 @@ Open the sim with `?debug=framestamp` to make that video machine-readable.
|
|
|
82
79
|
Every surface paint then draws its `Date.now()` low 20 bits as a 23-cell
|
|
83
80
|
barcode — `home` and `app:*` at 45% of the surface height, `shell-overlay` on
|
|
84
81
|
its own row at 55% so overlay paints (keyboard, native UI) are attributable
|
|
85
|
-
separately
|
|
86
|
-
shows and how late that
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# sim opened with ?debug=framestamp
|
|
90
|
-
bun ~/screen/src/cli.ts run --window-id <id> --duration <seconds> \
|
|
91
|
-
--out <artifact.mov> -- <operating-system input command>
|
|
92
|
-
bun scripts/debug/decode-framestamp.ts <artifact.mov>
|
|
93
|
-
```
|
|
82
|
+
separately. Decode the documented 23-cell barcode with a compatible framestamp
|
|
83
|
+
decoder to report, per presented frame, which paint it shows and how late that
|
|
84
|
+
paint presented. If no decoder is available, keep the recording as qualitative
|
|
85
|
+
evidence and make no numeric presentation-latency claim from it.
|
|
94
86
|
|
|
95
87
|
This is the only way to separate a frame the compositor never produced from one
|
|
96
88
|
it produced and the browser never presented.
|
|
@@ -153,13 +145,13 @@ the report and how to read it:
|
|
|
153
145
|
workload.
|
|
154
146
|
**before widening any skip bucket, read the `also fail a later gate`
|
|
155
147
|
line under it.** the counters name only the FIRST failed gate, so a big
|
|
156
|
-
bucket can be entirely blocked a second time and unwidenable: on
|
|
148
|
+
bucket can be entirely blocked a second time and unwidenable: on one dense
|
|
157
149
|
token-list fling all 8298 `animated` skips also carried a style transform
|
|
158
150
|
or a non-cacheable chunk, and narrowing the animated gate moved 6007 to
|
|
159
151
|
`transform` and 2350 to `cacheable` while promoting nothing. a bucket is
|
|
160
152
|
worth attacking when its also-blocked share is small.
|
|
161
|
-
and blits firing is not the same as the tier paying for itself: on
|
|
162
|
-
|
|
153
|
+
and blits firing is not the same as the tier paying for itself: on that same
|
|
154
|
+
token list the tier blits every visible row and costs 70MB of GPU
|
|
163
155
|
cache for no frame-time change, while the retained row boundaries under it
|
|
164
156
|
cost 2.4ms a frame. the discriminator is per-row draw density, so check
|
|
165
157
|
`draw calls` in the same block before concluding a cache is earning its
|
|
@@ -198,11 +190,34 @@ not the installed Safari engine.
|
|
|
198
190
|
|
|
199
191
|
every receipt must carry the exact page and frame URLs, browser user agent,
|
|
200
192
|
harness-source identity, capture time, engine build identity and generation,
|
|
201
|
-
runtime bundle receipt,
|
|
193
|
+
runtime bundle receipt, sampled host capacity at run start, runtime errors, and
|
|
194
|
+
any partial failure. use the shared host-capacity sampler; do not record raw
|
|
195
|
+
`freemem()` or decide from macOS load average.
|
|
202
196
|
partial artifacts remain inadmissible until every requested run number for that
|
|
203
197
|
scenario exists with one harness, engine, seed, and viewport identity. browser
|
|
204
|
-
comparisons use the same
|
|
205
|
-
|
|
198
|
+
comparisons use the same root/target viewport tuple and backing scale. for a
|
|
199
|
+
wrapper or embedded surface, first prove the target has nonzero presented
|
|
200
|
+
geometry; a finite host viewport that responsively hides the target measures a
|
|
201
|
+
different surface. direct and embedded modes may intentionally have different
|
|
202
|
+
tuples, but browsers within one mode may not. finite but different device pixel
|
|
203
|
+
ratios are not comparable. if setup reloads only the child frame, replay the
|
|
204
|
+
parent's presentation control and wait for the new child to acknowledge it. a
|
|
205
|
+
selected parent toggle can outlive its child and is not proof of the child's
|
|
206
|
+
mode.
|
|
207
|
+
the profile intentionally blocks Graphite cache cleanup, so its cache snapshot
|
|
208
|
+
is not a terminal memory verdict. require a capture-local post-profile
|
|
209
|
+
compositor snapshot with before, after, and delta cleanup counters. an
|
|
210
|
+
over-limit profiled Context needs fresh submitted-work attempt and
|
|
211
|
+
successful-completion deltas; an over-limit profiled Recorder also needs a
|
|
212
|
+
fresh cleanup in that capture. classify Context and Recorder independently as
|
|
213
|
+
within-limit, locked-over-limit, or purgeable-over-limit; never compare their
|
|
214
|
+
aggregate, and never admit purgeable overage. a cache with zero purgeable bytes
|
|
215
|
+
can still hold a returned-resource queue: settled maintenance releases completed
|
|
216
|
+
Recorder resources, then budget enforcement evicts
|
|
217
|
+
least-recently-used overage before the next paint or resource insertion can
|
|
218
|
+
inherit the synchronous work. perpetual renderer
|
|
219
|
+
animation is not finite interaction demand; finite motion, readbacks, and
|
|
220
|
+
profiling must still block cleanup.
|
|
206
221
|
the host-clock `displayFrames`/`timerFrames` and shell-link
|
|
207
222
|
`displayPumps`/`timerPumps` counters prove whether the visible-rAF fallback
|
|
208
223
|
engaged. preserve failed receipts instead of retrying them out of the data set.
|
|
@@ -255,9 +270,9 @@ invalidates the profile.
|
|
|
255
270
|
|
|
256
271
|
### the cadence block: frames that never happened
|
|
257
272
|
|
|
258
|
-
work-per-painted-frame cannot see a frame that was never delivered
|
|
259
|
-
|
|
260
|
-
|
|
273
|
+
work-per-painted-frame cannot see a frame that was never delivered because a
|
|
274
|
+
worker was descheduled or its resilient clock fell back late. the report shows
|
|
275
|
+
low avg and zero jank while the user sees stutter.
|
|
261
276
|
the `cadence` section of `perf shell stop` measures the delivery side and
|
|
262
277
|
attributes a missing frame to its hop:
|
|
263
278
|
|
|
@@ -271,13 +286,14 @@ attributes a missing frame to its hop:
|
|
|
271
286
|
- `idle breaks` — gaps >250ms, excluded from all three: demand-gated
|
|
272
287
|
quiesce is legitimate, not starvation.
|
|
273
288
|
|
|
274
|
-
the compositor `compositorHostFrameClock`
|
|
275
|
-
|
|
276
|
-
profile window. published
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
289
|
+
the compositor `compositorHostFrameClock` keeps its historical name and reports
|
|
290
|
+
display/timer ticks consumed by the compositor worker's resilient clock during
|
|
291
|
+
the acknowledged profile window. `published` is null because renderer-main no
|
|
292
|
+
longer publishes compositor frames. sparse consumed ticks with low production
|
|
293
|
+
time identifies worker scheduling starvation. many consumed ticks with sparse
|
|
294
|
+
paints can be legitimate dirty-gating; correlate the frame series before
|
|
295
|
+
treating it as a regression. shell cadence comes from its worker frame and paint
|
|
296
|
+
series.
|
|
281
297
|
|
|
282
298
|
compare baseline vs contended captures of the same scripted window; also
|
|
283
299
|
compare **painted-frame counts**, the crudest and most robust signal.
|
|
@@ -339,9 +355,9 @@ which tier *should* absorb your cost and prove whether it does.
|
|
|
339
355
|
| layer compositor (`paint-boundary.ts`) | animating a child never re-records ancestors | replays >> records |
|
|
340
356
|
| idle boundary pre-record | the first drag replays instead of recording; cold records happen while the surface is quiet | `pre-recorded: N boundaries at idle` in the report, and the first interaction's record cost near its warm cost |
|
|
341
357
|
| damage rects (`damage-rect.ts`) | repaint clips to changed region (opaque-backdrop gated) | worst-frame render bounded during small updates |
|
|
342
|
-
| raster tier | stable rows become GPU textures; scroll skips recording | compositor block: promotions > 0 once warm, blits ≈ one per visible row
|
|
358
|
+
| raster tier | stable rows become GPU textures; scroll skips recording | compositor block: promotions > 0 once warm, blits ≈ one per visible row on a dense feed |
|
|
343
359
|
| flood guard, pointer coalescing, vsync hysteresis | message-storm and pump-thrash protection | msgs/s sane during gestures and at rest |
|
|
344
|
-
| resilient
|
|
360
|
+
| worker-owned resilient frame clocks | renderer-main stalls do not stop shell or compositor motion | compositor consumed display/timer frames plus shell worker frame and paint cadence |
|
|
345
361
|
|
|
346
362
|
there is no whole-screen scroll blit. one existed for a few hours in June
|
|
347
363
|
2026 and was reverted (`6706f3a014`): it shifted a surface RECTANGLE, so a
|
|
@@ -374,5 +390,5 @@ tier fire on feeds came entirely from rejection counters.
|
|
|
374
390
|
done means: a named hot path + the counter or split that indicts it + the
|
|
375
391
|
same capture re-run showing the number moved + no new errors (`get errors`)
|
|
376
392
|
+ nothing torn down left running (close sims you opened, kill load loops).
|
|
377
|
-
for engine changes, run the
|
|
378
|
-
|
|
393
|
+
for engine changes, run the affected integration tests exposed by the installed
|
|
394
|
+
rnx version and capture stable screenshots of surfaces you touched.
|
package/src/app-url.ts
CHANGED
|
@@ -24,9 +24,8 @@ export function isAppDeepLinkTarget(target: string): boolean {
|
|
|
24
24
|
export async function openAppUrl(bridge: InspectBridge, target: string): Promise<string> {
|
|
25
25
|
const normalized = normalizeAppUrlTarget(target)
|
|
26
26
|
const result: unknown = await bridge.send({
|
|
27
|
-
type: '
|
|
28
|
-
|
|
29
|
-
args: [normalized],
|
|
27
|
+
type: 'openUrl',
|
|
28
|
+
url: normalized,
|
|
30
29
|
})
|
|
31
30
|
if (
|
|
32
31
|
result !== null &&
|
|
@@ -208,8 +208,10 @@ export function parseStateOptions(value: unknown): SimStateOptions {
|
|
|
208
208
|
const input = recordValue(value, 'state')
|
|
209
209
|
const route = optionalBoolean(input, 'route', 'state')
|
|
210
210
|
const errors = optionalBoolean(input, 'errors', 'state')
|
|
211
|
+
const logs = optionalBoolean(input, 'logs', 'state')
|
|
211
212
|
const depth = optionalNumber(input, 'depth', 'state')
|
|
212
213
|
const errorLimit = optionalNumber(input, 'errorLimit', 'state')
|
|
214
|
+
const logLimit = optionalNumber(input, 'logLimit', 'state')
|
|
213
215
|
const layers =
|
|
214
216
|
input.layers === undefined ? undefined : stringValue(input.layers, 'state.layers')
|
|
215
217
|
if (
|
|
@@ -225,9 +227,11 @@ export function parseStateOptions(value: unknown): SimStateOptions {
|
|
|
225
227
|
tree: optionalBoolean(input, 'tree', 'state') ?? true,
|
|
226
228
|
...(route === undefined ? {} : { route }),
|
|
227
229
|
...(errors === undefined ? {} : { errors }),
|
|
230
|
+
...(logs === undefined ? {} : { logs }),
|
|
228
231
|
...(depth === undefined ? {} : { depth }),
|
|
229
232
|
...(layers === undefined ? {} : { layers }),
|
|
230
233
|
...(errorLimit === undefined ? {} : { errorLimit }),
|
|
234
|
+
...(logLimit === undefined ? {} : { logLimit }),
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
237
|
|
|
@@ -277,15 +281,22 @@ export function parseSemanticQuery(value: unknown): SimSemanticQuery {
|
|
|
277
281
|
return validationFailure('query.kind', 'must be tree, find, or count')
|
|
278
282
|
}
|
|
279
283
|
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
function semanticResolveSelector(
|
|
285
|
+
value: unknown,
|
|
286
|
+
path: string,
|
|
287
|
+
): SimSemanticResolveSelector {
|
|
288
|
+
const selector = recordValue(value, path)
|
|
282
289
|
if (selector.testID !== undefined) {
|
|
283
|
-
return { testID: stringValue(selector.testID,
|
|
290
|
+
return { testID: stringValue(selector.testID, `${path}.testID`) }
|
|
284
291
|
}
|
|
285
292
|
if (selector.text !== undefined) {
|
|
286
|
-
return { text: stringValue(selector.text,
|
|
293
|
+
return { text: stringValue(selector.text, `${path}.text`) }
|
|
287
294
|
}
|
|
288
|
-
return validationFailure(
|
|
295
|
+
return validationFailure(path, 'must select testID or text')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export function parseSemanticResolveSelector(value: unknown): SimSemanticResolveSelector {
|
|
299
|
+
return semanticResolveSelector(value, 'selector')
|
|
289
300
|
}
|
|
290
301
|
|
|
291
302
|
export function parseSemanticWaitOptions(value: unknown): SemanticWaitOptions {
|
|
@@ -308,7 +319,7 @@ export function parseSemanticWaitOptions(value: unknown): SemanticWaitOptions {
|
|
|
308
319
|
return {
|
|
309
320
|
condition: {
|
|
310
321
|
type,
|
|
311
|
-
|
|
322
|
+
selector: semanticResolveSelector(condition.selector, 'waitFor.condition.selector'),
|
|
312
323
|
},
|
|
313
324
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
314
325
|
}
|
package/src/bridge-contract.ts
CHANGED
|
@@ -11,12 +11,16 @@
|
|
|
11
11
|
import type {
|
|
12
12
|
SootSimAgentActionDetail,
|
|
13
13
|
SootSimExternalAppLifecycleOptions,
|
|
14
|
-
} from '@
|
|
14
|
+
} from '@rnx/globals'
|
|
15
15
|
|
|
16
16
|
export type BridgeCommandType =
|
|
17
17
|
| 'evaluate'
|
|
18
18
|
| 'call'
|
|
19
19
|
| 'screenshot'
|
|
20
|
+
| 'capture'
|
|
21
|
+
| 'captureRegions'
|
|
22
|
+
| 'setAppearance'
|
|
23
|
+
| 'openUrl'
|
|
20
24
|
| 'tap'
|
|
21
25
|
| 'longPress'
|
|
22
26
|
| 'keyboard'
|
|
@@ -48,6 +52,11 @@ export interface WsCommand {
|
|
|
48
52
|
target?: SootSimAgentActionDetail['target']
|
|
49
53
|
action?: string
|
|
50
54
|
text?: string
|
|
55
|
+
appearance?: 'light' | 'dark'
|
|
56
|
+
url?: string
|
|
57
|
+
includeVisual?: boolean
|
|
58
|
+
includeFonts?: boolean
|
|
59
|
+
regions?: import('./capture-contract').RnxCaptureRegionRequest[]
|
|
51
60
|
depth?: number
|
|
52
61
|
// screenshot — which canvas layers to composite. omit for full (today's
|
|
53
62
|
// default: everything including iOS chrome). 'tenant' excludes the shell
|
|
@@ -174,8 +183,8 @@ export interface PerformResult {
|
|
|
174
183
|
|
|
175
184
|
export type SemanticWaitCondition =
|
|
176
185
|
| { type: 'ready' }
|
|
177
|
-
| { type: 'present';
|
|
178
|
-
| { type: 'absent';
|
|
186
|
+
| { type: 'present'; selector: SimSemanticResolveSelector }
|
|
187
|
+
| { type: 'absent'; selector: SimSemanticResolveSelector }
|
|
179
188
|
|
|
180
189
|
export interface SemanticWaitOptions {
|
|
181
190
|
condition: SemanticWaitCondition
|
|
@@ -239,11 +248,22 @@ export interface SimStateOptions {
|
|
|
239
248
|
tree?: boolean
|
|
240
249
|
route?: boolean
|
|
241
250
|
errors?: boolean
|
|
251
|
+
// include the bounded guest console tail. omitted by the ordinary state
|
|
252
|
+
// command so one-shot state remains compact; `rnx logs` requests it.
|
|
253
|
+
logs?: boolean
|
|
242
254
|
// tree depth, matching the standalone `tree` command. default 5.
|
|
243
255
|
depth?: number
|
|
244
256
|
layers?: WsCommand['layers']
|
|
245
257
|
// cap on recentErrors entries. default 20.
|
|
246
258
|
errorLimit?: number
|
|
259
|
+
// cap on recentLogs entries. default and maximum 100.
|
|
260
|
+
logLimit?: number
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface SimStateLogEntry {
|
|
264
|
+
level: string
|
|
265
|
+
text: string
|
|
266
|
+
at?: number
|
|
247
267
|
}
|
|
248
268
|
|
|
249
269
|
export interface SimStateResult {
|
|
@@ -251,7 +271,8 @@ export interface SimStateResult {
|
|
|
251
271
|
screenshot?: unknown
|
|
252
272
|
tree?: SimSemanticNode[]
|
|
253
273
|
route?: { url?: string; screen?: string | null; stack?: string[] } | null
|
|
254
|
-
recentErrors?:
|
|
274
|
+
recentErrors?: SimStateLogEntry[]
|
|
275
|
+
recentLogs?: SimStateLogEntry[]
|
|
255
276
|
keyboard?: { visible: boolean; mode?: string | null }
|
|
256
277
|
capturedAt: number
|
|
257
278
|
}
|