rnxsim 0.1.456 → 0.1.458

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 (57) hide show
  1. package/cli/commands/inspect/actions.ts +63 -14
  2. package/cli/commands/inspect.ts +66 -5
  3. package/cli/ws-bridge.ts +3 -0
  4. package/detox/index.ts +12 -1
  5. package/dist-lib/agent-daemon-client.cjs +1 -1
  6. package/dist-lib/agent-events.cjs +1 -1
  7. package/dist-lib/agent-identity.cjs +1 -1
  8. package/dist-lib/agent-sessions.cjs +1 -1
  9. package/dist-lib/attached-projects.cjs +1 -1
  10. package/dist-lib/auth/shared-session.cjs +1 -1
  11. package/dist-lib/backend-origin.cjs +1 -1
  12. package/dist-lib/beta.cjs +1 -1
  13. package/dist-lib/beta.mjs +1 -1
  14. package/dist-lib/bridge-constants.cjs +1 -1
  15. package/dist-lib/bridge-contract-input.cjs +1 -1
  16. package/dist-lib/bridge-contract-input.mjs +1 -1
  17. package/dist-lib/bridge-contract.cjs +1 -1
  18. package/dist-lib/bridge-contract.mjs +1 -1
  19. package/dist-lib/capture-contract.cjs +1 -1
  20. package/dist-lib/capture-contract.mjs +1 -1
  21. package/dist-lib/cli-constants.cjs +1 -1
  22. package/dist-lib/cloud-contract.cjs +1 -1
  23. package/dist-lib/cloud-contract.mjs +1 -1
  24. package/dist-lib/cloud.cjs +1 -1
  25. package/dist-lib/cloud.mjs +1 -1
  26. package/dist-lib/config.cjs +1 -1
  27. package/dist-lib/detox/index.cjs +15 -2
  28. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  29. package/dist-lib/home-paths.cjs +1 -1
  30. package/dist-lib/host/bridge-host.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  32. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  33. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  34. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  35. package/dist-lib/host/websocket-proxy.cjs +1 -1
  36. package/dist-lib/index.cjs +43 -15
  37. package/dist-lib/jump-to-source-babel.cjs +1 -1
  38. package/dist-lib/jump-to-source-native.cjs +1 -1
  39. package/dist-lib/menu.cjs +1 -1
  40. package/dist-lib/menu.mjs +1 -1
  41. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  42. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  43. package/dist-lib/metro-production-bundle.cjs +1 -1
  44. package/dist-lib/metro-production-bundle.mjs +1 -1
  45. package/dist-lib/metro.cjs +1 -1
  46. package/dist-lib/profiles.cjs +1 -1
  47. package/dist-lib/public-brand.cjs +1 -1
  48. package/dist-lib/react-native-host-modules.cjs +1 -1
  49. package/dist-lib/react-native-host-modules.mjs +1 -1
  50. package/dist-lib/render-mode.cjs +1 -1
  51. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  52. package/dist-lib/sdk.cjs +43 -15
  53. package/dist-lib/sdk.mjs +43 -15
  54. package/dist-lib/skills.cjs +766 -58
  55. package/dist-lib/vite.cjs +1 -1
  56. package/package.json +1 -1
  57. package/src/sim-client.ts +4 -0
