execbro 2.9.6 → 2.9.8

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.
Files changed (33) hide show
  1. package/build/__tests__/unit/checkInjectedJs.test.d.ts +2 -0
  2. package/build/__tests__/unit/checkInjectedJs.test.d.ts.map +1 -0
  3. package/build/__tests__/unit/checkInjectedJs.test.js +42 -0
  4. package/build/__tests__/unit/checkInjectedJs.test.js.map +1 -0
  5. package/build/__tests__/unit/overlayAdoption.test.d.ts +2 -0
  6. package/build/__tests__/unit/overlayAdoption.test.d.ts.map +1 -0
  7. package/build/__tests__/unit/overlayAdoption.test.js +38 -0
  8. package/build/__tests__/unit/overlayAdoption.test.js.map +1 -0
  9. package/build/__tests__/unit/pressabilityAudit.test.d.ts +2 -0
  10. package/build/__tests__/unit/pressabilityAudit.test.d.ts.map +1 -0
  11. package/build/__tests__/unit/pressabilityAudit.test.js +96 -0
  12. package/build/__tests__/unit/pressabilityAudit.test.js.map +1 -0
  13. package/build/__tests__/unit/tapAndroidStatusBarInset.test.d.ts +2 -0
  14. package/build/__tests__/unit/tapAndroidStatusBarInset.test.d.ts.map +1 -0
  15. package/build/__tests__/unit/tapAndroidStatusBarInset.test.js +139 -0
  16. package/build/__tests__/unit/tapAndroidStatusBarInset.test.js.map +1 -0
  17. package/build/__tests__/unit/tapDuration.test.js +2 -2
  18. package/build/__tests__/unit/tapDuration.test.js.map +1 -1
  19. package/build/core/guides.d.ts.map +1 -1
  20. package/build/core/guides.js +86 -13
  21. package/build/core/guides.js.map +1 -1
  22. package/build/core/injected/overlayAdoption.d.ts +19 -0
  23. package/build/core/injected/overlayAdoption.d.ts.map +1 -0
  24. package/build/core/injected/overlayAdoption.js +17 -0
  25. package/build/core/injected/overlayAdoption.js.map +1 -0
  26. package/build/core/screenState.d.ts +18 -0
  27. package/build/core/screenState.d.ts.map +1 -1
  28. package/build/core/screenState.js +138 -7
  29. package/build/core/screenState.js.map +1 -1
  30. package/build/pro/tap.d.ts.map +1 -1
  31. package/build/pro/tap.js +7 -3
  32. package/build/pro/tap.js.map +1 -1
  33. package/package.json +3 -3
