peachsim 0.1.629 → 0.1.631

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 (128) hide show
  1. package/README.md +8 -4
  2. package/cli/app-fonts.ts +23 -4
  3. package/cli/bridge-flow-runner.ts +45 -31
  4. package/cli/cli-update.ts +2 -7
  5. package/cli/cloud-test-tunnel.ts +16 -3
  6. package/cli/command-registry.ts +1 -0
  7. package/cli/commands/compat.ts +11 -60
  8. package/cli/commands/config.ts +1 -1
  9. package/cli/commands/control.ts +40 -8
  10. package/cli/commands/daemon-mac-app.ts +4 -2
  11. package/cli/commands/daemon.ts +4 -4
  12. package/cli/commands/detect.ts +289 -26
  13. package/cli/commands/device.ts +2 -3
  14. package/cli/commands/inspect/actions.ts +125 -90
  15. package/cli/commands/inspect/core.ts +1 -1
  16. package/cli/commands/inspect.ts +10 -1
  17. package/cli/commands/maestro.ts +3 -1
  18. package/cli/commands/platform.ts +1 -1
  19. package/cli/commands/project-report.ts +386 -0
  20. package/cli/commands/projectReportContract.ts +42 -0
  21. package/cli/commands/report-issue.ts +38 -54
  22. package/cli/commands/screenshot-layers.ts +1 -1
  23. package/cli/commands/screenshot.ts +1 -1
  24. package/cli/commands/setup.ts +6 -4
  25. package/cli/commands/skills.ts +0 -31
  26. package/cli/commands/telemetry.ts +8 -3
  27. package/cli/commands/test.ts +347 -134
  28. package/cli/drivers/playwright-provisioning.ts +3 -2
  29. package/cli/drivers/playwright-sim-host.ts +25 -9
  30. package/cli/main.ts +19 -3
  31. package/cli/outbound-endpoints.ts +2 -5
  32. package/cli/privacy.ts +1 -2
  33. package/cli/runtime-diagnostics.ts +51 -0
  34. package/cli/telemetry.ts +78 -7
  35. package/detox/index.ts +77 -51
  36. package/dist-lib/agent-daemon-client.cjs +1 -1
  37. package/dist-lib/agent-events.cjs +1 -1
  38. package/dist-lib/agent-identity.cjs +1 -1
  39. package/dist-lib/agent-sessions.cjs +1 -1
  40. package/dist-lib/attached-projects.cjs +1 -1
  41. package/dist-lib/auth/shared-session.cjs +1 -1
  42. package/dist-lib/backend-origin.cjs +1 -1
  43. package/dist-lib/beta.cjs +1 -1
  44. package/dist-lib/beta.mjs +1 -1
  45. package/dist-lib/bridge-constants.cjs +1 -1
  46. package/dist-lib/bridge-contract-input.cjs +1 -1
  47. package/dist-lib/bridge-contract-input.mjs +1 -1
  48. package/dist-lib/bridge-contract.cjs +1 -1
  49. package/dist-lib/bridge-contract.mjs +1 -1
  50. package/dist-lib/capture-contract.cjs +1 -1
  51. package/dist-lib/capture-contract.mjs +1 -1
  52. package/dist-lib/cli-constants.cjs +1 -1
  53. package/dist-lib/cloud-contract.cjs +1 -1
  54. package/dist-lib/cloud-contract.mjs +1 -1
  55. package/dist-lib/cloud-test-args.cjs +1 -1
  56. package/dist-lib/cloud-test-args.mjs +1 -1
  57. package/dist-lib/cloud.cjs +1 -1
  58. package/dist-lib/cloud.mjs +1 -1
  59. package/dist-lib/config.cjs +1 -1
  60. package/dist-lib/detox/index.cjs +130 -33
  61. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  62. package/dist-lib/home-paths.cjs +8 -5
  63. package/dist-lib/host/bridge-host.cjs +353 -290
  64. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  65. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  66. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  67. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  68. package/dist-lib/host/websocket-proxy.cjs +1 -1
  69. package/dist-lib/index.cjs +257 -121
  70. package/dist-lib/jump-to-source-babel.cjs +1 -1
  71. package/dist-lib/jump-to-source-native.cjs +1 -1
  72. package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
  73. package/dist-lib/menu.cjs +11 -1
  74. package/dist-lib/menu.mjs +11 -1
  75. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  76. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  77. package/dist-lib/metro-production-bundle.cjs +1 -1
  78. package/dist-lib/metro-production-bundle.mjs +1 -1
  79. package/dist-lib/metro.cjs +132 -9
  80. package/dist-lib/native-app-identity.cjs +278 -0
  81. package/dist-lib/native-app-identity.mjs +245 -0
  82. package/dist-lib/profiles.cjs +1 -1
  83. package/dist-lib/public-brand.cjs +1 -1
  84. package/dist-lib/react-native-host-modules.cjs +1 -1
  85. package/dist-lib/react-native-host-modules.mjs +1 -1
  86. package/dist-lib/render-mode.cjs +1 -1
  87. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  88. package/dist-lib/sdk.cjs +112 -87
  89. package/dist-lib/sdk.mjs +111 -87
  90. package/dist-lib/skills.cjs +1270 -709
  91. package/dist-lib/swift-compile.cjs +1 -1
  92. package/dist-lib/swift-compile.mjs +1 -1
  93. package/dist-lib/swift-package.cjs +1 -1
  94. package/dist-lib/swift-package.mjs +1 -1
  95. package/dist-lib/swift-submit.cjs +1 -1
  96. package/dist-lib/swift-submit.mjs +1 -1
  97. package/dist-lib/swift.cjs +672 -275
  98. package/dist-lib/vite-swift.cjs +1 -1
  99. package/dist-lib/vite.cjs +11 -28
  100. package/kotlin/README.md +32 -4
  101. package/kotlin/fixtures/counter/Counter.kt +26 -0
  102. package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
  103. package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
  104. package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
  105. package/kotlin/fork/LICENSE +178 -0
  106. package/kotlin/fork/NOTICE +25 -0
  107. package/kotlin/fork/README.md +59 -0
  108. package/kotlin/fork/build.sh +128 -0
  109. package/kotlin/fork/compose-worker-globals.patch +96 -0
  110. package/kotlin/fork/fork.json +33 -0
  111. package/kotlin/fork/publish.ts +77 -0
  112. package/kotlin/fork/skiko-worker-clock.patch +33 -0
  113. package/kotlin/toolchain.json +288 -0
  114. package/package.json +13 -5
  115. package/skills/contrast/SKILL.md +1 -0
  116. package/src/automatic-update-policy.ts +17 -0
  117. package/src/home-paths.ts +11 -9
  118. package/src/host/bridge-host.ts +3 -1
  119. package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
  120. package/src/menu.ts +11 -0
  121. package/src/metro-plugin.ts +18 -0
  122. package/src/native-app-identity.ts +376 -0
  123. package/src/native-firebase-config.ts +90 -0
  124. package/src/screenshots/frame-compose.ts +1 -1
  125. package/src/screenshots/registry.ts +1 -1
  126. package/src/screenshots/schema.ts +2 -2
  127. package/src/vite-plugin-one.ts +11 -28
  128. package/src/vite-plugin.ts +6 -1
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var REFUSED_PERFORM_STEP_TYPES = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-test-args.ts
4
4
  var CLOUD_TEST_ARGS_MAX_COUNT = 32;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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;
