rnxsim 0.1.353 → 0.1.355

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 (176) hide show
  1. package/cli/bridge-flow-runner.ts +44 -51
  2. package/cli/commands/inspect/settling.ts +9 -2
  3. package/cli/outbound-endpoints.ts +1 -1
  4. package/detox/index.ts +144 -74
  5. package/detox/proof-frame.cjs +107 -0
  6. package/dist-cli/bin.js +5 -5
  7. package/dist-cli/chunks/{agent-YTAX6OQQ.js → agent-2MW7ZKUX.js} +2 -2
  8. package/dist-cli/chunks/{agent-wrapper-2QSUXMNK.js → agent-wrapper-XYQBKV24.js} +2 -2
  9. package/dist-cli/chunks/{app-fonts-4EVHPXVG.js → app-fonts-SXIZFMPY.js} +2 -2
  10. package/dist-cli/chunks/{assert-IXMSQLVY.js → assert-R324GCRG.js} +2 -2
  11. package/dist-cli/chunks/{auth-6QFWU2T5.js → auth-INKYLYRZ.js} +2 -2
  12. package/dist-cli/chunks/{beta-27I5WWRE.js → beta-BQHBSKA5.js} +2 -2
  13. package/dist-cli/chunks/{camera-4HFUBXPM.js → camera-UPRFBRPF.js} +2 -2
  14. package/dist-cli/chunks/{chunk-ZJ4O636U.js → chunk-23TG7DLH.js} +1 -1
  15. package/dist-cli/chunks/{chunk-3XDGLCNP.js → chunk-247ZSWTI.js} +2 -2
  16. package/dist-cli/chunks/chunk-2GLEESND.js +535 -0
  17. package/dist-cli/chunks/{chunk-6JBOKETZ.js → chunk-2Z2S3C6A.js} +2 -2
  18. package/dist-cli/chunks/{chunk-ELBDKQK2.js → chunk-42LIUAHU.js} +2 -2
  19. package/dist-cli/chunks/{chunk-PBTG4UCS.js → chunk-6EC3D5IG.js} +1 -1
  20. package/dist-cli/chunks/{chunk-3UXMNDMH.js → chunk-6WCDWBG6.js} +2 -2
  21. package/dist-cli/chunks/{chunk-5DLBRZAG.js → chunk-7URIRES5.js} +2 -2
  22. package/dist-cli/chunks/{chunk-HVLZYUGF.js → chunk-AY4OA5UI.js} +2 -2
  23. package/dist-cli/chunks/{chunk-YYYWU6LL.js → chunk-BUOAYILA.js} +12 -5
  24. package/dist-cli/chunks/{chunk-KIQVNLVD.js → chunk-CK3M7MAL.js} +2 -2
  25. package/dist-cli/chunks/{chunk-KZLGVYCX.js → chunk-CRE3V3EG.js} +1 -1
  26. package/dist-cli/chunks/{chunk-7FUSVOMH.js → chunk-CUXVUSZS.js} +2 -2
  27. package/dist-cli/chunks/{chunk-4IXIONDR.js → chunk-EQEEPP5A.js} +2 -2
  28. package/dist-cli/chunks/{chunk-ZYGWIVW4.js → chunk-EZXNGHZT.js} +2 -2
  29. package/dist-cli/chunks/{chunk-WKQ6W74M.js → chunk-F6S4Z7N7.js} +1 -1
  30. package/dist-cli/chunks/{chunk-4NPZ5FO2.js → chunk-FDI226G4.js} +2 -2
  31. package/dist-cli/chunks/{chunk-VZDW2U64.js → chunk-FF2CEKZF.js} +2 -2
  32. package/dist-cli/chunks/{chunk-HZTWQZUD.js → chunk-FFNFGVGH.js} +2 -2
  33. package/dist-cli/chunks/{chunk-OEU2MEZQ.js → chunk-FPWDC2DE.js} +1 -1
  34. package/dist-cli/chunks/{chunk-ZF53H457.js → chunk-GE7GYFE4.js} +2 -2
  35. package/dist-cli/chunks/{chunk-LMFAIAA5.js → chunk-GFDFVKVW.js} +1 -1
  36. package/dist-cli/chunks/{chunk-WTGQUQ32.js → chunk-GWL4KMTK.js} +2 -2
  37. package/dist-cli/chunks/{chunk-JVVO63QH.js → chunk-IAVHAWDL.js} +1 -1
  38. package/dist-cli/chunks/{chunk-IX7W5BXL.js → chunk-IJGL6T4M.js} +2 -2
  39. package/dist-cli/chunks/{chunk-LAFKQUT7.js → chunk-JE6NXNGL.js} +3 -3
  40. package/dist-cli/chunks/{chunk-6NE5Z6KG.js → chunk-JP2YS7LC.js} +1 -1
  41. package/dist-cli/chunks/{chunk-UNBVUOIC.js → chunk-JYQNEVHV.js} +2 -2
  42. package/dist-cli/chunks/{chunk-MA5E6HJR.js → chunk-KLVSEUJP.js} +2 -2
  43. package/dist-cli/chunks/{chunk-T2ZZSSCP.js → chunk-LJCBPR7S.js} +2 -2
  44. package/dist-cli/chunks/{chunk-WU25RTIX.js → chunk-LQEC53JM.js} +2 -2
  45. package/dist-cli/chunks/{chunk-7V5O6I4Q.js → chunk-MCAQZI3R.js} +1 -1
  46. package/dist-cli/chunks/{chunk-UEILOAPW.js → chunk-MKHCGQSF.js} +1 -1
  47. package/dist-cli/chunks/{chunk-PNQ33FJB.js → chunk-N532KCKW.js} +2 -2
  48. package/dist-cli/chunks/{chunk-TX2T5KPQ.js → chunk-NCF3QNJG.js} +2 -2
  49. package/dist-cli/chunks/{chunk-GAYCF2O5.js → chunk-PYSIEEKP.js} +1 -1
  50. package/dist-cli/chunks/{chunk-ECIDT6F5.js → chunk-QWJD2CAJ.js} +1 -1
  51. package/dist-cli/chunks/{chunk-XVLYLZOM.js → chunk-QYIT7H6Q.js} +2 -2
  52. package/dist-cli/chunks/{chunk-RRX5RZI2.js → chunk-S27I7H2K.js} +1 -1
  53. package/dist-cli/chunks/{chunk-ZXHAAVTH.js → chunk-S4K3TDYB.js} +2 -2
  54. package/dist-cli/chunks/{chunk-4PV6QASJ.js → chunk-SEWNI4GS.js} +1 -1
  55. package/dist-cli/chunks/{chunk-3IWR7KHR.js → chunk-SJEAA2FW.js} +2 -2
  56. package/dist-cli/chunks/{chunk-BK5TJXUU.js → chunk-TADYO7TY.js} +2 -2
  57. package/dist-cli/chunks/chunk-UIBR3GXC.js +4 -0
  58. package/dist-cli/chunks/{chunk-CMQIFA4L.js → chunk-VEMZUXVR.js} +1 -1
  59. package/dist-cli/chunks/{chunk-YQJOM55S.js → chunk-VWPXXB6U.js} +1 -1
  60. package/dist-cli/chunks/{chunk-RMOSWLWG.js → chunk-W3QLC24Z.js} +2 -2
  61. package/dist-cli/chunks/{chunk-WV3TKN7D.js → chunk-WUYI4PVY.js} +1 -1
  62. package/dist-cli/chunks/{chunk-VLI54BKH.js → chunk-X36BQCH5.js} +2 -2
  63. package/dist-cli/chunks/{chunk-57YZEJ6J.js → chunk-XFPGXEKW.js} +1 -1
  64. package/dist-cli/chunks/{chunk-DSBUGNC5.js → chunk-XZJNPATS.js} +2 -2
  65. package/dist-cli/chunks/{chunk-CYS3D7RG.js → chunk-Y3D3DCQV.js} +2 -2
  66. package/dist-cli/chunks/{chunk-V7X543SB.js → chunk-Y5BP72QO.js} +1 -1
  67. package/dist-cli/chunks/{chunk-HWMBTYJX.js → chunk-ZNWLFYZK.js} +2 -2
  68. package/dist-cli/chunks/{chunk-7SKQRS74.js → chunk-ZOFRHAGX.js} +1 -1
  69. package/dist-cli/chunks/{chunk-UQBXA3AK.js → chunk-ZQF3PK76.js} +2 -2
  70. package/dist-cli/chunks/{cleanup-ULH3BHAE.js → cleanup-5FGGUP6U.js} +2 -2
  71. package/dist-cli/chunks/cli-version-JP47UGY6.js +4 -0
  72. package/dist-cli/chunks/{compat-ONN5DOHB.js → compat-J4OEALGF.js} +2 -2
  73. package/dist-cli/chunks/{config-OPZU73MX.js → config-MCH2R7WG.js} +2 -2
  74. package/dist-cli/chunks/{control-WNYEAI4K.js → control-NPWFRKZS.js} +2 -2
  75. package/dist-cli/chunks/daemon-M26NJFNC.js +4 -0
  76. package/dist-cli/chunks/{debug-GNI3HDAK.js → debug-7NHPYUX6.js} +3 -3
  77. package/dist-cli/chunks/{desktop-DF65PDJG.js → desktop-EIBJC5EU.js} +3 -3
  78. package/dist-cli/chunks/{detox-N267KW2Y.js → detox-ZFEQKHDT.js} +2 -2
  79. package/dist-cli/chunks/{device-RFU44PE3.js → device-JM7QMQFQ.js} +2 -2
  80. package/dist-cli/chunks/{diagnose-XR2JIGDE.js → diagnose-DCMU2GAD.js} +2 -2
  81. package/dist-cli/chunks/{disk-cleanup-DPY6TYXA.js → disk-cleanup-RPW5MYGM.js} +2 -2
  82. package/dist-cli/chunks/drivers-DW3CQUTK.js +4 -0
  83. package/dist-cli/chunks/{film-NQQZPZ2W.js → film-NRGBZSC7.js} +3 -3
  84. package/dist-cli/chunks/flow-76SLGQCI.js +4 -0
  85. package/dist-cli/chunks/help-GUYB5XWH.js +4 -0
  86. package/dist-cli/chunks/{hidden-runtime-alias-APCBIXJ6.js → hidden-runtime-alias-GSZG7QFD.js} +2 -2
  87. package/dist-cli/chunks/{home-paths-27GY5EPD.js → home-paths-OGXLRRTG.js} +2 -2
  88. package/dist-cli/chunks/inspect-URTBYLXV.js +4 -0
  89. package/dist-cli/chunks/install-desktop-BINBAGSN.js +4 -0
  90. package/dist-cli/chunks/{login-6KIO5FR4.js → login-A7JSAMON.js} +2 -2
  91. package/dist-cli/chunks/{logout-WMCYGTYA.js → logout-EBUWNT63.js} +2 -2
  92. package/dist-cli/chunks/{maestro-7QLOUZIE.js → maestro-OEXXVYMW.js} +3 -3
  93. package/dist-cli/chunks/{maestro-generate-QIGCQANR.js → maestro-generate-DKH6IUTC.js} +3 -3
  94. package/dist-cli/chunks/{mode-3H662MUJ.js → mode-YKX2UTBX.js} +2 -2
  95. package/dist-cli/chunks/{optional-demo-registry-FQV54ASP.js → optional-demo-registry-W4Z54NYF.js} +2 -2
  96. package/dist-cli/chunks/{perf-KC6LOGFD.js → perf-EJDB2NWH.js} +2 -2
  97. package/dist-cli/chunks/{permissions-UGVHA3L6.js → permissions-MXUT3YR6.js} +2 -2
  98. package/dist-cli/chunks/privacy-JIJOFIGM.js +4 -0
  99. package/dist-cli/chunks/{record-V72Q363I.js → record-STFUL6CS.js} +3 -3
  100. package/dist-cli/chunks/{report-issue-MILOOCMG.js → report-issue-TE2QTEMZ.js} +2 -2
  101. package/dist-cli/chunks/reset-LAIGONON.js +4 -0
  102. package/dist-cli/chunks/runtime-ZS3FBQLG.js +4 -0
  103. package/dist-cli/chunks/{screenshot-command-FYMZF5AF.js → screenshot-command-SRW3HXF7.js} +3 -3
  104. package/dist-cli/chunks/{screenshot-layers-OXLW6GEJ.js → screenshot-layers-IULR35XJ.js} +2 -2
  105. package/dist-cli/chunks/{screenshots-capture-N3LKTUKB.js → screenshots-capture-54GFQLXS.js} +2 -2
  106. package/dist-cli/chunks/{serve-USDREK3N.js → serve-WJAOT43K.js} +2 -2
  107. package/dist-cli/chunks/setup-36ACJ5FT.js +4 -0
  108. package/dist-cli/chunks/{skills-3MIZF3DS.js → skills-DW5GLHAT.js} +2 -2
  109. package/dist-cli/chunks/{state-MCFLWQHV.js → state-IW4THIPU.js} +2 -2
  110. package/dist-cli/chunks/{storage-KXNS5WEC.js → storage-F4RQZFTZ.js} +2 -2
  111. package/dist-cli/chunks/store-MTN4TPL6.js +4 -0
  112. package/dist-cli/chunks/telemetry-CJSVYHLI.js +4 -0
  113. package/dist-cli/chunks/{timeline-QJ3USMSX.js → timeline-IX3HVS22.js} +2 -2
  114. package/dist-cli/chunks/{upgrade-LXFD4DFX.js → upgrade-T4LWQ2JA.js} +2 -2
  115. package/dist-cli/chunks/upload-LHWECFWH.js +4 -0
  116. package/dist-cli/chunks/{version-D5DLNPHP.js → version-MNRMHJ64.js} +2 -2
  117. package/dist-cli/chunks/{web-FRFNTTZ4.js → web-ARKJI3PY.js} +2 -2
  118. package/dist-cli/chunks/welcome-XH657K2V.js +5 -0
  119. package/dist-cli/chunks/{what-happened-FJ6GRQAS.js → what-happened-EBK5NZFI.js} +2 -2
  120. package/dist-lib/agent-daemon-client.cjs +1 -1
  121. package/dist-lib/agent-events.cjs +1 -1
  122. package/dist-lib/agent-identity.cjs +1 -1
  123. package/dist-lib/agent-sessions.cjs +1 -1
  124. package/dist-lib/attached-projects.cjs +1 -1
  125. package/dist-lib/auth/shared-session.cjs +1 -1
  126. package/dist-lib/backend-origin.cjs +1 -1
  127. package/dist-lib/beta.cjs +1 -1
  128. package/dist-lib/beta.mjs +1 -1
  129. package/dist-lib/bridge-constants.cjs +1 -1
  130. package/dist-lib/bridge-contract.cjs +1 -1
  131. package/dist-lib/cli-constants.cjs +1 -1
  132. package/dist-lib/config.cjs +1 -1
  133. package/dist-lib/detox/index.cjs +196 -54
  134. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  135. package/dist-lib/home-paths.cjs +1 -1
  136. package/dist-lib/host/bridge-host.cjs +1 -1
  137. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  138. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  139. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  140. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  141. package/dist-lib/host/websocket-proxy.cjs +1 -1
  142. package/dist-lib/index.cjs +10 -3
  143. package/dist-lib/jump-to-source-babel.cjs +1 -1
  144. package/dist-lib/menu.cjs +1 -1
  145. package/dist-lib/menu.mjs +1 -1
  146. package/dist-lib/metro-production-bundle.cjs +1 -1
  147. package/dist-lib/metro-production-bundle.mjs +1 -1
  148. package/dist-lib/metro.cjs +1 -1
  149. package/dist-lib/profiles.cjs +1 -1
  150. package/dist-lib/public-brand.cjs +1 -1
  151. package/dist-lib/react-native-host-modules.cjs +1 -1
  152. package/dist-lib/react-native-host-modules.mjs +1 -1
  153. package/dist-lib/render-mode.cjs +1 -1
  154. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  155. package/dist-lib/sdk.cjs +10 -3
  156. package/dist-lib/sdk.mjs +10 -3
  157. package/dist-lib/skills.cjs +4735 -196
  158. package/dist-lib/vite.cjs +1 -1
  159. package/package.json +1 -1
  160. package/dist-cli/chunks/chunk-37J74ASV.js +0 -4
  161. package/dist-cli/chunks/chunk-R4KBCGXX.js +0 -543
  162. package/dist-cli/chunks/cli-version-I2E56I4W.js +0 -4
  163. package/dist-cli/chunks/daemon-5J6V2GLG.js +0 -4
  164. package/dist-cli/chunks/drivers-OIZC544W.js +0 -4
  165. package/dist-cli/chunks/flow-3NHEHRF4.js +0 -4
  166. package/dist-cli/chunks/help-VACWNWEH.js +0 -4
  167. package/dist-cli/chunks/inspect-2JELKZ5A.js +0 -4
  168. package/dist-cli/chunks/install-desktop-4R7UTGQU.js +0 -4
  169. package/dist-cli/chunks/privacy-E6KH2DRJ.js +0 -4
  170. package/dist-cli/chunks/reset-LEL5ZGFN.js +0 -4
  171. package/dist-cli/chunks/runtime-RT2OTIQC.js +0 -4
  172. package/dist-cli/chunks/setup-QC7W7NCL.js +0 -4
  173. package/dist-cli/chunks/store-GL6DFPJL.js +0 -4
  174. package/dist-cli/chunks/telemetry-OOW5FMZQ.js +0 -4
  175. package/dist-cli/chunks/upload-EUEO4D5N.js +0 -4
  176. package/dist-cli/chunks/welcome-YYYGS5WD.js +0 -5
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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;
@@ -109,6 +109,94 @@ var require_motion_change = __commonJS({
109
109
  }
110
110
  });
