rnxsim 0.1.506 → 0.1.508

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 (61) hide show
  1. package/cli/commands/control.ts +3 -3
  2. package/cli/commands/flow.ts +8 -12
  3. package/cli/commands/platform.ts +2 -1
  4. package/cli/ws-bridge.ts +28 -15
  5. package/detox/index.ts +24 -0
  6. package/dist-lib/agent-daemon-client.cjs +1 -1
  7. package/dist-lib/agent-events.cjs +1 -1
  8. package/dist-lib/agent-identity.cjs +1 -1
  9. package/dist-lib/agent-sessions.cjs +1 -1
  10. package/dist-lib/attached-projects.cjs +1 -1
  11. package/dist-lib/auth/shared-session.cjs +1 -1
  12. package/dist-lib/backend-origin.cjs +1 -1
  13. package/dist-lib/beta.cjs +1 -1
  14. package/dist-lib/beta.mjs +1 -1
  15. package/dist-lib/bridge-constants.cjs +1 -1
  16. package/dist-lib/bridge-contract-input.cjs +1 -1
  17. package/dist-lib/bridge-contract-input.mjs +1 -1
  18. package/dist-lib/bridge-contract.cjs +1 -1
  19. package/dist-lib/bridge-contract.mjs +1 -1
  20. package/dist-lib/capture-contract.cjs +1 -1
  21. package/dist-lib/capture-contract.mjs +1 -1
  22. package/dist-lib/cli-constants.cjs +1 -1
  23. package/dist-lib/cloud-contract.cjs +1 -1
  24. package/dist-lib/cloud-contract.mjs +1 -1
  25. package/dist-lib/cloud.cjs +1 -1
  26. package/dist-lib/cloud.mjs +1 -1
  27. package/dist-lib/config.cjs +1 -1
  28. package/dist-lib/detox/index.cjs +24 -1
  29. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  30. package/dist-lib/home-paths.cjs +1 -1
  31. package/dist-lib/host/bridge-host.cjs +1 -1
  32. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  33. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  34. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  35. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  36. package/dist-lib/host/websocket-proxy.cjs +1 -1
  37. package/dist-lib/index.cjs +36 -20
  38. package/dist-lib/jump-to-source-babel.cjs +1 -1
  39. package/dist-lib/jump-to-source-native.cjs +1 -1
  40. package/dist-lib/menu.cjs +1 -1
  41. package/dist-lib/menu.mjs +1 -1
  42. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  43. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  44. package/dist-lib/metro-production-bundle.cjs +1 -1
  45. package/dist-lib/metro-production-bundle.mjs +1 -1
  46. package/dist-lib/metro.cjs +1 -1
  47. package/dist-lib/profiles.cjs +1 -1
  48. package/dist-lib/public-brand.cjs +1 -1
  49. package/dist-lib/react-native-host-modules.cjs +1 -1
  50. package/dist-lib/react-native-host-modules.mjs +1 -1
  51. package/dist-lib/render-mode.cjs +1 -1
  52. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  53. package/dist-lib/sdk.cjs +1 -1
  54. package/dist-lib/sdk.mjs +1 -1
  55. package/dist-lib/skills.cjs +26 -21
  56. package/dist-lib/swift.cjs +507 -0
  57. package/dist-lib/vite.cjs +185 -5
  58. package/package.json +6 -1
  59. package/src/swift.ts +6 -0
  60. package/src/vite-plugin-one.ts +8 -0
  61. package/src/vite-plugin-swift.ts +254 -0