@@ -835,6 +835,87 @@ function readBrowserCompositeCaptureRequest(value) {
835
835
  return request;
836
836
  }
837
837
 
838
+ // ../peach-engine/src/open-external.ts
839
+ var AUTH_BROWSER_EXTERNAL_NAVIGATION_EVENT = "peach:auth-browser-external-navigation";
840
+ var AUTH_BROWSER_SESSION_FRAGMENT_KEY = "peach-auth-session";
841
+ async function forwardPopupSchemeNavigations(context, eventName, sessionFragmentKey) {
842
+ const readiness = /* @__PURE__ */ new Map();
843
+ const pendingOwner = (identity) => {
844
+ const existing = readiness.get(identity);
845
+ if (existing) return existing;
846
+ let resolve;
847
+ const owner = new Promise((done) => {
848
+ resolve = done;
849
+ });
850
+ const pending = { owner, resolve };
851
+ readiness.set(identity, pending);
852
+ return pending;
853
+ };
854
+ await context.exposeBinding("__peachAuthBrowserReady", async (source, identity) => {
855
+ if (typeof identity !== "string") throw new Error("invalid auth browser session");
856
+ const owner = await pendingOwner(identity).owner;
857
+ readiness.delete(identity);
858
+ if (owner !== source.page) throw new Error("auth browser popup ownership mismatch");
859
+ });
860
+ const browserSchemes = /* @__PURE__ */ new Set([
861
+ "http:",
862
+ "https:",
863
+ "about:",
864
+ "blob:",
865
+ "data:",
866
+ "file:",
867
+ "javascript:"
868
+ ]);
869
+ context.on("page", (popup) => {
870
+ let owner = null;
871
+ const opener = popup.opener();
872
+ void opener.catch(() => {
873
+ });
874
+ const recordSession = () => {
875
+ if (owner) return;
876
+ try {
877
+ owner = new URLSearchParams(new URL(popup.url()).hash.slice(1)).get(
878
+ sessionFragmentKey
879
+ );
880
+ if (owner) {
881
+ const identity = owner;
882
+ const pending = pendingOwner(identity);
883
+ void opener.then(pending.resolve, () => pending.resolve(null));
884
+ }
885
+ } catch {
886
+ }
887
+ };
888
+ recordSession();
889
+ popup.on("framenavigated", recordSession);
890
+ const forward = (detail) => opener.then(
891
+ (page) => page?.evaluate(
892
+ ([name2, detail2]) => !window.dispatchEvent(new CustomEvent(name2, { detail: detail2, cancelable: true })),
893
+ [eventName, detail]
894
+ )
895
+ );
896
+ popup.on("close", () => {
897
+ if (!owner) return;
898
+ readiness.get(owner)?.resolve(null);
899
+ readiness.delete(owner);
900
+ void forward({ session: owner, closed: true }).catch(() => {
901
+ });
902
+ });
903
+ popup.on("request", (request) => {
904
+ if (!owner) return;
905
+ if (!request.isNavigationRequest() || request.frame() !== popup.mainFrame()) return;
906
+ let protocol;
907
+ try {
908
+ protocol = new URL(request.url()).protocol;
909
+ } catch {
910
+ return;
911
+ }
912
+ if (browserSchemes.has(protocol)) return;
913
+ void forward({ session: owner, url: request.url() }).then((accepted) => accepted ? popup.close() : void 0).catch(() => {
914
+ });
915
+ });
916
+ });
917
+ }
918
+
838
919
  // ../peach-engine/src/remote-stream/remoteEngineParam.ts