111
111
 
112
+ // detox/proof-frame.cjs
113
+ var require_proof_frame = __commonJS({
114
+ "detox/proof-frame.cjs"(exports2, module2) {
115
+ "use strict";
116
+ var PROOF_CONTENT_DEFINITION = Object.freeze({
117
+ channelThreshold: 24,
118
+ contentBandInsetFraction: 0.08,
119
+ minimumContentPercent: 5e-3
120
+ });
121
+ var REQUIRED_IDENTICAL_PROOF_FRAMES2 = 3;
122
+ function framesIdentical2(a, b) {
123
+ if (!a || !b || a.length !== b.length) return false;
124
+ return a.equals(b);
125
+ }
126
+ function measureProofFrameContent(input) {
127
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
128
+ throw new Error("proof content measurement requires an input object");
129
+ }
130
+ const { data, width, height } = input;
131
+ if (!data || typeof data.length !== "number" || !Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0 || data.length !== width * height * 4) {
132
+ throw new Error("proof content measurement needs RGBA pixels and dimensions");
133
+ }
134
+ const yStart = Math.floor(height * PROOF_CONTENT_DEFINITION.contentBandInsetFraction);
135
+ const yEnd = Math.ceil(
136
+ height * (1 - PROOF_CONTENT_DEFINITION.contentBandInsetFraction)
137
+ );
138
+ const bucketCounts = new Uint32Array(32 * 32 * 32);
139
+ let totalPixels = 0;
140
+ for (let y = yStart; y < yEnd; y++) {
141
+ for (let x = 0; x < width; x++) {
142
+ const offset = (y * width + x) * 4;
143
+ const bucket = data[offset] >> 3 << 10 | data[offset + 1] >> 3 << 5 | data[offset + 2] >> 3;
144
+ bucketCounts[bucket]++;
145
+ totalPixels++;
146
+ }
147
+ }
148
+ let dominantBucket = 0;
149
+ for (let index = 1; index < bucketCounts.length; index++) {
150
+ if (bucketCounts[index] > bucketCounts[dominantBucket]) dominantBucket = index;
151
+ }
152
+ const dominant = {
153
+ red: ((dominantBucket >> 10 & 31) << 3) + 4,
154
+ green: ((dominantBucket >> 5 & 31) << 3) + 4,
155
+ blue: ((dominantBucket & 31) << 3) + 4
156
+ };
157
+ let contentPixels = 0;
158
+ for (let y = yStart; y < yEnd; y++) {
159
+ for (let x = 0; x < width; x++) {
160
+ const offset = (y * width + x) * 4;
161
+ if (Math.max(
162
+ Math.abs(data[offset] - dominant.red),
163
+ Math.abs(data[offset + 1] - dominant.green),
164
+ Math.abs(data[offset + 2] - dominant.blue)
165
+ ) >= PROOF_CONTENT_DEFINITION.channelThreshold) {
166
+ contentPixels++;
167
+ }
168
+ }
169
+ }
170
+ const contentPercent = contentPixels / totalPixels * 100;
171
+ return {
172
+ contentPercent,
173
+ contentPixels,
174
+ dominant,
175
+ passedMinimum: contentPercent >= PROOF_CONTENT_DEFINITION.minimumContentPercent,
176
+ totalPixels
177
+ };
178
+ }
179
+ function settleDecision(previousPixels, currentFrame) {
180
+ if (!currentFrame) return { decision: "continue", content: null };
181
+ const content = measureProofFrameContent(currentFrame);
182
+ if (!content.passedMinimum) {
183
+ return { decision: "insufficient-content", content };
184
+ }
185
+ if (previousPixels && framesIdentical2(previousPixels, currentFrame.data)) {
186
+ return { decision: "identical", content };
187
+ }
188
+ return { decision: "changed", content };
189
+ }
190
+ module2.exports = {
191
+ PROOF_CONTENT_DEFINITION,
192
+ REQUIRED_IDENTICAL_PROOF_FRAMES: REQUIRED_IDENTICAL_PROOF_FRAMES2,
193
+ framesIdentical: framesIdentical2,
194
+ measureProofFrameContent,
195
+ settleDecision
196
+ };
197
+ }
198
+ });
199
+
112
200
  // detox/index.ts