@@ -1299,7 +1299,7 @@ export async function runLinkCommand(args: string[], opts: ControlCommandOptions
1299
1299
  export async function runOpenCommand(
1300
1300
  args: string[],
1301
1301
  opts: ControlCommandOptions = {},
1302
- ): Promise<number | undefined> {
1302
+ ): Promise<{ simId: string; launched: boolean } | undefined> {
1303
1303
  const parsed = parseBridgeCliArgs(args, {
1304
1304
  port: opts.port,
1305
1305
  commandTimeoutMs: opts.timeoutMs,
@@ -1678,7 +1678,7 @@ export async function runOpenCommand(
1678
1678
  quiet,
1679
1679
  )
1680
1680
  await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args)
1681
- return parsed.wsPort
1681
+ return { simId: targetSim.id, launched: false }
1682
1682
  }
1683
1683
  } finally {
1684
1684
  bridge.close()
@@ -1756,7 +1756,7 @@ export async function runOpenCommand(
1756
1756
  signalDriverLaunchConnected(result)
1757
1757
  printOpenedSim(openUrl, match, `${driver.name} driver`, quiet)
1758
1758
  await maybeDescribeAfterOpen(parsed.wsPort, match.id, args)
1759
- return parsed.wsPort
1759
+ return { simId: match.id, launched: true }
1760
1760
  }
1761
1761
 
1762
1762
  async function runUseLikeCommand(args: string[], opts: ControlCommandOptions = {}) {
@@ -541,22 +541,18 @@ flow extension:
541
541
  openArgs.push('--headless')
542
542
  }
543
543
  if (proofMode) openArgs.push('--proof')
544
- await runOpenCommand(openArgs, {
544
+ const opened = await runOpenCommand(openArgs, {
545
545
  port: parsedBridgeArgs.wsPort,
546
546
  timeoutMs: parsedBridgeArgs.commandTimeoutMs,
547
547
  runtimeConfig: targetAppResolution.runtimeConfig,
548
548
  })
549
- // a flow that opened its own sim owns it, and owning it means closing it.
550
- // this used to be claimed only for `--driver` runs, so a `--new` run
551
- // stranded its browser: the detached host's watchdog polls the *top*
552
- // ancestor (getStableOwnerPid -> findTopAncestor), which is the shell or
553
- // agent session, not the run. that pid lives for hours, so the watchdog
554
- // stayed happy and every flow left one more Chrome behind.
555
- closeFlowOwnedSimAfterRun = effectiveOpenInNewSim || !!driverFlag
556
- if (closeFlowOwnedSimAfterRun) {
557
- const openedSimId = readCurrentSimId()
558
- if (openedSimId) ownedSimIds.add(openedSimId)
559
- }
549
+ // a flow that launched its own sim owns it, and owning it means closing it.
550
+ // the detached host's watchdog polls the *top* ancestor
551
+ // (getStableOwnerPid -> findTopAncestor), which is the shell, agent
552
+ // session, or runner daemon, not the run. that pid can live for days, so
553
+ // a launched sim nobody closes stays open and keeps its flow lock.
554
+ closeFlowOwnedSimAfterRun = opened?.launched === true || !!driverFlag
555
+ if (closeFlowOwnedSimAfterRun && opened) ownedSimIds.add(opened.simId)
560
556
  }
561
557
 
562
558
  const resolvedBridgeArgs = parseBridgeCliArgs(args, FLOW_BRIDGE_ARG_OPTIONS)
@@ -294,7 +294,8 @@ export async function runPlatformCommand(
294
294
  }
295
295
 
296
296
  const { runOpenCommand } = await import('./control')
297
- return runOpenCommand(args, { port: opts.port })
297
+ await runOpenCommand(args, { port: opts.port })
298
+ return 0
298
299
  }
299
300
 
300
301
  /** Runs the existing remote session path without changing the local platform commands. */
package/cli/ws-bridge.ts CHANGED
@@ -616,25 +616,35 @@ export function createBridge(wsPort: number, opts: WsBridgeOptions = {}): WsBrid
616
616
 
617
617
  let warnedAboutContention = false
618
618
  let noticedTarget = false
619
- // the browser host behind each target, learned while that sim is still
620
- // connected. a reload changes the sim id but not the host.
621
- const hostPidBySimId = new Map<string, number>()
619
+ // the browser host and connection behind each target, learned while that
620
+ // sim is still connected. a reload changes the connection, and sometimes the
621
+ // sim id, but not the host.
622
+ const lineageBySimId = new Map<string, { hostPid: number; connectedAt: number }>()
622
623
  const lineageLookupBySimId = new Map<string, Promise<void>>()
623
624
 
624
625
  // a reload retires the socket but keeps the browser host. the replacement
625
626
  // can receive a new sim id or restore the prior one from session storage.
626
- // the restored id is definitive; a new id must be the only same-host match.
627
+ // the unloading page's socket stays listed as open until its close lands, so
628
+ // only a connection newer than the known one is a replacement. the restored
629
+ // id is definitive; a new id must be the only newer same-host match.
627
630
  function pickReloadedTarget(sims: unknown, retiredSimId: string): string | null {
628
- const pinnedHostPid = hostPidBySimId.get(retiredSimId)
629
- if (pinnedHostPid === undefined) return null
631
+ const lineage = lineageBySimId.get(retiredSimId)
632
+ if (!lineage) return null
630
633
  const matches = (Array.isArray(sims) ? (sims as BridgeSimInfo[]) : []).filter(
631
- (sim) => sim.readyState === 'open' && sim.meta?.sootsimHostPid === pinnedHostPid,
634
+ (sim) =>
635
+ sim.readyState === 'open' &&
636
+ sim.meta?.sootsimHostPid === lineage.hostPid &&
637
+ sim.connectedAt > lineage.connectedAt,
632
638
  )
633
- const restored = matches.find((sim) => sim.id === retiredSimId)
634
- if (restored) return restored.id
635
- if (matches.length !== 1) return null
636
- hostPidBySimId.set(matches[0].id, pinnedHostPid)
637
- return matches[0].id
639
+ const successor =
640
+ matches.find((sim) => sim.id === retiredSimId) ??
641
+ (matches.length === 1 ? matches[0] : null)
642
+ if (!successor) return null
643
+ lineageBySimId.set(successor.id, {
644
+ hostPid: lineage.hostPid,
645
+ connectedAt: successor.connectedAt,
646
+ })
647
+ return successor.id
638
648
  }
639
649
 
640
650
  // print a one-line notice on first sim-scoped command so agents/users see
@@ -761,7 +771,7 @@ export function createBridge(wsPort: number, opts: WsBridgeOptions = {}): WsBrid
761
771
  if (
762
772
  targetedSimId &&
763
773
  cmd.type !== 'bridge:list-sims' &&
764
- !hostPidBySimId.has(targetedSimId)
774
+ !lineageBySimId.has(targetedSimId)
765
775
  ) {
766
776
  let lookup = lineageLookupBySimId.get(targetedSimId)
767
777
  if (!lookup) {
@@ -773,8 +783,11 @@ export function createBridge(wsPort: number, opts: WsBridgeOptions = {}): WsBrid
773
783
  (sim) => sim.id === targetedSimId,
774
784
  )
775
785
  const hostPid = targeted?.meta?.sootsimHostPid
776
- if (typeof hostPid === 'number') {
777
- hostPidBySimId.set(targetedSimId, hostPid)
786
+ if (targeted && typeof hostPid === 'number') {
787
+ lineageBySimId.set(targetedSimId, {
788
+ hostPid,
789
+ connectedAt: targeted.connectedAt,
790
+ })
778
791
  }
779
792
  } catch {
780
793
  // lineage enables fail-closed reload following, but a failed
package/detox/index.ts CHANGED
@@ -2594,6 +2594,30 @@ export const device = {
2594
2594
  }
2595
2595
  },
2596
2596
 
2597
+ // window-point counterpart to element(...).longPress, for a target detox can
2598
+ // only address by coordinate (a native tab cell, a shell chrome control).
2599
+ async longPress(point: { x: number; y: number }, durationMs = 1000) {
2600
+ const page = getPage()
2601
+ const { x, y } = point
2602
+ await page.evaluate(
2603
+ async ({ x: px, y: py, ms }) => {
2604
+ const longPress = window.SootSim?.bridges?.interact?.longPress
2605
+ if (typeof longPress !== 'function') {
2606
+ throw new Error('sootsim longPress bridge is not installed')
2607
+ }
2608
+ const hit = await longPress(px, py, ms)
2609
+ if (!hit) {
2610
+ throw new Error(`sootsim longPress missed at ${px},${py}`)
2611
+ }
2612
+ },
2613
+ { x, y, ms: durationMs },
2614
+ )
2615
+ await page.waitForTimeout(50)
2616
+ if (_synchronizationEnabled) {
2617
+ await waitForSootsimIdle(page)
2618
+ }
2619
+ },
2620
+
2597
2621
  async sendToHome() {
2598
2622
  const page = getPage()
2599
2623
  _suspendedAppId = await page.evaluate(async () => {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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;
@@ -3702,6 +3702,29 @@ var device = {
3702
3702
  await waitForSootsimIdle(page);
3703
3703
  }
3704
3704
  },
3705
+ // window-point counterpart to element(...).longPress, for a target detox can
3706
+ // only address by coordinate (a native tab cell, a shell chrome control).
3707
+ async longPress(point, durationMs = 1e3) {
3708
+ const page = getPage();
3709
+ const { x, y } = point;
3710
+ await page.evaluate(
3711
+ async ({ x: px, y: py, ms }) => {
3712
+ const longPress = window.SootSim?.bridges?.interact?.longPress;
3713
+ if (typeof longPress !== "function") {
3714
+ throw new Error("sootsim longPress bridge is not installed");
3715
+ }
3716
+ const hit = await longPress(px, py, ms);
3717
+ if (!hit) {
3718
+ throw new Error(`sootsim longPress missed at ${px},${py}`);
3719
+ }
3720
+ },
3721
+ { x, y, ms: durationMs }
3722
+ );
3723
+ await page.waitForTimeout(50);
3724
+ if (_synchronizationEnabled) {
3725
+ await waitForSootsimIdle(page);
3726
+ }
3727
+ },
3705
3728
  async sendToHome() {
3706
3729
  const page = getPage();
3707
3730
  _suspendedAppId = await page.evaluate(async () => {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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;
@@ -1092,19 +1092,21 @@ function createBridge(wsPort, opts = {}) {
1092
1092
  });
1093
1093
  let warnedAboutContention = false;
1094
1094
  let noticedTarget = false;
1095
- const hostPidBySimId = /* @__PURE__ */ new Map();
1095
+ const lineageBySimId = /* @__PURE__ */ new Map();
1096
1096
  const lineageLookupBySimId = /* @__PURE__ */ new Map();
1097
1097
  function pickReloadedTarget(sims, retiredSimId) {
1098
- const pinnedHostPid = hostPidBySimId.get(retiredSimId);
1099
- if (pinnedHostPid === void 0) return null;
1098
+ const lineage = lineageBySimId.get(retiredSimId);
1099
+ if (!lineage) return null;
1100
1100
  const matches = (Array.isArray(sims) ? sims : []).filter(
1101
- (sim) => sim.readyState === "open" && sim.meta?.sootsimHostPid === pinnedHostPid
1101
+ (sim) => sim.readyState === "open" && sim.meta?.sootsimHostPid === lineage.hostPid && sim.connectedAt > lineage.connectedAt
1102
1102
  );
1103
- const restored = matches.find((sim) => sim.id === retiredSimId);
1104
- if (restored) return restored.id;
1105
- if (matches.length !== 1) return null;
1106
- hostPidBySimId.set(matches[0].id, pinnedHostPid);
1107
- return matches[0].id;
1103
+ const successor = matches.find((sim) => sim.id === retiredSimId) ?? (matches.length === 1 ? matches[0] : null);
1104
+ if (!successor) return null;
1105
+ lineageBySimId.set(successor.id, {
1106
+ hostPid: lineage.hostPid,
1107
+ connectedAt: successor.connectedAt
1108
+ });
1109
+ return successor.id;
1108
1110
  }
1109
1111
  function maybeNoticeTarget(cmdType, simId) {
1110
1112
  if (noticedTarget) return;
@@ -1194,7 +1196,7 @@ function createBridge(wsPort, opts = {}) {
1194
1196
  const sentSimId = opts.simIdSource === "flag" ? opts.simId : readCurrentSimId() ?? opts.simId;
1195
1197
  const targetedSimId = typeof cmd.simId === "string" && cmd.simId ? cmd.simId : sentSimId;
1196
1198
  try {
1197
- if (targetedSimId && cmd.type !== "bridge:list-sims" && !hostPidBySimId.has(targetedSimId)) {
1199
+ if (targetedSimId && cmd.type !== "bridge:list-sims" && !lineageBySimId.has(targetedSimId)) {
1198
1200
  let lookup = lineageLookupBySimId.get(targetedSimId);
1199
1201
  if (!lookup) {
1200
1202
  lookup = (async () => {
@@ -1205,8 +1207,11 @@ function createBridge(wsPort, opts = {}) {
1205
1207
  (sim) => sim.id === targetedSimId
1206
1208
  );
1207
1209
  const hostPid = targeted?.meta?.sootsimHostPid;
1208
- if (typeof hostPid === "number") {
1209
- hostPidBySimId.set(targetedSimId, hostPid);
1210
+ if (targeted && typeof hostPid === "number") {
1211
+ lineageBySimId.set(targetedSimId, {
1212
+ hostPid,
1213
+ connectedAt: targeted.connectedAt
1214
+ });
1210
1215
  }
1211
1216
  } catch {
1212
1217
  } finally {
@@ -3868,6 +3873,17 @@ function serveRuntimeFile(req, res, fullPath) {
3868
3873
  import_fs3.default.createReadStream(fullPath).pipe(res);
3869
3874
  }
3870
3875
 
3876
+ // src/vite-plugin-swift.ts
3877
+ var import_node_child_process2 = require("node:child_process");
3878
+ var import_node_os2 = __toESM(require("node:os"), 1);
3879
+ var import_node_path6 = __toESM(require("node:path"), 1);
3880
+ var import_node_util = require("node:util");
3881
+ var run = (0, import_node_util.promisify)(import_node_child_process2.execFile);
3882
+ var TOOLCHAIN_BIN = import_node_path6.default.join(
3883
+ import_node_os2.default.homedir(),
3884
+ "Library/Developer/Toolchains/swift-6.2-RELEASE.xctoolchain/usr/bin"
3885
+ );
3886
+
3871
3887
  // src/vite-plugin-one.ts
3872
3888
  function rnxPlugin(options = {}) {
3873
3889
  const prefix2 = options.prefix || "/__soot";
@@ -4192,13 +4208,13 @@ function resolveMetroPort(server) {
4192
4208
  var metro_plugin_default = withRNX;
4193
4209
 
4194
4210
  // src/jump-to-source-babel.ts
4195
- function normalizeSourcePath(path8) {
4196
- const queryStart = path8.indexOf("?");
4197
- const clean = queryStart >= 0 ? path8.slice(0, queryStart) : path8;
4211
+ function normalizeSourcePath(path9) {
4212
+ const queryStart = path9.indexOf("?");
4213
+ const clean = queryStart >= 0 ? path9.slice(0, queryStart) : path9;
4198
4214
  return clean.replace(/\\/g, "/");
4199
4215
  }
4200
- function matchesPath(path8, matcher) {
4201
- return typeof matcher === "string" ? path8.includes(matcher) : matcher.test(path8);
4216
+ function matchesPath(path9, matcher) {
4217
+ return typeof matcher === "string" ? path9.includes(matcher) : matcher.test(path9);
4202
4218
  }
4203
4219
  function shouldStampFile(filename, options) {
4204
4220
  const normalized = normalizeSourcePath(filename);
@@ -4231,11 +4247,11 @@ function sootsimJumpToSourceBabelPlugin(api, options = {}) {
4231
4247
  return {
4232
4248
  name: "sootsim-jump-to-source",
4233
4249
  visitor: {
4234
- JSXOpeningElement(path8, state) {
4250
+ JSXOpeningElement(path9, state) {
4235
4251
  if (options.enabled === false) return;
4236
4252
  const filename = state.file?.opts?.filename;
4237
4253
  if (!filename || !shouldStampFile(filename, options)) return;
4238
- const node = path8.node;
4254
+ const node = path9.node;
4239
4255
  const tagName = getJSXName(node.name);
4240
4256
  if (!tagName || tagName === "Fragment" || tagName.endsWith(".Fragment")) return;
4241
4257
  if (hasAttribute(node, attrName)) return;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "rnx";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-fingerprint-registry.ts
4
4
  var RNX_METRO_FINGERPRINT_SCHEMA_VERSION = 2;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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.506 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.508 | (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;