839
920
  function readRemoteEngineParam(search, hash) {
840
921
  const fromQuery = new URLSearchParams(search).get("remoteEngine");
@@ -1979,7 +2060,6 @@ var _reapBrowserNow = null;
1979
2060
  var _context = null;
1980
2061
  var _page = null;
1981
2062
  var _synchronizationEnabled = false;
1982
- var _suspendedAppId = null;
1983
2063
  var _browserCompromised = null;
1984
2064
  var browserIdentity = 0;
1985
2065
  var contextIdentity = 0;
@@ -2394,7 +2474,7 @@ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false) {
2394
2474
  }
2395
2475
  async function findNodeByMatcher(matcher) {
2396
2476
  const page = getPage();
2397
- if (matcher.index !== void 0) {
2477
+ if (matcher.index !== void 0 || matcher.type === "text") {
2398
2478
  return page.evaluate(async (indexedMatcher) => {
2399
2479
  const filter = indexedMatcher.type === "id" ? { hasId: indexedMatcher.value } : indexedMatcher.type === "text" ? { hasText: indexedMatcher.value } : indexedMatcher.type === "label" ? { hasLabel: indexedMatcher.value } : indexedMatcher.type === "role" ? { hasRole: indexedMatcher.value } : { type: indexedMatcher.value };
2400
2480
  const results = await window.__sootsimTest.queryAll(filter);
@@ -2409,11 +2489,6 @@ async function findNodeByMatcher(matcher) {
2409
2489
  (id) => window.__sootsimTest.findByTestId(id),
2410
2490
  matcher.value
2411
2491
  );
2412
- } else if (matcher.type === "text") {
2413
- return page.evaluate(
2414
- (text) => window.__sootsimTest.findByText(text),
2415
- matcher.value
2416
- );
2417
2492
  } else if (matcher.type === "label") {
2418
2493
  return page.evaluate(
2419
2494
  (label) => window.__sootsimTest.findByLabel(label),
@@ -2629,7 +2704,15 @@ async function dispatchDeviceOrientation(orientation) {
2629
2704
  landscapeSide: DETOX_PLATFORM === "ios" ? "right" : "left"
2630
2705
  }
2631
2706
  );
2632
- await page.waitForTimeout(50);
2707
+ await page.waitForFunction(
2708
+ (next) => {
2709
+ const settings = window.SootSim?.bridges?.settings?.get?.();
2710
+ const rotation = Reflect.get(window, "__sootsimDeviceRotation");
2711
+ return typeof settings === "object" && settings !== null && "orientation" in settings && settings.orientation === next && rotation?.active !== true;
2712
+ },
2713
+ orientation,
2714
+ { timeout: 15e3 }
2715
+ );
2633
2716
  }
2634
2717
  var MAX_SETTLED_SPEED_PT_PER_SEC = 2;
2635
2718
  async function waitForFrameClock(page, minMs = 25) {
@@ -3121,11 +3204,13 @@ function createSootSimElement(matcher) {
3121
3204
  visible: node.layout.width > 0 && node.layout.height > 0,
3122
3205
  enabled: !node.accessibilityState?.disabled,
3123
3206
  ...node,
3124
- frame: node.absolutePosition ? {
3207
+ // the transformed rect when the node reports one; a node resolved
3208
+ // without a size (x and y only) keeps its own frame
3209
+ frame: node.absolutePosition?.width !== void 0 && node.absolutePosition.height !== void 0 ? {
3125
3210
  x: node.absolutePosition.x,
3126
3211
  y: node.absolutePosition.y,
3127
- width: node.absolutePosition.width ?? node.frame?.width ?? 0,
3128
- height: node.absolutePosition.height ?? node.frame?.height ?? 0
3212
+ width: node.absolutePosition.width,
3213
+ height: node.absolutePosition.height
3129
3214
  } : node.frame
3130
3215
  };
3131
3216
  },
@@ -3211,25 +3296,34 @@ var device = {
3211
3296
  if (_browserCompromised) {
3212
3297
  throw new Error(`sootsim browser is compromised: ${_browserCompromised}`);
3213
3298
  }
3214
- if (_page && opts?.newInstance === false && !opts.delete && !opts.recordVideoDir && _suspendedAppId) {
3299
+ if (_page && opts?.newInstance === false && !opts.delete && !opts.recordVideoDir) {
3300
+ if (opts.url) {
3301
+ throw new Error(`SootSim cannot deliver a url to a running app: ${opts.url}`);
3302
+ }
3215
3303
  const page = _page;
3216
- const appId = _suspendedAppId;
3217
- await page.evaluate(
3218
- (id) => window.SootSim?.bridges?.mainShell?.launchApp?.(id),
3219
- appId
3220
- );
3221
- await pollUntil(
3222
- () => page.evaluate(async (id) => {
3223
- const state = await window.SootSim?.bridges?.mainShell?.getState?.();
3224
- return state?.state === "app" && state.activeApp === id && state.switcherPhase === "idle";
3225
- }, appId),
3226
- Boolean,
3227
- {
3228
- timeoutMs: 1e4,
3229
- label: `SootSim app ${appId} to resume`
3304
+ const appId = await page.evaluate(async () => {
3305
+ const state = await window.SootSim?.bridges?.mainShell?.getState?.();
3306
+ const guestApp = state?.guestApp;
3307
+ if (typeof guestApp !== "string") {
3308
+ throw new Error("SootSim main shell reports no guest app");
3230
3309
  }
3231
- );
3232
- _suspendedAppId = null;
3310
+ if (state?.state === "app" && state.activeApp === guestApp) return null;
3311
+ window.SootSim?.bridges?.mainShell?.launchApp?.(guestApp);
3312
+ return guestApp;
3313
+ });
3314
+ if (appId !== null) {
3315
+ await pollUntil(
3316
+ () => page.evaluate(async (id) => {
3317
+ const state = await window.SootSim?.bridges?.mainShell?.getState?.();
3318
+ return state?.state === "app" && state.activeApp === id && state.switcherPhase === "idle";
3319
+ }, appId),
3320
+ Boolean,
3321
+ {
3322
+ timeoutMs: 1e4,
3323
+ label: `SootSim app ${appId} to resume`
3324
+ }
3325
+ );
3326
+ }
3233
3327
  await waitForSootsimTree(page, 1e4);
3234
3328
  if (opts?.userNotification) {
3235
3329
  await postRemotePushToSimulator(opts.userNotification, true);
@@ -3270,6 +3364,11 @@ var device = {
3270
3364
  reapOwnedBrowser();
3271
3365
  throw error;
3272
3366
  }
3367
+ await forwardPopupSchemeNavigations(
3368
+ _context,
3369
+ AUTH_BROWSER_EXTERNAL_NAVIGATION_EVENT,
3370
+ AUTH_BROWSER_SESSION_FRAGMENT_KEY
3371
+ );
3273
3372
  await _context.exposeBinding("__sootsimHostCapture", async (source, value) => {
3274
3373
  const request = readBrowserCompositeCaptureRequest(value);
3275
3374
  const session = await source.page.context().newCDPSession(source.page);
@@ -4182,14 +4281,12 @@ var device = {
4182
4281
  },
4183
4282
  async sendToHome() {
4184
4283
  const page = getPage();
4185
- _suspendedAppId = await page.evaluate(async () => {
4284
+ await page.evaluate(async () => {
4186
4285
  const state = await window.SootSim?.bridges?.mainShell?.getState?.();
4187
- const appId = state?.activeApp;
4188
- if (typeof appId !== "string") {
4286
+ if (typeof state?.activeApp !== "string") {
4189
4287
  throw new Error(`cannot send an inactive SootSim app home`);
4190
4288
  }
4191
4289
  window.SootSim?.bridges?.mainShell?.goHome?.();
4192
- return appId;
4193
4290
  });
4194
4291
  await pollUntil(
4195
4292
  () => page.evaluate(async () => {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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;
@@ -226,7 +226,7 @@ function readPrivacyPreferences() {
226
226
  return {
227
227
  productAnalytics: typeof productAnalytics === "boolean" ? productAnalytics : false,
228
228
  crashReports: typeof crashReports === "boolean" ? crashReports : false,
229
- configured: typeof productAnalytics === "boolean" && typeof crashReports === "boolean"
229
+ configured: typeof productAnalytics === "boolean"
230
230
  };
231
231
  }
232
232
  function writePrivacyPreferences(preferences) {
@@ -238,10 +238,13 @@ function writePrivacyPreferences(preferences) {
238
238
  });
239
239
  }
240
240
  function readOrCreateAnonymousId() {
241
- const existing = readSharedConfig().anonymousId;
242
- if (typeof existing === "string" && existing.trim()) return existing;
241
+ const existing = readSharedConfig().settings?.anonymousId;
242
+ if (typeof existing === "string" && /^anon-cli-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(
243
+ existing
244
+ ))
245
+ return existing;
243
246
  const created = `anon-cli-${(0, import_node_crypto.randomUUID)()}`;
244
- writeSharedConfig({ anonymousId: created });
247
+ writeSharedConfig({ settings: { anonymousId: created } });
245
248
  return created;
246
249
  }
247
250
  function readDefaultBox() {