@@ -21,8 +21,18 @@ const guides = [
21
21
  - list_devices — iOS simulators, Android emulators, and physical devices in one call
22
22
  - ios_boot_simulator — boot an iOS simulator if needed
23
23
  - ios_launch_app / android_launch_app — launch the app
24
+ - ios_terminate_app — kill an app that is in a bad state before relaunching
25
+ - android_list_packages — find the package name when you only know the app by sight
24
26
  - Wait 2-3 seconds, then scan_metro
25
27
 
28
+ ## Stale Bundle After a Metro Restart
29
+ scan_metro detects that the process serving a port CHANGED (pid via lsof) and says so. It means
30
+ Fast Refresh history is discontinuous: edits made while Metro was down are NOT in the running
31
+ bundle, and reconnecting does not reconcile them. Devices attached on a restarted port are
32
+ flagged, and tap, swipe and get_screen_state carry a staleBundle warning until reload_app clears
33
+ it. Believe the warning — every other signal reads healthy, so stale behaviour otherwise looks
34
+ exactly like "my fix didn't work".
35
+
26
36
  ## Switch to Native Debugger
27
37
  - disconnect_metro — closes all CDP connections and stops auto-reconnect
28
38
  - The built-in React Native debugger can now connect
@@ -33,7 +43,8 @@ const guides = [
33
43
  - connect_metro: connect to specific port (when you know it)
34
44
  - disconnect_metro: close all connections (free CDP slot for native debugger)
35
45
  - ensure_connection: health check with healthCheck=true
36
- - get_connection_status: check uptime and gaps`
46
+ - get_connection_status: check uptime and gaps
47
+ - get_license_status: installation id and license tier (activate_license / delete_account manage it)`
37
48
  },
38
49
  {
39
50
  id: "inspect",
@@ -42,9 +53,9 @@ const guides = [
42
53
  content: `# Component Inspection
43
54
 
44
55
  ## Recommended Workflow: Identify a Component on Screen
45
- 1. Take a screenshot (ios_screenshot / android_screenshot) or use ocr_screenshot
46
- 2. Identify the target element visually, estimate its coordinates
47
- 3. Pass those coordinates straight through — every layout tool, tap() and the screenshots share one screen-space coordinate system, so no conversion is needed
56
+ 1. get_screen_state — screenshot-free, and every element comes back with a ready (x, y). Start here; only fall back to a screenshot (ios_screenshot / android_screenshot / ocr_screenshot) when you need to see the element to pick it out
57
+ 2. Take the coordinate from that listing, or estimate it off the screenshot
58
+ 3. Pass it straight through — every layout tool, tap() and the screenshots share one screen-space coordinate system, so no conversion is needed
48
59
  4. Pick the right tool (see decision below) and call it with (x, y)
49
60
 
50
61
  ### inspect_at_point(x, y)
@@ -53,7 +64,7 @@ NO overlay, zero visual side effect, safe to call rapidly or across a transition
53
64
 
54
65
  Returns:
55
66
  - element name and full owner-tree path
56
- - FRAME PER ANCESTOR (position/size in dp for every ancestor that hit-tested the point)
67
+ - FRAME PER ANCESTOR (position/size for every ancestor that hit-tested the point, in delivered-screenshot pixels — the same space as screenshots and tap)
57
68
  - PROPS of the innermost component (handlers as [Function], refs, testID, custom props)
58
69
  - the node's own style object
59
70
  - source {file, line, column} plus the owner chain as "Source ancestors" (set source=false to skip in tight loops)
@@ -72,6 +83,7 @@ looks wrong and isn't on the node itself, walk the ancestors it returns.
72
83
  - find_components(pattern) — regex search by component name across the fiber tree.
73
84
  - get_component_tree — compact names-only structure by default; pass structureOnly=false only when you genuinely need props/styles for the whole tree.
74
85
  - inspect_component(name) — deep dive into a specific component's props, state, and hooks.
86
+ - measure(componentName) — the reverse of inspect_at_point: geometry {x, y, width, height} for a component you can name, without hand-rolling a fiber walk in execute_in_app.
75
87
 
76
88
  ## Tips
77
89
  - Works on Paper, Fabric, and Bridgeless / new arch.
@@ -96,6 +108,10 @@ looks wrong and isn't on the node itself, walk the ancestors it returns.
96
108
  - A LogBox banner is excluded from the listing (it mounts above the app and its own buttons
97
109
  would otherwise be the only pressables returned). A note says so when one is up — the
98
110
  banner still covers screen, so use logbox({action:"dismiss"}) before trusting edge taps.
111
+ - Press targets the walk drops are counted and attributed to a rule (pruned as hidden,
112
+ not yet measurable, or dropped for zero size / off-viewport). An overlay listed with no
113
+ pressables inside it means treat that as a grouping fault in this tool, not an empty sheet
114
+ — screenshot and tap by coordinates instead of trusting the empty group.
99
115
 
100
116
  ## Coordinates
101
117
  All layout tools, tap() and the screenshots share ONE screen-space coordinate system. A frame
@@ -125,16 +141,22 @@ size in a note when it applies.
125
141
  - Style is the node's own style object, not a merged cascade — walk the returned ancestors when a value isn't on the node itself.
126
142
 
127
143
  ## Full Screen Layout
128
- - get_screen_layout — full layout data for all components
129
- - Use componentsOnly=true to hide host components (View, Text) and see only custom components
144
+ - get_screen_layout — full layout data for all components. Host components (View, Text) are
145
+ already filtered out; the tree is custom components only, so there is nothing to switch off
146
+ - Use extended=true for layout styles (padding, margin, flex, backgroundColor)
130
147
  - find_components with includeLayout=true for targeted layout info
148
+ - measure(componentName) — geometry for one named component, when you know the name and only
149
+ want its frame
131
150
 
132
151
  ## Key Tools
133
152
  - get_screen_state: route + overlays + every element, screenshot-free (start here)
134
153
  - ios_screenshot / android_screenshot: visual capture
135
154
  - tap: also returns a post-tap screenshot by default (no separate screenshot call needed after tapping)
136
155
  - ocr_screenshot: screenshot with text recognition and tap coordinates
137
- - inspect_at_point: frames per ancestor + props + source file:line (no overlay, fast)`
156
+ - inspect_at_point: frames per ancestor + props + source file:line (no overlay, fast)
157
+ - measure: geometry for one named component
158
+ - get_images: re-read any screenshot already captured (including tap burst frames) instead of taking another
159
+ - logbox: dismiss / ignore / push / detect the LogBox overlay — dismiss returns the full error content, so nothing is lost by clearing it`
138
160
  },
139
161
  {
140
162
  id: "interact",
@@ -159,6 +181,13 @@ Use tap — it tries multiple strategies automatically and returns a post-tap sc
159
181
  tap returns a screenshot after every action (screenshot=true by default) — no need to call ios_screenshot/android_screenshot after tapping.
160
182
  For coordinate/accessibility/OCR taps, it also verifies if the tap caused a visual change (verify=true by default). Set screenshot=false for fastest execution.
161
183
 
184
+ ### When verification says meaningful:false but you think the tap landed
185
+ Retry with burst=true. It captures 4 rapid screenshots after the tap, catching press animations
186
+ and highlights that settle before the ordinary after-screenshot. Then read
187
+ verification.transientChangeDetected, and pull the individual frames with
188
+ get_images({groupId: verification.burstGroupId}) — the frames are already in the shared image
189
+ buffer, so inspecting them costs no extra capture.
190
+
162
191
  ## Long Press
163
192
  Pass duration (milliseconds) to hold the touch instead of releasing it: tap(testID="row-3", duration=800). Use it for context menus, drag starts and multi-select. React Native fires onLongPress at 500ms, so anything under 500 will not trigger it; 800 is a safe default. Works on both platforms and with every targeting strategy (testID, text, component, coordinates).
164
193
 
@@ -243,6 +272,17 @@ tap(text=...) skips fiber for non-ASCII (Hermes limitation) and uses accessibili
243
272
  - dismiss_keyboard: blur the focused input, closing the keyboard.
244
273
  - ios_button / android_key_event: hardware buttons (HOME, BACK, etc.)
245
274
  - ios_open_url: deep links and universal links
275
+ - get_images: retrieve screenshots already captured by any tool, including tap burst frames
276
+
277
+ ## Jumping Straight to a Screen
278
+ navigate drives the app's router instead of tapping through the UI, and checks the route
279
+ actually moved: navigate({to:"/settings"}) -> read changed -> get_screen_state.
280
+ Destinations are NOT interchangeable — Expo Router takes paths ("/event-details?id=1"),
281
+ React Navigation takes route names ("TarotNav"); the response says which router resolved, and
282
+ unknown React Navigation names are rejected before dispatch with nearest-match suggestions.
283
+ navigate({action:"back"}) and {action:"reset"} are available too. changed=false means it settled
284
+ without moving; indeterminate=true means no settled reading. Prefer this over a hand-written
285
+ router call through execute_in_app, which reports success whenever nothing throws.
246
286
 
247
287
  ## After Interactions
248
288
  - Take a screenshot to verify the result`
@@ -262,10 +302,18 @@ tap(text=...) skips fiber for non-ASCII (Hermes limitation) and uses accessibili
262
302
  3. clear_logs — reset buffer, then re-capture after a specific action
263
303
 
264
304
  ## Key Tools
265
- - get_logs: retrieve logs with filtering (level, maxLogs, summary, verbose, startFromText)
305
+ - get_logs: retrieve logs with filtering (level, maxLogs, summary, verbose, startFromText, epoch)
266
306
  - search_logs: text search across all captured logs
267
307
  - clear_logs: reset the log buffer
268
308
 
309
+ ## App Restarts (epochs)
310
+ Every log and network entry carries a per-device epoch that increments on each new app run, and
311
+ the output draws a "── app restarted (epoch N) ──" divider at each boundary. The default is
312
+ epoch="all", so pre-restart data is never hidden from you — pass epoch="current" to read only the
313
+ run in front of you, or a number for one specific run. get_network_requests takes the same
314
+ parameter. When a crash and its aftermath sit in one read, the divider is what tells you which
315
+ side of the restart a message came from.
316
+
269
317
  ## NATIVE LOGS (crashes the JS console cannot see)
270
318
 
271
319
  get_logs(source="native") reads Android logcat / iOS os_log, filtered to your
@@ -356,6 +404,12 @@ are trying to fix.
356
404
  network_replay({requestId}) re-issues a captured request, optionally with a
357
405
  changed body or header, without driving the UI back to the screen that made it.
358
406
 
407
+ app_request issues a NEW request from inside the app, as the logged-in user — through the app's
408
+ real network stack, TLS trust and proxy config. Use it to reproduce a 4xx, check what an endpoint
409
+ returns for an edge case, or clean up test records the UI cannot reach. auth="auto" resolves the
410
+ token in-app, so the credential never enters the transcript; a hand-written fetch in
411
+ execute_in_app either digs the token out of redux or embeds a JWT literal, which does.
412
+
359
413
  ## Key Tools
360
414
  - get_network_requests: list requests with filters (urlPattern, method, status, summary)
361
415
  - search_network: search by URL pattern
@@ -364,6 +418,7 @@ changed body or header, without driving the UI back to the screen that made it.
364
418
  - network_mock: replace or tamper with responses (add / list / remove / clear)
365
419
  - network_condition: offline / slow / normal
366
420
  - network_replay: re-issue a captured request, with optional overrides
421
+ - app_request: issue a new request from inside the app, authenticated, without putting the token in the transcript
367
422
 
368
423
  ## Tips
369
424
  - Start with summary=true to see the request landscape
@@ -402,9 +457,12 @@ If the app called \`init({ stores, navigation, custom })\`, prefer the SDK paths
402
457
  ## Common Patterns (no SDK)
403
458
  - Read Redux: execute_in_app("globalThis.__REDUX_STORE__.getState().sliceName")
404
459
  - Dispatch action: execute_in_app("globalThis.__dispatch__(globalThis.__REDUX_ACTIONS__.slice.action(args))")
405
- - Navigate: execute_in_app("globalThis.__navigate__('ScreenName')")
406
460
  - Current route: execute_in_app("globalThis.__getCurrentRoute__()")
407
461
 
462
+ Note: do NOT navigate this way. A router call through execute_in_app reports success whenever
463
+ nothing throws — a path sent to a React Navigation ref changes nothing and warns only in LogBox.
464
+ Use the navigate tool, which verifies the route actually moved (see the "interact" guide).
465
+
408
466
  ## Long-Running Expressions
409
467
  - Pass timeoutMs to raise the 10s default (capped at 120000) — the promise poll ladder is derived from it, so a big budget is actually used
410
468
  - A promise that outlives the budget is kept in the app and its handle returned: execute_in_app({collect:"<handle>", waitMs:30000}) blocks server-side until it settles instead of making you poll
@@ -433,20 +491,35 @@ If the app called \`init({ stores, navigation, custom })\`, prefer the SDK paths
433
491
  4. get_bundle_errors({ clear: true }) — read, then reset the error buffer
434
492
  5. reload_app — trigger full JS bundle reload (only if needed)
435
493
 
494
+ ## Did My Edit Land? (ask before reloading)
495
+ get_refresh_status answers whether the JS runtime ACCEPTED a Fast Refresh update, which is a
496
+ different question from whether Metro compiled (get_bundle_status). Capture a Date.now() BEFORE
497
+ editing, wait ~2s after saving, then get_refresh_status({since: <that timestamp>}) — updateCount
498
+ > 0 means the edit is in the running app. Use it instead of reloading on a hunch, and instead of
499
+ polling logs or screenshots. A full reload resets its ring buffer, so the next call reports
500
+ "recorder just installed".
501
+
436
502
  ## When to Reload
437
503
  React Native has Fast Refresh by default. Only reload_app when:
438
- - Changes aren't appearing after a few seconds
504
+ - get_refresh_status shows no update accepted after a few seconds
439
505
  - App is in a broken/error state
440
506
  - Need to reset full app state (navigation, context)
441
507
  - Made changes to native code or config files
442
508
 
509
+ reload_app reconnects itself — do NOT follow it with scan_metro. The fresh runtime often answers
510
+ no CDP probe within the tool's own wait, so the reply says reconnect is still in progress and a
511
+ backoff loop finishes it a few seconds later; get_apps immediately after such a reply can
512
+ legitimately come back empty. A reflexive scan_metro there throws away the navigation stack, auth
513
+ and in-memory caches for nothing.
514
+
443
515
  ## Red Screen Errors
444
516
  If no errors captured via CDP, use get_bundle_errors with platform="ios" or "android" — this triggers screenshot+OCR fallback to read errors from the device screen.
445
517
 
446
518
  ## Key Tools
447
- - get_bundle_status: Metro health check
519
+ - get_bundle_status: Metro health check (did it compile?)
520
+ - get_refresh_status: did the running runtime accept the Fast Refresh update?
448
521
  - get_bundle_errors: compilation errors
449
- - reload_app: full JS bundle reload
522
+ - reload_app: full JS bundle reload — reconnects itself, no scan_metro afterwards
450
523
  - ensure_connection: verify connection with healthCheck=true`
451
524
  },
452
525
  {
@@ -1 +1 @@
1
- {"version":3,"file":"guides.js","sourceRoot":"","sources":["../../src/core/guides.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guides.js","sourceRoot":"","sources":["../../src/core/guides.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface AdoptionRect {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface AdoptionPressable {
8
+ overlayIdx: number | null;
9
+ paintIdx: number;
10
+ bounds: AdoptionRect;
11
+ }
12
+ export interface AdoptionOverlay {
13
+ hasContent: boolean;
14
+ enterIdx: number;
15
+ contentBounds: AdoptionRect;
16
+ }
17
+ export declare function adoptsByContainment(p: AdoptionPressable, o: AdoptionOverlay): boolean;
18
+ export declare const OVERLAY_ADOPTION_JS: string;
19
+ //# sourceMappingURL=overlayAdoption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlayAdoption.d.ts","sourceRoot":"","sources":["../../../src/core/injected/overlayAdoption.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAE9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,OAAO,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,YAAY,CAAC;CAC/B;AAoBD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAUrF;AAGD,eAAO,MAAM,mBAAmB,QAAiE,CAAC"}
@@ -0,0 +1,17 @@
1
+ export function adoptsByContainment(p, o) {
2
+ if (p.overlayIdx != null)
3
+ return false;
4
+ if (!o.hasContent)
5
+ return false;
6
+ if (!(o.enterIdx >= 0))
7
+ return false;
8
+ if (!(p.paintIdx > o.enterIdx))
9
+ return false;
10
+ var b = p.bounds;
11
+ var ob = o.contentBounds;
12
+ return b.x >= ob.x && b.y >= ob.y &&
13
+ b.x + b.width <= ob.x + ob.width &&
14
+ b.y + b.height <= ob.y + ob.height;
15
+ }
16
+ export const OVERLAY_ADOPTION_JS = `var adoptsByContainment = ${adoptsByContainment.toString()};`;
17
+ //# sourceMappingURL=overlayAdoption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlayAdoption.js","sourceRoot":"","sources":["../../../src/core/injected/overlayAdoption.ts"],"names":[],"mappings":"AA4CA,MAAM,UAAU,mBAAmB,CAAC,CAAoB,EAAE,CAAkB;IACxE,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC,CAAC,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAChC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC,CAAC,aAAa,CAAC;IACzB,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK;QAChC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC;AAC3C,CAAC;AAGD,MAAM,CAAC,MAAM,mBAAmB,GAAG,6BAA6B,mBAAmB,CAAC,QAAQ,EAAE,GAAG,CAAC"}
@@ -143,6 +143,24 @@ export declare function formatScreenStateSummary(ss: ScreenState, convert?: Item
143
143
  export declare function describePressHandler(raw: unknown): string | null;
144
144
  export declare function describePropHandlers(raw: unknown): string | null;
145
145
  export declare function parseScreenStateResponse(raw: unknown): ScreenState | null;
146
+ export interface PressabilityAuditCounts {
147
+ markerTotal?: number;
148
+ markerHiddenCount?: number;
149
+ markerUnmeasurableCount?: number;
150
+ markerSkipped?: Array<{
151
+ id: string;
152
+ why: string;
153
+ }>;
154
+ collectedCount?: number;
155
+ emittedCount?: number;
156
+ emptyOverlayGroups?: string[];
157
+ droppedByGeometry?: number;
158
+ droppedIds?: Array<{
159
+ id: string;
160
+ why: string;
161
+ }>;
162
+ }
163
+ export declare function formatPressabilityAudit(counts: PressabilityAuditCounts): string | null;
146
164
  export declare function getScreenState(options?: {
147
165
  device?: string;
148
166
  }): Promise<ExecutionResult & {
@@ -1 +1 @@
1
- {"version":3,"file":"screenState.d.ts","sourceRoot":"","sources":["../../src/core/screenState.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"screenState.d.ts","sourceRoot":"","sources":["../../src/core/screenState.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { executeInApp, delay } from "./jsExecute.js";
2
2
  import { iconSemanticHint } from "./iconSemantics.js";
3
3
  import { VISIBILITY_HELPERS_JS, detectNativeSheet, NATIVE_SHEET_MARKER_RE_SRC } from "./injected/visibility.js";
4
4
  import { RN_PRIMITIVES_SRC, GENERIC_COMPONENT_SRC } from "./injectedFilters.js";
5
+ import { OVERLAY_ADOPTION_JS } from "./injected/overlayAdoption.js";
5
6
  import { SHEET_HELPERS_JS } from "./injected/sheetOffset.js";
6
7
  export function markPressablesCoveredByOverlay(pressables, overlayBounds) {
7
8
  for (const p of pressables) {
@@ -266,6 +267,35 @@ export function parseScreenStateResponse(raw) {
266
267
  notes: r.notes ?? [],
267
268
  };
268
269
  }
270
+ export function formatPressabilityAudit(counts) {
271
+ const total = counts.markerTotal ?? 0;
272
+ const hidden = counts.markerHiddenCount ?? 0;
273
+ const unmeasurable = counts.markerUnmeasurableCount ?? 0;
274
+ const emptyGroups = counts.emptyOverlayGroups ?? [];
275
+ if (total === 0 || (hidden === 0 && unmeasurable === 0 && emptyGroups.length === 0))
276
+ return null;
277
+ const samples = (counts.markerSkipped ?? []).slice(0, 6).map((s) => `${s.id} (${s.why})`);
278
+ const detail = samples.length > 0 ? ` Skipped: ${samples.join("; ")}.` : "";
279
+ const droppedGeom = counts.droppedByGeometry ?? 0;
280
+ const droppedDetail = (counts.droppedIds ?? []).slice(0, 6).map((d) => `${d.id} (${d.why})`).join("; ");
281
+ if (emptyGroups.length > 0 && droppedGeom > 0) {
282
+ return (`${emptyGroups.join(", ")} is reported below with no pressables, and ${droppedGeom} press target(s) were dropped before grouping. ` +
283
+ `The two are not necessarily the same elements — an overlay listed with nothing in it is a grouping fault in this tool either way, ` +
284
+ `not evidence that the sheet is empty. Dropped: ${droppedDetail}. Screenshot the screen and tap by coordinates if you can see a control inside it.`);
285
+ }
286
+ if (emptyGroups.length > 0) {
287
+ return (`${emptyGroups.join(", ")} is reported below with no pressables, but React Native has ${total} press target(s) mounted on this screen. ` +
288
+ `An overlay detected confidently enough to be listed, holding nothing, is far more likely to be a grouping fault in this tool than a genuinely ` +
289
+ `empty sheet — screenshot the screen, and tap by coordinates if you can see a control inside it.`);
290
+ }
291
+ if (unmeasurable > 0) {
292
+ return (`${unmeasurable} of ${total} press target(s) React Native reports on this screen have no measurable host view and are NOT listed ` +
293
+ `below${hidden > 0 ? `, and ${hidden} more were pruned as hidden` : ""}. An unmeasurable press target is usually one that is mounted but ` +
294
+ `not laid out yet (sheet content mid-animation), so it may appear on a second call — re-read before concluding it is absent.${detail}`);
295
+ }
296
+ return (`${hidden} of ${total} press target(s) React Native reports were pruned as hidden and are not listed below. This is normally correct — ` +
297
+ `inactive navigator routes stay mounted — but if something you expected is missing, this names the rule that dropped it.${detail}`);
298
+ }
269
299
  export async function getScreenState(options = {}) {
270
300
  const { device } = options;
271
301
  const dispatchExpression = `
@@ -844,6 +874,11 @@ export async function getScreenState(options = {}) {
844
874
 
845
875
  var hostFibers = [];
846
876
  var fiberMeta = [];
877
+ // Audit accumulators — see the PressabilityDebugView branch in the walk below.
878
+ var markerTotal = 0;
879
+ var markerHiddenCount = 0;
880
+ var markerUnmeasurableCount = 0;
881
+ var markerSkipped = [];
847
882
  // overlayFiberMeta index -> fiberMeta index at which that overlay's subtree was entered.
848
883
  var overlayEnterIdx = [];
849
884
  // A count badge ("1", "99+") is the only text on icon buttons like a cart — treat it
@@ -1044,11 +1079,16 @@ export async function getScreenState(options = {}) {
1044
1079
  return isScreenHidden(getComponentName(hostFiber), hostFiber.memoizedProps, hostFiber);
1045
1080
  }
1046
1081
 
1047
- function walkPressabilityDebugViews(fiber, depth, hidden, ovIdx) {
1082
+ function walkPressabilityDebugViews(fiber, depth, hidden, ovIdx, hiddenBy) {
1048
1083
  if (!fiber || depth > 5000) return;
1049
1084
  var name = getComponentName(fiber);
1050
1085
  var props = fiber.memoizedProps;
1051
- var nextHidden = hidden || isScreenHidden(name, props, fiber);
1086
+ var becameHidden = isScreenHidden(name, props, fiber);
1087
+ var nextHidden = hidden || becameHidden;
1088
+ // Which rule pruned this subtree. Every marker dropped below here is
1089
+ // attributed to it, so an unexpected pruner is legible in the audit instead
1090
+ // of presenting as a silently shorter list.
1091
+ var nextHiddenBy = hiddenBy || (becameHidden ? (name || 'unnamed') : null);
1052
1092
 
1053
1093
  // Track which overlay subtree we're inside — membership by ancestry, not
1054
1094
  // geometry. A bottom sheet's subtree includes a full-screen backdrop, so
@@ -1069,6 +1109,33 @@ export async function getScreenState(options = {}) {
1069
1109
  }
1070
1110
  }
1071
1111
 
1112
+ // Audit: RN renders a PressabilityDebugView inside every press target it owns
1113
+ // (Pressable, every Touchable*, and gesture-handler's Pressable), whether or not
1114
+ // "Show Touchables" is on — the component returns null when disabled but the
1115
+ // fiber is still mounted. So the marker count is RN's own answer to "how many
1116
+ // press targets exist", and anything this walk reports is a subset of it.
1117
+ // Counting the drops, with the rule that caused each one, turns a silently short
1118
+ // list into a statement about what was skipped and why.
1119
+ if (name === 'PressabilityDebugView') {
1120
+ markerTotal++;
1121
+ var auditHost = fiber.return;
1122
+ var auditWhy = null;
1123
+ if (nextHidden) auditWhy = 'pruned as hidden by ' + nextHiddenBy;
1124
+ else if (!auditHost) auditWhy = 'marker had no host view';
1125
+ else if (!getMeasurable(auditHost)) auditWhy = 'host view is not measurable';
1126
+ if (auditWhy) {
1127
+ if (auditWhy.indexOf('pruned as hidden') === 0) markerHiddenCount++;
1128
+ else markerUnmeasurableCount++;
1129
+ if (markerSkipped.length < 12) {
1130
+ var ap = (auditHost && auditHost.memoizedProps) || {};
1131
+ markerSkipped.push({
1132
+ id: ap.testID || ap.nativeID || ap.accessibilityLabel || getComponentName(auditHost) || 'unnamed',
1133
+ why: auditWhy
1134
+ });
1135
+ }
1136
+ }
1137
+ }
1138
+
1072
1139
  if (!nextHidden && name === 'PressabilityDebugView') {
1073
1140
  var hostFiber = fiber.return;
1074
1141
  if (hostFiber && getMeasurable(hostFiber)) {
@@ -1188,11 +1255,11 @@ export async function getScreenState(options = {}) {
1188
1255
 
1189
1256
  var child = fiber.child;
1190
1257
  while (child) {
1191
- walkPressabilityDebugViews(child, depth + 1, nextHidden, ovIdx);
1258
+ walkPressabilityDebugViews(child, depth + 1, nextHidden, ovIdx, nextHiddenBy);
1192
1259
  child = child.sibling;
1193
1260
  }
1194
1261
  }
1195
- walkPressabilityDebugViews(roots[0].current, 0, false, null);
1262
+ walkPressabilityDebugViews(roots[0].current, 0, false, null, null);
1196
1263
 
1197
1264
  // ------------------------------------------------------------------
1198
1265
  // 3b. Standalone texts — proximity labels for icon-only pressables
@@ -1484,6 +1551,16 @@ export async function getScreenState(options = {}) {
1484
1551
  } catch(e) {}
1485
1552
  }
1486
1553
 
1554
+ // Handed to the resolve pass the same way the measurements are: this script and the
1555
+ // one that builds the response are separate evaluations with no shared scope.
1556
+ globalThis.__screenStateAudit = {
1557
+ markerTotal: markerTotal,
1558
+ markerHiddenCount: markerHiddenCount,
1559
+ markerUnmeasurableCount: markerUnmeasurableCount,
1560
+ markerSkipped: markerSkipped,
1561
+ collectedCount: hostFibers.length
1562
+ };
1563
+
1487
1564
  return { count: hostFibers.length + textFibers.length + imageFibers.length, overlayCount: overlayFiberMeta.length };
1488
1565
  })()
1489
1566
  `;
@@ -1502,6 +1579,7 @@ export async function getScreenState(options = {}) {
1502
1579
  const measureBudgetMs = Math.min(3000, 400 + dispatchedNodes * 2);
1503
1580
  await delay(measureBudgetMs);
1504
1581
  const resolveExpression = `
1582
+ ${OVERLAY_ADOPTION_JS}
1505
1583
  (function() {
1506
1584
  ${SHEET_HELPERS_JS}
1507
1585
  var hostFibers = globalThis.__screenStateFibers;
@@ -1693,6 +1771,8 @@ export async function getScreenState(options = {}) {
1693
1771
  }
1694
1772
 
1695
1773
  // Build pressable list
1774
+ var droppedByGeometry = 0;
1775
+ var droppedIds = [];
1696
1776
  var allPressables = [];
1697
1777
  for (var i = 0; i < meta.length; i++) {
1698
1778
  if (i === rootIdx) continue;
@@ -1700,7 +1780,26 @@ export async function getScreenState(options = {}) {
1700
1780
  if (!m0) { unmeasuredCount++; continue; }
1701
1781
  var tr = withTransform(shiftRect(m0, shiftFor(sheetIdx, i)), meta[i].transform);
1702
1782
  var m = tr.m;
1703
- if (!keepElement(m, tr.unreliable)) continue;
1783
+ if (!keepElement(m, tr.unreliable)) {
1784
+ // Dropped for geometry: zero-sized, or measured outside the viewport. Both are
1785
+ // usually right, and both were silent — which is why a sheet whose content
1786
+ // measures at zero size looked exactly like a sheet with no buttons in it.
1787
+ droppedByGeometry++;
1788
+ // Deduped by identity: a parked drawer contributes dozens of identical rows
1789
+ // and would otherwise fill the sample, hiding the one element being hunted.
1790
+ var dropId = meta[i].testID || meta[i].label || meta[i].component || 'unnamed';
1791
+ var seenDrop = false;
1792
+ for (var dq = 0; dq < droppedIds.length; dq++) if (droppedIds[dq].id === dropId) { seenDrop = true; break; }
1793
+ if (!seenDrop && droppedIds.length < 12) {
1794
+ droppedIds.push({
1795
+ id: dropId,
1796
+ why: (m.width <= 0 || m.height <= 0)
1797
+ ? 'measured ' + Math.round(m.width) + 'x' + Math.round(m.height)
1798
+ : 'measured off-viewport at ' + Math.round(m.x) + ',' + Math.round(m.y)
1799
+ });
1800
+ }
1801
+ continue;
1802
+ }
1704
1803
  allPressables.push({
1705
1804
  transformNote: tr.note,
1706
1805
  // Position in the DFS collection order == paint order. Kept so occlusion can
@@ -1810,8 +1909,15 @@ export async function getScreenState(options = {}) {
1810
1909
  var p = allPressables[pi];
1811
1910
  var assignedToOverlay = false;
1812
1911
  for (var ov = 0; ov < overlays.length; ov++) {
1813
- if (p.overlayIdx === overlays[ov].origIdx ||
1814
- (p.overlayIdx == null && overlays[ov].hasContent && inside(p.bounds, overlays[ov].contentBounds))) {
1912
+ // Containment is a fallback for content the overlay portals out of its own
1913
+ // subtree, so it must only ever adopt something painted ON TOP of the overlay.
1914
+ // Without the paint-order test it also adopts the screen behind: an RN <Modal>
1915
+ // measures a content rect large enough to contain the buttons underneath it,
1916
+ // and those were reported as the modal's own contents — i.e. as reachable,
1917
+ // when they are exactly what the modal blocks (verified on the test app,
1918
+ // 2026-09-04). The occludes() helper already encodes the same ordering for the
1919
+ // inverse question; this is that rule applied to adoption.
1920
+ if (p.overlayIdx === overlays[ov].origIdx || adoptsByContainment(p, overlays[ov])) {
1815
1921
  overlays[ov].pressables.push(p);
1816
1922
  assignedToOverlay = true;
1817
1923
  break;
@@ -1898,6 +2004,23 @@ export async function getScreenState(options = {}) {
1898
2004
  overlays[so].images.sort(byPosition);
1899
2005
  }
1900
2006
 
2007
+ var audit = globalThis.__screenStateAudit || {};
2008
+ // A press target can survive the walk and still never reach the caller: overlay
2009
+ // membership, coverage and measurement each drop elements in this pass. Counting
2010
+ // what is actually emitted is the only way that loss is visible at all — the
2011
+ // Gorhom sheet case (portaled outside the navigator, collected, then emitted
2012
+ // nowhere) produced an empty sheet group and no other trace (2026-09-04).
2013
+ var emittedPressables = rootPressables.length;
2014
+ var emptyOverlayGroups = [];
2015
+ for (var ec = 0; ec < overlays.length; ec++) {
2016
+ var opl = (overlays[ec].pressables || []).length;
2017
+ emittedPressables += opl;
2018
+ // An overlay confident enough to be reported, holding nothing, is the shape of a
2019
+ // real defect rather than of routine filtering: the sheet is on screen with a
2020
+ // visible button and the caller is told it is empty.
2021
+ if (opl === 0) emptyOverlayGroups.push(overlays[ec].type || 'overlay');
2022
+ }
2023
+
1901
2024
  // Strip bounds from overlay objects (not in public interface)
1902
2025
  var cleanOverlays = overlays.map(function(o) {
1903
2026
  return { type: o.type, title: o.title, pressables: o.pressables, texts: o.texts, images: o.images };
@@ -1920,6 +2043,11 @@ export async function getScreenState(options = {}) {
1920
2043
  return { route: route, overlays: cleanOverlays, pressables: rootPressables, texts: rootTexts, images: rootImages, nativeMarkers: nativeMarkers,
1921
2044
  logBoxSkipped: logBoxSkipped,
1922
2045
  unmeasuredCount: unmeasuredCount, transformedCount: transformedCount, sheetShift: Math.round(sheetShiftApplied),
2046
+ markerTotal: audit.markerTotal, markerHiddenCount: audit.markerHiddenCount,
2047
+ markerUnmeasurableCount: audit.markerUnmeasurableCount, markerSkipped: audit.markerSkipped,
2048
+ collectedCount: audit.collectedCount, emittedCount: emittedPressables,
2049
+ emptyOverlayGroups: emptyOverlayGroups,
2050
+ droppedByGeometry: droppedByGeometry, droppedIds: droppedIds,
1923
2051
  dispatchedCount: meta.length + textContents.length + imageMeta.length };
1924
2052
  })()
1925
2053
  `;
@@ -1945,6 +2073,9 @@ export async function getScreenState(options = {}) {
1945
2073
  completenessNotes.push(`${counts.unmeasuredCount} element(s) did not return a measurement within ${measureBudgetMs}ms and are NOT listed below. ` +
1946
2074
  `This is a timing miss, not an empty screen — call get_screen_state again, or take a screenshot, before concluding anything is absent.`);
1947
2075
  }
2076
+ const markerNote = formatPressabilityAudit(counts);
2077
+ if (markerNote)
2078
+ completenessNotes.push(markerNote);
1948
2079
  if ((counts.transformedCount ?? 0) > 0) {
1949
2080
  completenessNotes.push(`${counts.transformedCount} element(s) are marked ⚠transformed. Their frames come from the layout tree, which does not include ` +
1950
2081
  `native-driven transforms (sticky headers, collapsing toolbars, animating sheets), so the coordinates may not be where the element ` +