113
201
  var detox_exports = {};
114
202
  __export(detox_exports, {
@@ -1364,6 +1452,7 @@ var by = {
1364
1452
 
1365
1453
  // detox/index.ts
1366
1454
  var import_motion_change = __toESM(require_motion_change(), 1);
1455
+ var import_proof_frame = __toESM(require_proof_frame(), 1);
1367
1456
  var BASE_URL = process.env.SOOTSIM_URL || "http://localhost:5173";
1368
1457
  var SCREENSHOT_DIR = process.env.SOOTSIM_SCREENSHOT_DIR || path.join(process.cwd(), "test", "detox-driver", "screenshots");
1369
1458
  var DETOX_PLATFORM = process.env.SOOTSIM_PLATFORM === "android" ? "android" : "ios";
@@ -1372,6 +1461,7 @@ var _reapBrowserNow = null;
1372
1461
  var _context = null;
1373
1462
  var _page = null;
1374
1463
  var _synchronizationEnabled = false;
1464
+ var _suspendedAppId = null;
1375
1465
  var pageDiagnostics = /* @__PURE__ */ new WeakMap();
1376
1466
  var STATUS_BAR_OVERRIDE_EVENT = "sootsim:statusBarOverride";
1377
1467
  function getPage() {
@@ -1608,9 +1698,10 @@ async function closeBrowser() {
1608
1698
  reapBrowserNow?.();
1609
1699
  }
1610
1700
  }
1611
- async function waitForSootsimIdle(page, maxMs = 3e3) {
1701
+ async function waitForSootsimIdle(page, maxMs = 3e3, strict = false) {
1612
1702
  const result = await page.evaluate(
1613
- async ({ maxMs: maxMs2 }) => {
1703
+ async ({ maxMs: maxMs2, strict: strict2 }) => {
1704
+ const start = Date.now();
1614
1705
  let transitionError = null;
1615
1706
  try {
1616
1707
  const waitForScreenTransitions = window.__sootsimTest?.waitForScreenTransitions;
@@ -1620,9 +1711,6 @@ async function waitForSootsimIdle(page, maxMs = 3e3) {
1620
1711
  settleMs: 48,
1621
1712
  startWindowMs: 600
1622
1713
  });
1623
- if (transitionResult?.started === true && transitionResult.settled === true && transitionResult.timedOut !== true) {
1624
- return { settled: true, elapsed: transitionResult.waitedMs ?? 0 };
1625
- }
1626
1714
  if (transitionResult?.timedOut) {
1627
1715
  return {
1628
1716
  settled: false,
@@ -1634,7 +1722,6 @@ async function waitForSootsimIdle(page, maxMs = 3e3) {
1634
1722
  } catch (error) {
1635
1723
  transitionError = error instanceof Error ? error.message : String(error);
1636
1724
  }
1637
- const start = Date.now();
1638
1725
  const deadline = start + maxMs2;
1639
1726
  const pollMs = 50;
1640
1727
  const requiredStablePolls = 3;
@@ -1650,6 +1737,22 @@ async function waitForSootsimIdle(page, maxMs = 3e3) {
1650
1737
  const readSnapshot = async () => {
1651
1738
  const root = window.__sootsimRoot;
1652
1739
  const layout = [];
1740
+ let animating = false;
1741
+ let auxSurfaceDebug = null;
1742
+ let layoutDirty = false;
1743
+ let renderStatsAvailable = false;
1744
+ if (strict2) {
1745
+ try {
1746
+ const renderHost = Reflect.get(window, "__sootsimRenderHost");
1747
+ const queryStats = typeof renderHost === "object" && renderHost !== null ? Reflect.get(renderHost, "queryStats") : null;
1748
+ const stats = typeof queryStats === "function" ? await queryStats.call(renderHost) : null;
1749
+ renderStatsAvailable = !!stats;
1750
+ auxSurfaceDebug = stats?.auxSurfaceDebug ?? null;
1751
+ animating = stats?.hasActiveAnims === true || stats?.hasActiveNativeAnimations === true || stats?.hasPendingAnimationFrames === true;
1752
+ layoutDirty = stats?.layoutDirty === true && stats?.renderRequested === true;
1753
+ } catch {
1754
+ }
1755
+ }
1653
1756
  if (root) {
1654
1757
  const walk = (node) => {
1655
1758
  if (node.layout && node.layout.width > 0) {
@@ -1664,19 +1767,27 @@ async function waitForSootsimIdle(page, maxMs = 3e3) {
1664
1767
  };
1665
1768
  walk(root);
1666
1769
  }
1667
- return layout;
1770
+ return {
1771
+ animating,
1772
+ auxSurfaceDebug,
1773
+ layout,
1774
+ layoutDirty,
1775
+ renderStatsAvailable
1776
+ };
1668
1777
  };
1669
1778
  let stableLayout = null;
1670
1779
  let stable = 0;
1780
+ let lastSnapshot = null;
1671
1781
  while (Date.now() < deadline) {
1672
- const layout = await readSnapshot();
1673
- if (isLayoutStable(stableLayout, layout)) {
1782
+ const snapshot = await readSnapshot();
1783
+ lastSnapshot = snapshot;
1784
+ if ((!strict2 || snapshot.renderStatsAvailable) && !snapshot.animating && !snapshot.layoutDirty && isLayoutStable(stableLayout, snapshot.layout)) {
1674
1785
  stable++;
1675
1786
  if (stable >= requiredStablePolls) {
1676
1787
  return { settled: true, elapsed: Date.now() - start };
1677
1788
  }
1678
1789
  } else {
1679
- stableLayout = layout;
1790
+ stableLayout = snapshot.layout;
1680
1791
  stable = 0;
1681
1792
  }
1682
1793
  await sleep(pollMs);
@@ -1684,10 +1795,10 @@ async function waitForSootsimIdle(page, maxMs = 3e3) {
1684
1795
  return {
1685
1796
  settled: false,
1686
1797
  elapsed: Date.now() - start,
1687
- reason: transitionError ? `layout fallback after screen transition wait failed: ${transitionError}` : "layout fallback"
1798
+ reason: transitionError ? `layout fallback after screen transition wait failed: ${transitionError}` : strict2 ? `strict idle state unavailable: renderStats=${lastSnapshot?.renderStatsAvailable === true} animating=${lastSnapshot?.animating === true} layoutDirty=${lastSnapshot?.layoutDirty === true} layoutNodes=${(lastSnapshot?.layout.length ?? 0) / 4} aux=${JSON.stringify(lastSnapshot?.auxSurfaceDebug)}` : "layout fallback"
1688
1799
  };
1689
1800
  },
1690
- { maxMs }
1801
+ { maxMs, strict }
1691
1802
  );
1692
1803
  if (!result?.settled) {
1693
1804
  throw new Error(
@@ -1849,48 +1960,25 @@ async function captureSootsimPngFast(opts) {
1849
1960
  }
1850
1961
  async function captureSootsimPng(opts) {
1851
1962
  const page = getPage();
1852
- const result = await page.evaluate(
1853
- async (captureOpts) => {
1854
- const screenshot = window.SootSim?.bridges?.screenshot;
1855
- if (typeof screenshot !== "function") {
1856
- throw new Error("sootsim screenshot bridge is not installed");
1857
- }
1858
- const gapMs = 100;
1859
- const maxWaitMs = 8e3;
1860
- const minAttempts = 3;
1861
- const t0 = Date.now();
1862
- let prev = await screenshot(captureOpts);
1863
- let attempts = 1;
1864
- while (attempts < minAttempts || Date.now() - t0 < maxWaitMs) {
1865
- await new Promise((r) => setTimeout(r, gapMs));
1866
- const next = await screenshot(captureOpts);
1867
- attempts++;
1868
- if (next === prev) {
1869
- return {
1870
- dataUrl: next,
1871
- stable: true,
1872
- attempts,
1873
- elapsedMs: Date.now() - t0
1874
- };
1875
- }
1876
- prev = next;
1877
- }
1878
- return { dataUrl: prev, stable: false, attempts, elapsedMs: Date.now() - t0 };
1879
- },
1880
- {
1881
- crop: opts?.crop,
1882
- format: "png"
1963
+ const deadline = Date.now() + 8e3;
1964
+ let previous = null;
1965
+ let identicalFrames = 1;
1966
+ let attempts = 0;
1967
+ while (Date.now() < deadline) {
1968
+ await waitForSootsimIdle(page, Math.max(1, deadline - Date.now()), true);
1969
+ const current = await captureSootsimPngFast(opts);
1970
+ attempts++;
1971
+ if ((0, import_proof_frame.framesIdentical)(previous, current)) {
1972
+ identicalFrames++;
1973
+ if (identicalFrames >= import_proof_frame.REQUIRED_IDENTICAL_PROOF_FRAMES) return current;
1974
+ } else {
1975
+ identicalFrames = 1;
1883
1976
  }
1884
- );
1885
- if (!result.dataUrl) {
1886
- throw new Error("sootsim screenshot bridge returned an empty image");
1977
+ previous = current;
1887
1978
  }
1888
- if (!result.stable) {
1889
- console.warn(
1890
- `[sootsim-detox] screenshot did not stabilize after ${result.elapsedMs}ms (${result.attempts} captures); using last frame`
1891
- );
1892
- }
1893
- return decodePngDataUrl(result.dataUrl);
1979
+ throw new Error(
1980
+ `sootsim screenshot did not reach ${import_proof_frame.REQUIRED_IDENTICAL_PROOF_FRAMES} identical idle frames in ${attempts} captures`
1981
+ );
1894
1982
  }
1895
1983
  async function writeSootsimScreenshot(name, opts) {
1896
1984
  ensureScreenshotDir();
@@ -2013,8 +2101,19 @@ function createSootSimElement(matcher) {
2013
2101
  },
2014
2102
  async replaceText(text) {
2015
2103
  const page = getPage();
2016
- await focusElementForTextEntry(el);
2017
2104
  const node = await findNodeByMatcher(matcher);
2105
+ if (matcher.type === "id" && typeof node?.nodeId === "number" && node.nodeId >= 1073741824) {
2106
+ const replaced = await page.evaluate(
2107
+ async ({ id, value: value2 }) => {
2108
+ const mainShell = window.SootSim?.bridges?.mainShell;
2109
+ if (typeof mainShell?.callTestBridge !== "function") return false;
2110
+ return mainShell.callTestBridge("replaceTextByTestId", id, value2);
2111
+ },
2112
+ { id: matcher.value, value: text }
2113
+ );
2114
+ if (replaced === true) return;
2115
+ }
2116
+ await focusElementForTextEntry(el);
2018
2117
  const value = typeof node?.text === "string" ? node.text : "";
2019
2118
  for (let i = 0; i < value.length; i++) {
2020
2119
  await page.keyboard.press("Backspace");
@@ -2287,6 +2386,28 @@ var device = {
2287
2386
  _currentUrl: "",
2288
2387
  _platform: DETOX_PLATFORM,
2289
2388
  async launchApp(opts) {
2389
+ if (_page && opts?.newInstance === false && !opts.delete && !opts.recordVideoDir && _suspendedAppId) {
2390
+ const page = _page;
2391
+ const appId = _suspendedAppId;
2392
+ await page.evaluate(
2393
+ (id) => window.SootSim?.bridges?.mainShell?.launchApp?.(id),
2394
+ appId
2395
+ );
2396
+ await pollUntil(
2397
+ () => page.evaluate(async (id) => {
2398
+ const state = await window.SootSim?.bridges?.mainShell?.getState?.();
2399
+ return state?.state === "app" && state.activeApp === id && state.switcherPhase === "idle";
2400
+ }, appId),
2401
+ Boolean,
2402
+ {
2403
+ timeoutMs: 1e4,
2404
+ label: `SootSim app ${appId} to resume`
2405
+ }
2406
+ );
2407
+ _suspendedAppId = null;
2408
+ await waitForSootsimTree(page, 1e4);
2409
+ return;
2410
+ }
2290
2411
  if (!_browser) {
2291
2412
  const launched = await launchReapedChromeScoped(
2292
2413
  (options) => import_playwright.chromium.launch(options),
@@ -2922,6 +3043,27 @@ var device = {
2922
3043
  }
2923
3044
  },
2924
3045
  async sendToHome() {
3046
+ const page = getPage();
3047
+ _suspendedAppId = await page.evaluate(async () => {
3048
+ const state = await window.SootSim?.bridges?.mainShell?.getState?.();
3049
+ const appId = state?.activeApp;
3050
+ if (typeof appId !== "string") {
3051
+ throw new Error(`cannot send an inactive SootSim app home`);
3052
+ }
3053
+ window.SootSim?.bridges?.mainShell?.goHome?.();
3054
+ return appId;
3055
+ });
3056
+ await pollUntil(
3057
+ () => page.evaluate(async () => {
3058
+ const state = await window.SootSim?.bridges?.mainShell?.getState?.();
3059
+ return state?.state === "home" && state.switcherPhase === "idle";
3060
+ }),
3061
+ Boolean,
3062
+ {
3063
+ timeoutMs: 1e4,
3064
+ label: "SootSim home transition"
3065
+ }
3066
+ );
2925
3067
  },
2926
3068
  // get direct access to the playwright page for advanced use
2927
3069
  getPage() {
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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;
@@ -762,16 +762,21 @@ async function waitForSootsimIdle({
762
762
 
763
763
  const readSnapshot = async () => {
764
764
  let animating = false
765
+ let layoutDirty = false
765
766
  let pendingFetches = 0
766
767
  let requestTotal = 0
767
768
  let requestInFlight = 0
769
+ let renderStatsAvailable = false
768
770
  try {
769
771
  const stats = await window.__sootsimRenderHost?.queryStats?.()
770
772
  if (stats) {
773
+ renderStatsAvailable = true
771
774
  animating =
772
775
  stats.hasActiveAnims === true ||
773
776
  stats.hasActiveNativeAnimations === true ||
774
777
  stats.hasPendingAnimationFrames === true
778
+ layoutDirty =
779
+ stats.layoutDirty === true && stats.renderRequested === true
775
780
  // a freshly-pushed screen showing a skeleton is layout-stable
776
781
  // but not actually settled \u2014 its data/images are still in
777
782
  // flight. treat bounded image-loader fetches as not-idle so
@@ -798,7 +803,7 @@ async function waitForSootsimIdle({
798
803
  }
799
804
  walk(root)
800
805
  }
801
- return { layout: nodes.join(';'), animating, pendingFetches, requestTotal, requestInFlight }
806
+ return { layout: nodes.join(';'), animating, layoutDirty, pendingFetches, renderStatsAvailable, requestTotal, requestInFlight }
802
807
  }
803
808
 
804
809
  // how long generic background network is allowed to keep us waiting AFTER
@@ -818,7 +823,9 @@ async function waitForSootsimIdle({
818
823
  let visuallyStillSince = 0
819
824
  while (Date.now() < deadline) {
820
825
  const snapshot = await readSnapshot()
821
- const strictOk = !strict || !snapshot.animating
826
+ const strictOk =
827
+ !strict ||
828
+ (snapshot.renderStatsAvailable && !snapshot.animating && !snapshot.layoutDirty)
822
829
  // visually settled: no animations, no image content loading, layout
823
830
  // unchanged since the last poll.
824
831
  const visuallyStill =
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_PRODUCTION_BUNDLE_OPTION = "rnxsim";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/react-native-host-modules.ts
4
4
  var REACT_NATIVE_PASSTHROUGH_SPECIFIERS = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.355 | (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;
@@ -146,16 +146,21 @@ async function waitForSootsimIdle({
146
146
 
147
147
  const readSnapshot = async () => {
148
148
  let animating = false
149
+ let layoutDirty = false
149
150
  let pendingFetches = 0
150
151
  let requestTotal = 0
151
152
  let requestInFlight = 0
153
+ let renderStatsAvailable = false
152
154
  try {
153
155
  const stats = await window.__sootsimRenderHost?.queryStats?.()
154
156
  if (stats) {
157
+ renderStatsAvailable = true
155
158
  animating =
156
159
  stats.hasActiveAnims === true ||
157
160
  stats.hasActiveNativeAnimations === true ||
158
161
  stats.hasPendingAnimationFrames === true
162
+ layoutDirty =
163
+ stats.layoutDirty === true && stats.renderRequested === true
159
164
  // a freshly-pushed screen showing a skeleton is layout-stable
160
165
  // but not actually settled \u2014 its data/images are still in
161
166
  // flight. treat bounded image-loader fetches as not-idle so
@@ -182,7 +187,7 @@ async function waitForSootsimIdle({
182
187
  }
183
188
  walk(root)
184
189
  }
185
- return { layout: nodes.join(';'), animating, pendingFetches, requestTotal, requestInFlight }
190
+ return { layout: nodes.join(';'), animating, layoutDirty, pendingFetches, renderStatsAvailable, requestTotal, requestInFlight }
186
191
  }
187
192
 
188
193
  // how long generic background network is allowed to keep us waiting AFTER
@@ -202,7 +207,9 @@ async function waitForSootsimIdle({
202
207
  let visuallyStillSince = 0
203
208
  while (Date.now() < deadline) {
204
209
  const snapshot = await readSnapshot()
205
- const strictOk = !strict || !snapshot.animating
210
+ const strictOk =
211
+ !strict ||
212
+ (snapshot.renderStatsAvailable && !snapshot.animating && !snapshot.layoutDirty)
206
213
  // visually settled: no animations, no image content loading, layout
207
214
  // unchanged since the last poll.
208
215
  const visuallyStill =