@@ -202,8 +202,20 @@ export async function tapResolvedTarget(
202
202
  let lastPayload: any = null
203
203
  let lastResult: any = null
204
204
 
205
- const canWaitForIdle = bridge.plane !== 'cloud' && timing.initialWaitMs > 0
206
- if (canWaitForIdle) {
205
+ // a CPU simulator only advances its animations while a command holds its
206
+ // clock, so a sheet that was still sliding in when the last command returned
207
+ // is still mid-slide now. settling first is what lets the resolved center and
208
+ // the hit test below describe the same tree.
209
+ const settleCloud = async () => {
210
+ try {
211
+ await bridge.send({ type: 'settle' })
212
+ } catch {
213
+ // best-effort readiness gate; the retry loop decides success.
214
+ }
215
+ }
216
+ if (bridge.plane === 'cloud') {
217
+ await settleCloud()
218
+ } else if (timing.initialWaitMs > 0) {
207
219
  try {
208
220
  await waitForSootsimIdle({
209
221
  bridge,
@@ -263,6 +275,7 @@ export async function tapResolvedTarget(
263
275
  lastOffscreenAt = null
264
276
  const requestedTarget = tapTargetFromPayload(payload, args.textFallback)
265
277
  const { tree } = await inspectTree(bridge, 50)
278
+ let moved = false
266
279
  if (Array.isArray(tree) && tree.length > 0) {
267
280
  const hit = hitTestSemanticTree(tree, payload.cx, payload.cy)
268
281
  const matched =
@@ -271,30 +284,52 @@ export async function tapResolvedTarget(
271
284
  hit.ancestors.some((ancestor) =>
272
285
  nodeMatchesRequested(ancestor, requestedTarget),
273
286
  ))
274
- if (hit && !matched) {
287
+ // a plain view over the point does not cover: the engine's hit-test
288
+ // passes through unpainted, non-pressable views (a transparent modal
289
+ // screen wrapping a dialog), and content behind an opaque surface is
290
+ // already dropped from the tree. only a pressable in the hit chain
291
+ // or a painted text leaf swallows the tap.
292
+ const blocks =
293
+ hit !== null &&
294
+ (hit.node.type === 'text' ||
295
+ hit.node.pressable === true ||
296
+ hit.ancestors.some((ancestor) => ancestor.pressable === true))
297
+ if (hit && !matched && blocks) {
298
+ // the point landed inside the target's own container but not on
299
+ // the target: it moved between the resolve and this inspect (a
300
+ // sheet still animating in), which is a retry, not a cover.
301
+ moved = subtreeMatchesRequested(hit.node, requestedTarget)
275
302
  lastResult = {
276
303
  hit: false,
277
- reason: 'target-covered',
304
+ reason: moved ? 'target-moved' : 'target-covered',
278
305
  requestedTarget,
279
306
  coordinateTarget: coveringNodeSummary(hit.node),
280
307
  }
281
- return { payload, result: lastResult, attempts, failure: 'missed' }
308
+ if (!moved)
309
+ return { payload, result: lastResult, attempts, failure: 'missed' }
282
310
  }
283
311
  }
284
- const result = await tapCoordinates(
285
- bridge,
286
- payload.cx,
287
- payload.cy,
288
- requestedTarget,
289
- )
290
- lastResult = result
291
- if (isTapSuccess(result)) return { payload, result, attempts }
312
+ if (!moved) {
313
+ const result = await tapCoordinates(
314
+ bridge,
315
+ payload.cx,
316
+ payload.cy,
317
+ requestedTarget,
318
+ )
319
+ lastResult = result
320
+ if (isTapSuccess(result)) return { payload, result, attempts }
321
+ }
292
322
  }
293
323
  }
294
324
 
295
325
  const remaining = deadline - Date.now()
296
326
  if (remaining <= 0) break
297
- if (bridge.plane === 'cloud' || timing.retryWaitMs <= 0) break
327
+ if (bridge.plane === 'cloud') {
328
+ if (lastResult?.reason !== 'target-moved' || attempts >= 3) break
329
+ await settleCloud()
330
+ continue
331
+ }
332
+ if (timing.retryWaitMs <= 0) break
298
333
  try {
299
334
  await waitForSootsimIdle({
300
335
  bridge,
@@ -315,6 +350,20 @@ export async function tapResolvedTarget(
315
350
  }
316
351
  }
317
352
 
353
+ function subtreeMatchesRequested(
354
+ node: SimSemanticNode,
355
+ requested: TapTargetSummary,
356
+ ): boolean {
357
+ for (const child of node.children ?? []) {
358
+ if (
359
+ nodeMatchesRequested(child, requested) ||
360
+ subtreeMatchesRequested(child, requested)
361
+ )
362
+ return true
363
+ }
364
+ return false
365
+ }
366
+
318
367
  export async function tapCoordinates(
319
368
  bridge: InspectBridge,
320
369
  x: number,
@@ -818,6 +818,25 @@ async function waitForKeyboardVisible(
818
818
  return getKeyboardState(bridge)
819
819
  }
820
820
 
821
+ /**
822
+ * keys for a CPU simulator. it has no keyboard bridge to probe and refuses the
823
+ * `keyboard` command, so its `perform` presses each character against
824
+ * whatever holds focus and fails the batch when nothing does.
825
+ */
826
+ async function performCloudKeys(
827
+ bridge: WsBridge,
828
+ steps: Array<{ type: 'type'; text: string } | { type: 'key'; key: string }>,
829
+ actionLabel: string,
830
+ ): Promise<void> {
831
+ const result: PerformResult = await bridge.send({ type: 'perform', steps })
832
+ if (result.ok) return
833
+ const failed = result.steps.find((step) => !step.ok)
834
+ console.error(
835
+ ` ${actionLabel} failed: ${failed?.error ?? result.error ?? 'no text input had focus'}. focus an input first with rnx do tap-id or rnx do type-into.`,
836
+ )
837
+ rnxExit(1)
838
+ }
839
+
821
840
  async function requireVisualKeyboard(bridge: WsBridge, actionLabel: string) {
822
841
  const state = await getKeyboardState(bridge)
823
842
  if (state.visible && (state.focusedInput || state.hostedEditorFocused)) return state
@@ -2457,6 +2476,26 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2457
2476
  console.error(inspectUsage('type-into', '<id> <text>'))
2458
2477
  rnxExit(1)
2459
2478
  }
2479
+ if (bridge.plane === 'cloud') {
2480
+ const outcome = await tapById(bridge, targetId, { agent: isAgentEnv() })
2481
+ if (!outcome.payload || typeof outcome.payload.cx !== 'number') {
2482
+ console.error(` not found: ${targetId}`)
2483
+ await printSimilarTestIds(bridge, targetId)
2484
+ rnxExit(1)
2485
+ }
2486
+ if (!isTapSuccess(outcome.result)) {
2487
+ printTapFailure(`id "${targetId}"`, outcome)
2488
+ rnxExit(1)
2489
+ }
2490
+ await performCloudKeys(bridge, [{ type: 'type', text }], 'type-into')
2491
+ await recordInspectAction(
2492
+ 'inspect type-into',
2493
+ { tapOn: { id: targetId }, inputText: text },
2494
+ `type-into #${targetId} ${JSON.stringify(text)}`,
2495
+ )
2496
+ console.log(` typed into ${targetId}: ${JSON.stringify(text)}`)
2497
+ break
2498
+ }
2460
2499
  // step 1: find the element
2461
2500
  const tiArg = JSON.stringify(targetId)
2462
2501
  const tiPayload = await bridge.send({
@@ -2582,6 +2621,16 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2582
2621
  console.error(inspectUsage('type', '<text>'))
2583
2622
  rnxExit(1)
2584
2623
  }
2624
+ if (bridge.plane === 'cloud') {
2625
+ await performCloudKeys(bridge, [{ type: 'type', text }], 'type')
2626
+ await recordInspectAction(
2627
+ 'inspect type',
2628
+ { inputText: text },
2629
+ `type ${JSON.stringify(text)}`,
2630
+ )
2631
+ console.log(` typed: ${JSON.stringify(text)}`)
2632
+ break
2633
+ }
2585
2634
  const keyboardState = await requireVisualKeyboard(bridge, 'type')
2586
2635
  await bridge.send({ type: 'keyboard', action: 'type', text })
2587
2636
  const outputText = redactTextForKeyboardState(text, keyboardState as any)
@@ -2606,8 +2655,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2606
2655
  console.error(inspectUsage('key', '<name>'))
2607
2656
  rnxExit(1)
2608
2657
  }
2609
- await requireVisualKeyboard(bridge, 'key')
2610
- await bridge.send({ type: 'keyboard', action: 'press', text: name })
2658
+ if (bridge.plane === 'cloud') {
2659
+ await performCloudKeys(bridge, [{ type: 'key', key: name }], 'key')
2660
+ } else {
2661
+ await requireVisualKeyboard(bridge, 'key')
2662
+ await bridge.send({ type: 'keyboard', action: 'press', text: name })
2663
+ }
2611
2664
  await recordInspectAction('inspect key', { pressKey: name }, `key ${name}`)
2612
2665
  console.log(` pressed: ${name}`)
2613
2666
  break
@@ -2619,9 +2672,17 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2619
2672
  console.error(inspectUsage('key-sequence', '<key> [<key> ...]'))
2620
2673
  rnxExit(1)
2621
2674
  }
2622
- await requireVisualKeyboard(bridge, 'key-sequence')
2623
- for (const key of keys) {
2624
- await bridge.send({ type: 'keyboard', action: 'press', text: key })
2675
+ if (bridge.plane === 'cloud') {
2676
+ await performCloudKeys(
2677
+ bridge,
2678
+ keys.map((key) => ({ type: 'key' as const, key })),
2679
+ 'key-sequence',
2680
+ )
2681
+ } else {
2682
+ await requireVisualKeyboard(bridge, 'key-sequence')
2683
+ for (const key of keys) {
2684
+ await bridge.send({ type: 'keyboard', action: 'press', text: key })
2685
+ }
2625
2686
  }
2626
2687
  await recordInspectAction(
2627
2688
  'inspect key-sequence',
package/cli/ws-bridge.ts CHANGED
@@ -912,6 +912,9 @@ function describeVisibleSimCandidate(sims: BridgeSimInfo[], currentId?: string |
912
912
  export async function checkSimHealth(
913
913
  bridge: WsBridge,
914
914
  ): Promise<{ hidden: boolean; warned: boolean; simId?: string | null }> {
915
+ // a CPU simulator has no document to be hidden, and the probe below is an
916
+ // `evaluate` the cloud runtime refuses by name.
917
+ if (bridge.plane === 'cloud') return { hidden: false, warned: false }
915
918
  try {
916
919
  const probe = (await bridge.send({
917
920
  type: 'evaluate',
package/detox/index.ts CHANGED
@@ -1333,7 +1333,7 @@ export const device = {
1333
1333
  // scoped reaper owns the whole Chrome process tree if Detox is interrupted.
1334
1334
  const launched = await launchReapedChromeScoped(
1335
1335
  (options) => chromium.launch(options),
1336
- { headless: true },
1336
+ { headless: true, ignoreDefaultArgs: ['--disable-popup-blocking'] },
1337
1337
  )
1338
1338
  _browser = launched.browser
1339
1339
  _reapBrowserNow = launched.reapNow
@@ -2322,6 +2322,17 @@ export const device = {
2322
2322
  }
2323
2323
  },
2324
2324
 
2325
+ // a real browser key press. host.ts turns window keydown into the
2326
+ // `sootsim:hostKey` shell event that overlays listen to, so this drives the
2327
+ // same path a desktop user does for keys no device button covers (Escape).
2328
+ async pressKey(key: string) {
2329
+ const page = getPage()
2330
+ await page.keyboard.press(key)
2331
+ if (_synchronizationEnabled) {
2332
+ await waitForSootsimIdle(page)
2333
+ }
2334
+ },
2335
+
2325
2336
  // raw coordinate tap, bypassing the element-based visibility/hit-test path.
2326
2337
  // mirrors detox 20.x device.tap({ x, y }) on real iOS — used when the
2327
2338
  // target is occluded by a native UIWindow (e.g. UIMenu's dim layer) so
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_MAX_MS = 5e3;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_DEFAULT_MS = 500;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/capture-contract.ts
4
4
  var RNX_SCREEN_CAPTURE_VERSION = 1;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-contract.ts
4
4
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -731,6 +731,9 @@ function softwareChromeLaunchOptions(opts) {
731
731
  return software;
732
732
  }
733
733
  function chromeLaunchOptions(opts = {}, runtime = currentRuntime()) {
734
+ if (signalShutdownClaimed) {
735
+ opts = { ...opts, handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false };
736
+ }
734
737
  return softwareChromeAllowed(runtime) ? softwareChromeLaunchOptions(opts) : gpuChromeLaunchOptions(opts, runtime);
735
738
  }
736
739
  async function launchReapedChromeScoped(launch, opts = {}, rendererTarget, policy = {}) {
@@ -2741,7 +2744,7 @@ var device = {
2741
2744
  if (!_browser) {
2742
2745
  const launched = await launchReapedChromeScoped(
2743
2746
  (options) => import_playwright.chromium.launch(options),
2744
- { headless: true }
2747
+ { headless: true, ignoreDefaultArgs: ["--disable-popup-blocking"] }
2745
2748
  );
2746
2749
  _browser = launched.browser;
2747
2750
  _reapBrowserNow = launched.reapNow;
@@ -3380,6 +3383,16 @@ var device = {
3380
3383
  await waitForSootsimIdle(page);
3381
3384
  }
3382
3385
  },
3386
+ // a real browser key press. host.ts turns window keydown into the
3387
+ // `sootsim:hostKey` shell event that overlays listen to, so this drives the
3388
+ // same path a desktop user does for keys no device button covers (Escape).
3389
+ async pressKey(key) {
3390
+ const page = getPage();
3391
+ await page.keyboard.press(key);
3392
+ if (_synchronizationEnabled) {
3393
+ await waitForSootsimIdle(page);
3394
+ }
3395
+ },
3383
3396
  // raw coordinate tap, bypassing the element-based visibility/hit-test path.
3384
3397
  // mirrors detox 20.x device.tap({ x, y }) on real iOS — used when the
3385
3398
  // target is occluded by a native UIWindow (e.g. UIMenu's dim layer) so
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;
@@ -2214,8 +2214,15 @@ async function tapResolvedTarget(bridge, args) {
2214
2214
  let attempts = 0;
2215
2215
  let lastPayload = null;
2216
2216
  let lastResult = null;
2217
- const canWaitForIdle = bridge.plane !== "cloud" && timing.initialWaitMs > 0;
2218
- if (canWaitForIdle) {
2217
+ const settleCloud = async () => {
2218
+ try {
2219
+ await bridge.send({ type: "settle" });
2220
+ } catch {
2221
+ }
2222
+ };
2223
+ if (bridge.plane === "cloud") {
2224
+ await settleCloud();
2225
+ } else if (timing.initialWaitMs > 0) {
2219
2226
  try {
2220
2227
  await waitForSootsimIdle({
2221
2228
  bridge,
@@ -2255,34 +2262,45 @@ async function tapResolvedTarget(bridge, args) {
2255
2262
  lastOffscreenAt = null;
2256
2263
  const requestedTarget = tapTargetFromPayload(payload, args.textFallback);
2257
2264
  const { tree } = await inspectTree(bridge, 50);
2265
+ let moved = false;
2258
2266
  if (Array.isArray(tree) && tree.length > 0) {
2259
2267
  const hit = hitTestSemanticTree(tree, payload.cx, payload.cy);
2260
2268
  const matched = hit !== null && (nodeMatchesRequested(hit.node, requestedTarget) || hit.ancestors.some(
2261
2269
  (ancestor) => nodeMatchesRequested(ancestor, requestedTarget)
2262
2270
  ));
2263
- if (hit && !matched) {
2271
+ const blocks = hit !== null && (hit.node.type === "text" || hit.node.pressable === true || hit.ancestors.some((ancestor) => ancestor.pressable === true));
2272
+ if (hit && !matched && blocks) {
2273
+ moved = subtreeMatchesRequested(hit.node, requestedTarget);
2264
2274
  lastResult = {
2265
2275
  hit: false,
2266
- reason: "target-covered",
2276
+ reason: moved ? "target-moved" : "target-covered",
2267
2277
  requestedTarget,
2268
2278
  coordinateTarget: coveringNodeSummary(hit.node)
2269
2279
  };
2270
- return { payload, result: lastResult, attempts, failure: "missed" };
2280
+ if (!moved)
2281
+ return { payload, result: lastResult, attempts, failure: "missed" };
2271
2282
  }
2272
2283
  }
2273
- const result = await tapCoordinates(
2274
- bridge,
2275
- payload.cx,
2276
- payload.cy,
2277
- requestedTarget
2278
- );
2279
- lastResult = result;
2280
- if (isTapSuccess(result)) return { payload, result, attempts };
2284
+ if (!moved) {
2285
+ const result = await tapCoordinates(
2286
+ bridge,
2287
+ payload.cx,
2288
+ payload.cy,
2289
+ requestedTarget
2290
+ );
2291
+ lastResult = result;
2292
+ if (isTapSuccess(result)) return { payload, result, attempts };
2293
+ }
2281
2294
  }
2282
2295
  }
2283
2296
  const remaining = deadline - Date.now();
2284
2297
  if (remaining <= 0) break;
2285
- if (bridge.plane === "cloud" || timing.retryWaitMs <= 0) break;
2298
+ if (bridge.plane === "cloud") {
2299
+ if (lastResult?.reason !== "target-moved" || attempts >= 3) break;
2300
+ await settleCloud();
2301
+ continue;
2302
+ }
2303
+ if (timing.retryWaitMs <= 0) break;
2286
2304
  try {
2287
2305
  await waitForSootsimIdle({
2288
2306
  bridge,
@@ -2301,6 +2319,13 @@ async function tapResolvedTarget(bridge, args) {
2301
2319
  failure: lastPayload && typeof lastPayload.cx === "number" ? "missed" : "not-found"
2302
2320
  };
2303
2321
  }
2322
+ function subtreeMatchesRequested(node, requested) {
2323
+ for (const child of node.children ?? []) {
2324
+ if (nodeMatchesRequested(child, requested) || subtreeMatchesRequested(child, requested))
2325
+ return true;
2326
+ }
2327
+ return false;
2328
+ }
2304
2329
  async function tapCoordinates(bridge, x, y, target) {
2305
2330
  return bridge.send({
2306
2331
  type: "tap",
@@ -2599,6 +2624,9 @@ var SimClient = class {
2599
2624
  this.bridge = bridge;
2600
2625
  this.simId = simId;
2601
2626
  }
2627
+ get plane() {
2628
+ return this.bridge.plane;
2629
+ }
2602
2630
  // --- transport (WsBridge/InspectBridge) ---
2603
2631
  send(cmd, opts) {
2604
2632
  if (this.closed) {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.456 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.458 | (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;