peachsim 0.1.939 → 0.1.1399

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 (396) hide show
  1. package/README.md +28 -22
  2. package/cli/app-catalog.ts +29 -14
  3. package/cli/app-fonts.ts +5 -3
  4. package/cli/bridge-flow-runner.ts +40 -29
  5. package/cli/cloud-client.ts +57 -21
  6. package/cli/cloud-test-tunnel.ts +12 -18
  7. package/cli/commands/agent.ts +1 -1
  8. package/cli/commands/app-fonts.ts +3 -3
  9. package/cli/commands/assert.ts +8 -8
  10. package/cli/commands/auth.ts +8 -3
  11. package/cli/commands/box/bundle-plane.ts +13 -1
  12. package/cli/commands/box.ts +16 -5
  13. package/cli/commands/compat.ts +1 -1
  14. package/cli/commands/config.ts +2 -2
  15. package/cli/commands/control.ts +125 -71
  16. package/cli/commands/cpu-profile.ts +45 -1
  17. package/cli/commands/daemon.ts +131 -33
  18. package/cli/commands/debug.ts +24 -17
  19. package/cli/commands/desktop.ts +7 -1
  20. package/cli/commands/detect.ts +101 -0
  21. package/cli/commands/detox.ts +6 -6
  22. package/cli/commands/device.ts +12 -12
  23. package/cli/commands/electron.ts +32 -14
  24. package/cli/commands/flow.ts +49 -41
  25. package/cli/commands/guest-host.ts +39 -1
  26. package/cli/commands/inspect/core.ts +14 -8
  27. package/cli/commands/inspect/list.ts +1 -1
  28. package/cli/commands/inspect/settle.ts +5 -3
  29. package/cli/commands/inspect/settling.ts +229 -44
  30. package/cli/commands/inspect/wait-idle.ts +3 -2
  31. package/cli/commands/inspect.ts +105 -93
  32. package/cli/commands/install-cli.ts +36 -15
  33. package/cli/commands/install-desktop.ts +68 -195
  34. package/cli/commands/kotlin.ts +6 -5
  35. package/cli/commands/login.ts +5 -5
  36. package/cli/commands/maestro-compare.ts +554 -0
  37. package/cli/commands/maestro-generate.ts +6 -3
  38. package/cli/commands/maestro.ts +22 -0
  39. package/cli/commands/mode.ts +2 -2
  40. package/cli/commands/no-bridge-hint.ts +6 -2
  41. package/cli/commands/platform.ts +35 -6
  42. package/cli/commands/preview.ts +6 -0
  43. package/cli/commands/project-report.ts +10 -12
  44. package/cli/commands/record.ts +37 -37
  45. package/cli/commands/runtime.ts +9 -9
  46. package/cli/commands/screenshot-layers.ts +4 -4
  47. package/cli/commands/screenshot-mode.ts +2 -2
  48. package/cli/commands/screenshot.ts +8 -8
  49. package/cli/commands/screenshots-capture.ts +2 -2
  50. package/cli/commands/serve.ts +9 -12
  51. package/cli/commands/setup.ts +29 -14
  52. package/cli/commands/shell-boolean-mode.ts +2 -2
  53. package/cli/commands/show-touches-mode.ts +2 -2
  54. package/cli/commands/skills.ts +11 -11
  55. package/cli/commands/swift.ts +29 -11
  56. package/cli/commands/telemetry.ts +2 -2
  57. package/cli/commands/test.ts +5 -0
  58. package/cli/commands/three-mode.ts +3 -3
  59. package/cli/commands/timeline.ts +4 -4
  60. package/cli/commands/upgrade.ts +2 -2
  61. package/cli/commands/upload.ts +15 -15
  62. package/cli/commands/what-happened.ts +2 -2
  63. package/cli/current-sim.ts +6 -3
  64. package/cli/desktop-companion.ts +55 -149
  65. package/cli/dev-build-freshness.ts +2 -2
  66. package/cli/drivers/desktop.ts +17 -9
  67. package/cli/drivers/electron.ts +1 -2
  68. package/cli/drivers/playwright-sim-host.ts +11 -2
  69. package/cli/drivers/playwright.ts +35 -2
  70. package/cli/drivers/types.ts +8 -0
  71. package/cli/maestro-compare.ts +670 -0
  72. package/cli/outbound-endpoints.ts +46 -8
  73. package/cli/recording-access.ts +6 -6
  74. package/cli/run-registry.ts +1 -1
  75. package/cli/runtime-compat.ts +5 -1
  76. package/cli/send-to-box.ts +3 -3
  77. package/cli/shell-init.ts +2 -1
  78. package/cli/ws-bridge.ts +9 -5
  79. package/detox/element-types.ts +1 -0
  80. package/detox/gestures.ts +3 -3
  81. package/detox/index.ts +67 -38
  82. package/detox/navigation-lifecycle.ts +9 -6
  83. package/detox/proof-frame.cjs +6 -4
  84. package/dist-lib/agent-daemon-client.cjs +1 -1
  85. package/dist-lib/agent-events.cjs +1 -1
  86. package/dist-lib/attached-projects.cjs +1 -1
  87. package/dist-lib/auth/shared-session.cjs +1 -1
  88. package/dist-lib/backend-origin.cjs +1 -1
  89. package/dist-lib/beta.cjs +1 -1
  90. package/dist-lib/beta.mjs +1 -1
  91. package/dist-lib/bridge-constants.cjs +1 -1
  92. package/dist-lib/bridge-contract-input.cjs +42 -17
  93. package/dist-lib/bridge-contract-input.mjs +41 -16
  94. package/dist-lib/bridge-contract.cjs +1 -4
  95. package/dist-lib/bridge-contract.mjs +1 -3
  96. package/dist-lib/bundle-channel.cjs +2918 -550
  97. package/dist-lib/capture-contract.cjs +65 -24
  98. package/dist-lib/capture-contract.mjs +63 -24
  99. package/dist-lib/cloud-contract.cjs +2 -2
  100. package/dist-lib/cloud-contract.mjs +2 -2
  101. package/dist-lib/cloud-test-args.cjs +1 -1
  102. package/dist-lib/cloud-test-args.mjs +1 -1
  103. package/dist-lib/cloud.cjs +3 -3
  104. package/dist-lib/cloud.mjs +3 -3
  105. package/dist-lib/config.cjs +15 -5
  106. package/dist-lib/config.mjs +154 -0
  107. package/dist-lib/detox/index.cjs +495 -139
  108. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  109. package/dist-lib/expo-swift-bundle.cjs +1168 -238
  110. package/dist-lib/expo-swift-metadata.cjs +34 -23
  111. package/dist-lib/expo-swift-metadata.mjs +32 -23
  112. package/dist-lib/home-paths.cjs +2 -2
  113. package/dist-lib/host/bridge-host.cjs +2938 -654
  114. package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
  117. package/dist-lib/host/replacement-module-handler.cjs +2 -2
  118. package/dist-lib/host/websocket-proxy.cjs +1 -1
  119. package/dist-lib/index.cjs +999 -353
  120. package/dist-lib/jump-to-source-babel.cjs +1 -1
  121. package/dist-lib/jump-to-source-native.cjs +1 -1
  122. package/dist-lib/kotlin-host.cjs +332 -19
  123. package/dist-lib/menu.cjs +1 -1
  124. package/dist-lib/menu.mjs +1 -1
  125. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  126. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  127. package/dist-lib/metro-production-bundle.cjs +7 -7
  128. package/dist-lib/metro-production-bundle.mjs +5 -5
  129. package/dist-lib/metro.cjs +688 -250
  130. package/dist-lib/native-app-identity-project.cjs +2647 -0
  131. package/dist-lib/native-app-identity-project.mjs +1257 -0
  132. package/dist-lib/native-app-identity.cjs +325 -25
  133. package/dist-lib/native-app-identity.mjs +323 -25
  134. package/dist-lib/native-firebase-metadata.cjs +1 -1
  135. package/dist-lib/native-firebase-metadata.mjs +1 -1
  136. package/dist-lib/plist.cjs +1 -1
  137. package/dist-lib/plist.mjs +1 -1
  138. package/dist-lib/profiles.cjs +1 -1
  139. package/dist-lib/public-brand.cjs +1 -1
  140. package/dist-lib/react-native-host-modules.cjs +5 -1
  141. package/dist-lib/react-native-host-modules.mjs +5 -1
  142. package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
  143. package/dist-lib/sdk.cjs +231 -51
  144. package/dist-lib/sdk.mjs +231 -51
  145. package/dist-lib/skills.cjs +4107 -1374
  146. package/dist-lib/swift-compile.cjs +290 -30
  147. package/dist-lib/swift-compile.mjs +290 -30
  148. package/dist-lib/swift-package.cjs +143 -12
  149. package/dist-lib/swift-package.mjs +137 -11
  150. package/dist-lib/swift-submit.cjs +47 -5
  151. package/dist-lib/swift-submit.mjs +42 -5
  152. package/dist-lib/swift-toolchain.cjs +7 -2
  153. package/dist-lib/swift.cjs +1 -1
  154. package/dist-lib/vite-swift.cjs +1392 -458
  155. package/dist-lib/vite.cjs +13 -17
  156. package/dist-lib/worklet-executable.cjs +248 -33
  157. package/dist-lib/worklet-executable.mjs +248 -33
  158. package/install.sh +10 -1
  159. package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
  160. package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
  161. package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
  162. package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
  163. package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
  164. package/kotlin/AppSources/android/view/Window.kt +36 -0
  165. package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
  166. package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
  167. package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
  168. package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
  169. package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
  170. package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
  171. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
  172. package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
  173. package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
  174. package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
  175. package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
  176. package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
  177. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
  178. package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
  179. package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
  180. package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
  181. package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
  182. package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
  183. package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
  184. package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
  185. package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
  186. package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
  187. package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
  188. package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
  189. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
  190. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
  191. package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
  192. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
  193. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
  194. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
  195. package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
  196. package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
  197. package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
  198. package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
  199. package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
  200. package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
  201. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
  202. package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
  203. package/kotlin/README.md +13 -3
  204. package/kotlin/Sources/android/os/Build.kt +17 -0
  205. package/kotlin/Sources/android/os/Handler.kt +35 -0
  206. package/kotlin/Sources/android/os/Looper.kt +17 -0
  207. package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
  208. package/kotlin/Sources/android/os/SystemClock.kt +14 -0
  209. package/kotlin/Sources/android/util/Log.kt +64 -0
  210. package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
  211. package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
  212. package/kotlin/Sources/org/json/JSON.kt +44 -0
  213. package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
  214. package/kotlin/fixtures/counter/Counter.kt +10 -3
  215. package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
  216. package/kotlin/fixtures/counter/vite.config.ts +2 -2
  217. package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
  218. package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
  219. package/kotlin/fixtures/import-animation/Animation.kt +80 -0
  220. package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
  221. package/kotlin/fixtures/import-animation/README.md +24 -0
  222. package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
  223. package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
  224. package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
  225. package/kotlin/fixtures/import-animation/package.json +23 -0
  226. package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
  227. package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
  228. package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
  229. package/kotlin/fixtures/import-editor/Editor.kt +59 -0
  230. package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
  231. package/kotlin/fixtures/import-editor/README.md +27 -0
  232. package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
  233. package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
  234. package/kotlin/fixtures/import-editor/package.json +23 -0
  235. package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
  236. package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
  237. package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
  238. package/kotlin/fixtures/import-effects/Effects.kt +87 -0
  239. package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
  240. package/kotlin/fixtures/import-effects/README.md +19 -0
  241. package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
  242. package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
  243. package/kotlin/fixtures/import-effects/package.json +23 -0
  244. package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
  245. package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
  246. package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
  247. package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
  248. package/kotlin/fixtures/import-layout/Layout.kt +72 -0
  249. package/kotlin/fixtures/import-layout/README.md +24 -0
  250. package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
  251. package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
  252. package/kotlin/fixtures/import-layout/package.json +23 -0
  253. package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
  254. package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
  255. package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
  256. package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
  257. package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
  258. package/kotlin/fixtures/import-navigation/README.md +31 -0
  259. package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
  260. package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
  261. package/kotlin/fixtures/import-navigation/package.json +23 -0
  262. package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
  263. package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
  264. package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
  265. package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
  266. package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
  267. package/kotlin/fixtures/import-overlays/README.md +34 -0
  268. package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
  269. package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
  270. package/kotlin/fixtures/import-overlays/package.json +23 -0
  271. package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
  272. package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
  273. package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
  274. package/kotlin/fixtures/import-scroll/README.md +23 -0
  275. package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
  276. package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
  277. package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
  278. package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
  279. package/kotlin/fixtures/import-scroll/package.json +23 -0
  280. package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
  281. package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
  282. package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
  283. package/kotlin/fixtures/import-selection/README.md +32 -0
  284. package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
  285. package/kotlin/fixtures/import-selection/Selection.kt +78 -0
  286. package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
  287. package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
  288. package/kotlin/fixtures/import-selection/package.json +23 -0
  289. package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
  290. package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
  291. package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
  292. package/kotlin/fixtures/import-surfaces/README.md +22 -0
  293. package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
  294. package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
  295. package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
  296. package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
  297. package/kotlin/fixtures/import-surfaces/package.json +23 -0
  298. package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
  299. package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
  300. package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
  301. package/kotlin/fixtures/import-values/README.md +23 -0
  302. package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
  303. package/kotlin/fixtures/import-values/Values.kt +66 -0
  304. package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
  305. package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
  306. package/kotlin/fixtures/import-values/package.json +23 -0
  307. package/kotlin/fixtures/import-values/tsconfig.json +20 -0
  308. package/kotlin/fixtures/import-values/vite.config.ts +20 -0
  309. package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
  310. package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
  311. package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
  312. package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
  313. package/kotlin/fork/NOTICE +6 -1
  314. package/kotlin/fork/README.md +15 -7
  315. package/kotlin/fork/build.sh +2 -0
  316. package/kotlin/fork/compose-worker-globals.patch +186 -4
  317. package/kotlin/fork/fork.json +2 -2
  318. package/kotlin/fork/skiko-worker-clock.patch +12 -0
  319. package/kotlin/toolchain.json +12 -12
  320. package/kotlin/tools/expo-types.main.kts +115 -0
  321. package/package.json +17 -23
  322. package/scripts/dev-server-scanner.ts +92 -66
  323. package/skills/contrast/SKILL.md +2 -2
  324. package/skills/peach-debug/SKILL.md +1 -1
  325. package/skills/peach-perf/SKILL.md +1 -1
  326. package/skills/peach-setup/SKILL.md +2 -1
  327. package/skills/peach-test/SKILL.md +8 -0
  328. package/src/assetCatalogContract.ts +43 -1
  329. package/src/bridge-contract-input.ts +46 -19
  330. package/src/bridge-contract.ts +0 -1
  331. package/src/bundle-channel.mjs +197 -84
  332. package/src/bundleGlobalFooter.ts +38 -0
  333. package/src/capture-contract.ts +107 -33
  334. package/src/cloud-contract.ts +5 -1
  335. package/src/cloud.ts +5 -2
  336. package/src/config.ts +22 -3
  337. package/src/configured-bundle-producer.ts +1 -1
  338. package/src/desktop-host-delivery.ts +95 -1
  339. package/src/expo-kotlin-bundle.ts +29 -0
  340. package/src/expo-kotlin-host.ts +201 -0
  341. package/src/expo-swift-host.ts +96 -76
  342. package/src/expoKotlinContract.ts +70 -0
  343. package/src/expoSwiftContract.ts +4 -25
  344. package/src/home-paths.ts +7 -4
  345. package/src/host/bridge-host.ts +23 -3
  346. package/src/host/fetch-proxy-handler.ts +13 -0
  347. package/src/host/fetch-proxy-overrides.ts +11 -0
  348. package/src/host/replacement-module-handler.ts +5 -2
  349. package/src/index.ts +3 -1
  350. package/src/kotlin-host.ts +463 -19
  351. package/src/metro-plugin.ts +56 -28
  352. package/src/metro-production-bundle.ts +2 -2
  353. package/src/native-app-identity-project.ts +190 -0
  354. package/src/native-app-identity.ts +398 -34
  355. package/src/native-firebase-config.ts +69 -15
  356. package/src/native-seam-manifest.ts +6 -0
  357. package/src/one-widget-discovery.ts +2 -1
  358. package/src/openstep-plist.ts +107 -0
  359. package/src/react-native-host-modules.ts +4 -0
  360. package/src/runtime-assets.ts +2 -2
  361. package/src/sim-client.ts +2 -2
  362. package/src/swift-binary-modules.ts +3 -1
  363. package/src/swift-compile.ts +286 -38
  364. package/src/swift-distribution-contract.ts +4 -0
  365. package/src/swift-distribution.lock.json +123 -12
  366. package/src/swift-distribution.ts +7 -3
  367. package/src/swift-host.ts +298 -83
  368. package/src/swift-package-manifest.ts +29 -2
  369. package/src/swift-package.ts +180 -10
  370. package/src/swift-packages.ts +4 -0
  371. package/src/swift-standin-emit.ts +4 -1
  372. package/src/swift-standins.ts +274 -15
  373. package/src/swift-submit.ts +62 -7
  374. package/src/swift-toolchain.ts +6 -1
  375. package/src/swiftContract.ts +126 -3
  376. package/src/vite-plugin-one.ts +13 -16
  377. package/src/vite-plugin-swift.ts +4 -5
  378. package/src/vite-plugin.ts +360 -144
  379. package/src/vite.d.ts +1 -1
  380. package/src/worker-system-chunks.ts +221 -0
  381. package/src/worklet-executable.ts +348 -38
  382. package/src/worklets-babel.ts +1 -1
  383. package/src/xcode-project.ts +243 -127
  384. package/dist-lib/agent-identity.cjs +0 -39
  385. package/dist-lib/agent-sessions.cjs +0 -760
  386. package/dist-lib/cli-constants.cjs +0 -32
  387. package/dist-lib/render-mode.cjs +0 -44
  388. package/kotlin/AppSources/android/view/View.kt +0 -74
  389. package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
  390. package/src/render-mode.ts +0 -15
  391. /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
  392. /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
  393. /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
  394. /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
  395. /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
  396. /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
package/dist-lib/sdk.mjs CHANGED
@@ -1,11 +1,10 @@
1
- /*! rnx v0.1.939 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! peach v0.1.1399 | (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);
5
5
 
6
6
  // src/bridge-contract.ts
7
7
  var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
8
- var PUBLIC_NO_NETWORK_MARKER = "public Peach Cloud simulators have no network";
9
8
  var HEADLESS_TENANT_FETCH_HUNG_MARKER = "headless tenant fetch hung";
10
9
  function readyProbeHasContent(probe) {
11
10
  return (probe.browserSurfaceCount ?? 0) > 0 || probe.liveFrameActive || probe.targets > 0 || probe.nodes >= SEMANTIC_READY_CONTENT_NODE_FLOOR;
@@ -746,7 +745,7 @@ function shellEscape(value) {
746
745
  }
747
746
  function waitReadyReason(status) {
748
747
  if (status.bridgeError) {
749
- if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER) || status.bridgeError.includes(PUBLIC_NO_NETWORK_MARKER)) {
748
+ if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER)) {
750
749
  return status.bridgeError;
751
750
  }
752
751
  return `sim unreachable: ${status.bridgeError} \u2014 the target tab is closed or no sim is connected (check \`peach list\`, reopen with \`peach open\`)`;
@@ -766,13 +765,18 @@ async function inspectCaptureReady(bridge, timeoutMs) {
766
765
  if (snapshot.ready) return snapshot;
767
766
  return inspectWaitReady(bridge, timeoutMs);
768
767
  }
769
- var READY_SNAPSHOT_SEND_TIMEOUT_MS = 2e3;
768
+ var READY_SNAPSHOT_SEND_TIMEOUT_MS = 15e3;
770
769
  async function inspectReadySnapshot(bridge, budgetMs, simId) {
771
770
  const deadline = Date.now() + budgetMs;
772
771
  let result;
773
772
  do {
774
- result = await sendReadyWait(bridge, 1, READY_SNAPSHOT_SEND_TIMEOUT_MS, simId);
775
- } while (result.polls !== 1 && !result.error && Date.now() < deadline);
773
+ const remaining = Math.max(0, deadline - Date.now());
774
+ const sendTimeoutMs = Math.max(
775
+ READY_SNAPSHOT_SEND_TIMEOUT_MS,
776
+ Math.min(remaining, 6e4)
777
+ );
778
+ result = await sendReadyWait(bridge, 1, sendTimeoutMs, simId);
779
+ } while (result.polls !== 1 && !result.error?.startsWith("sim disconnected") && !result.error?.startsWith("bridge never reconnected") && Date.now() < deadline);
776
780
  return waitReadyStatus(
777
781
  result,
778
782
  result.polls === 1 && result.probe ? readyProbeIsReady(result.probe) : false
@@ -1416,6 +1420,17 @@ async function resolveTargetCoords(bridge, target) {
1416
1420
  }
1417
1421
 
1418
1422
  // cli/commands/inspect/settling.ts
1423
+ var RuntimeReadinessUnsupportedError = class extends Error {
1424
+ constructor(runtimeVersion, missingFields) {
1425
+ super(
1426
+ `runtime ${runtimeVersion} cannot report animation readiness (${missingFields.join(", ")} missing); run \`peach upgrade\` and reopen the simulator`
1427
+ );
1428
+ this.runtimeVersion = runtimeVersion;
1429
+ this.missingFields = missingFields;
1430
+ __publicField(this, "code", "runtime_readiness_unsupported");
1431
+ this.name = "RuntimeReadinessUnsupportedError";
1432
+ }
1433
+ };
1419
1434
  async function waitForSootsimIdle({
1420
1435
  bridge,
1421
1436
  simId,
@@ -1425,16 +1440,23 @@ async function waitForSootsimIdle({
1425
1440
  strict = false,
1426
1441
  paintStill = false
1427
1442
  }) {
1428
- const result = await bridge.send(
1429
- {
1430
- type: "evaluate",
1431
- simId,
1432
- code: `(async () => {
1443
+ let result;
1444
+ try {
1445
+ result = await bridge.send(
1446
+ {
1447
+ type: "evaluate",
1448
+ simId,
1449
+ code: `(async () => {
1433
1450
  const start = Date.now()
1434
1451
  const deadline = start + ${Math.max(0, Math.round(maxMs))}
1435
1452
  const pollMs = ${Math.max(1, Math.round(pollMs))}
1436
1453
  const strict = ${strict ? "true" : "false"}
1437
1454
  const paintStill = ${paintStill ? "true" : "false"}
1455
+ // full mounted-geometry observation needs at least two hierarchy reads
1456
+ // plus the stillness window, which a sub-second budget cannot afford:
1457
+ // tight budgets (auto-wait) settle on worker stillness plus root
1458
+ // membership, generous ones confirm the geometry too.
1459
+ const fullGeometry = ${maxMs >= 1e3 ? "true" : "false"}
1438
1460
  const requiredStillMs = paintStill ? 0 : ${Math.max(1, Math.round(stablePolls)) * Math.max(1, Math.round(pollMs))}
1439
1461
  const minimumStablePolls = paintStill ? 1 : ${Math.min(2, Math.max(1, Math.round(stablePolls)))}
1440
1462
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
@@ -1471,58 +1493,177 @@ async function waitForSootsimIdle({
1471
1493
  }
1472
1494
  } catch {}
1473
1495
 
1496
+ // a worker that cannot answer within the remaining budget is busy, not
1497
+ // idle: its poll reads as unsettled. bounding each read by the budget
1498
+ // keeps a busy worker from holding a poll past the deadline.
1499
+ const BUSY = { busy: true }
1500
+ const answer = (read) =>
1501
+ Promise.race([
1502
+ Promise.resolve().then(read),
1503
+ new Promise((resolve) =>
1504
+ setTimeout(() => resolve(BUSY), Math.max(deadline - Date.now(), 100)),
1505
+ ),
1506
+ ])
1507
+
1474
1508
  const readSnapshot = async () => {
1475
1509
  let animating = false
1476
1510
  let layoutDirty = false
1477
1511
  let pendingFetches = 0
1512
+ let workerBusy = false
1478
1513
  let requestTotal = 0
1479
1514
  let requestInFlight = 0
1515
+ let appCommits = null
1516
+ let nodeCount = null
1480
1517
  let renderStatsAvailable = false
1481
1518
  let shellAnimating = false
1519
+ let webViewStarting = false
1520
+ let webViewBlocker = ''
1482
1521
  // strict also waits out shell motion: a system alert, sheet or menu
1483
1522
  // animates in the shell worker while the app's own stats read still,
1484
1523
  // so its presentation is complete only once the shell's list empties.
1485
1524
  if (strict) {
1486
- try {
1487
- const motion = await window.__sootsimTest?.listAnimations?.()
1488
- shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell')
1489
- } catch {}
1525
+ const motion = await answer(() => window.__sootsimTest?.listAnimations?.()).catch(() => null)
1526
+ if (motion === BUSY) workerBusy = true
1527
+ else shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell' && anim.priority !== 'low')
1490
1528
  }
1491
- try {
1492
- const stats = await window.__sootsimRenderHost?.queryStats?.()
1493
- if (stats) {
1494
- renderStatsAvailable = true
1495
- animating =
1496
- stats.hasActiveAnims === true ||
1497
- stats.hasActiveNativeAnimations === true ||
1498
- stats.hasPendingAnimationFrames === true
1499
- layoutDirty =
1500
- stats.layoutDirty === true && stats.renderRequested === true
1501
- // a freshly-pushed screen showing a skeleton is layout-stable
1502
- // but not actually settled \u2014 its data/images are still in
1503
- // flight. treat bounded image-loader fetches as not-idle so
1504
- // settle waits for real content, capped by the budget.
1505
- const pf = stats.memory && stats.memory.imageLoader
1506
- ? stats.memory.imageLoader.pendingFetches
1507
- : 0
1508
- pendingFetches = typeof pf === 'number' ? pf : 0
1529
+ const stats = await answer(() => window.__sootsimRenderHost?.queryStats?.()).catch(() => null)
1530
+ if (stats === BUSY) {
1531
+ workerBusy = true
1532
+ } else if (stats) {
1533
+ renderStatsAvailable = true
1534
+ const missingFields = ['hasActiveBlockingNativeAnimations', 'hasPendingBlockingAnimationFrames']
1535
+ .filter((field) => typeof stats[field] !== 'boolean')
1536
+ if (strict && missingFields.length > 0) {
1537
+ return {
1538
+ runtimeUnsupported: {
1539
+ error: 'runtime_readiness_unsupported',
1540
+ runtimeVersion: window.__sootsimRuntimeVersion || 'unknown',
1541
+ missingFields,
1542
+ },
1543
+ }
1509
1544
  }
1510
- } catch {}
1545
+ // positive checks only: an older runtime without the blocking
1546
+ // fields reads as still, and strict rejects that runtime above
1547
+ // instead of ever settling on unknown motion.
1548
+ animating =
1549
+ stats.hasActiveAnims === true ||
1550
+ stats.hasActiveBlockingNativeAnimations === true ||
1551
+ stats.hasPendingBlockingAnimationFrames === true
1552
+ layoutDirty =
1553
+ stats.layoutDirty === true && stats.renderRequested === true
1554
+ // a freshly-pushed screen showing a skeleton is layout-stable
1555
+ // but not actually settled \u2014 its data/images are still in
1556
+ // flight. treat bounded image-loader fetches as not-idle so
1557
+ // settle waits for real content, capped by the budget.
1558
+ const pf = stats.memory && stats.memory.imageLoader
1559
+ ? stats.memory.imageLoader.pendingFetches
1560
+ : 0
1561
+ pendingFetches = typeof pf === 'number' ? pf : 0
1562
+ // tenant layout commits: a screen that keeps committing is still
1563
+ // mounting or remounting, even with no animation flag raised.
1564
+ appCommits = typeof stats.appCommitCount === 'number' ? stats.appCommitCount : null
1565
+ }
1566
+ // image preparation ends in the tenant before the compositor decodes
1567
+ // and realizes its pixels. both owners must finish before settling.
1568
+ // the compositor rejects a stats request it is too busy to answer.
1569
+ const compositor = await answer(() => window.__sootsimCompositor.getStats()).catch(() => BUSY)
1570
+ if (compositor === BUSY) {
1571
+ workerBusy = true
1572
+ } else {
1573
+ pendingFetches += compositor.images.pendingFetches
1574
+ pendingFetches += compositor.imageRealization.pending
1575
+ if (compositor.webViewCaptureSettled === false) {
1576
+ webViewStarting = true
1577
+ webViewBlocker = 'compositor webView capture not settled'
1578
+ }
1579
+ }
1511
1580
  try {
1512
1581
  const counts = await window.__sootsimTest?.getRequestCounts?.()
1513
1582
  requestTotal = typeof counts?.total === 'number' ? counts.total : 0
1514
1583
  requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
1515
1584
  } catch {}
1516
- const root = window.__sootsimRoot
1585
+ // mounted-root membership: the live node count moves while the tree
1586
+ // mounts, unmounts or recycles, in either render mode.
1587
+ try {
1588
+ const total = await window.__sootsimTest?.getNodeCount?.()
1589
+ nodeCount = typeof total === 'number' ? total : null
1590
+ } catch {}
1591
+ // the mounted hierarchy in render-worker mode comes from the test
1592
+ // bridge: window.__sootsimRoot is an empty placeholder there, so a
1593
+ // walk over it hashes every screen to the same empty string while
1594
+ // it moves. listInspectable is the worker-backed read describe
1595
+ // uses; a worker too busy to answer it reads as unsettled. tight
1596
+ // budgets skip this read and settle on the cheaper signals above.
1597
+ let hierarchy = null
1598
+ if (fullGeometry && typeof window.__sootsimTest?.listInspectable === 'function') {
1599
+ try {
1600
+ hierarchy = await answer(() => window.__sootsimTest.listInspectable({}))
1601
+ } catch {
1602
+ hierarchy = null
1603
+ }
1604
+ }
1605
+ if (hierarchy === BUSY) {
1606
+ workerBusy = true
1607
+ hierarchy = null
1608
+ } else if (!Array.isArray(hierarchy)) {
1609
+ hierarchy = null
1610
+ }
1517
1611
  const nodes = []
1518
- if (root) {
1519
- const walk = (n) => {
1520
- if (n.layout && n.layout.width > 0) {
1521
- nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
1612
+ const PREVIEW_PROGRESS_REGEX = /^(creating webview|loading html|fetching bundle|waiting for first render|starting preview|loading simulator|fetching app code|waiting for native preview|starting design|loading canvas|fetching screens|painting the canvas|waiting for webview|waiting for preview|waiting for canvas|preview stalled)/i
1613
+ const notePreviewProgress = (tid, text) => {
1614
+ if (typeof tid === 'string' && (tid === 'web-preview-progress' || tid.endsWith('-preview-progress'))) {
1615
+ webViewStarting = true
1616
+ if (!webViewBlocker) webViewBlocker = 'preview progress active (' + tid + ')'
1617
+ }
1618
+ if (typeof text === 'string' && PREVIEW_PROGRESS_REGEX.test(text.trim())) {
1619
+ webViewStarting = true
1620
+ if (!webViewBlocker) webViewBlocker = 'webView startup in progress ("' + text.trim() + '")'
1621
+ }
1622
+ }
1623
+ if (hierarchy) {
1624
+ for (const n of hierarchy) {
1625
+ const layout = n && n.layout
1626
+ if (layout && layout.width > 0) {
1627
+ const abs = (n && (n.absolute || n.absolutePosition)) || layout
1628
+ nodes.push(Math.round(abs.x) + ',' + Math.round(abs.y) + ',' + Math.round(layout.width))
1629
+ }
1630
+ notePreviewProgress(
1631
+ n.testID || n.testId,
1632
+ typeof n.text === 'string' ? n.text : '',
1633
+ )
1634
+ }
1635
+ } else {
1636
+ const root = window.__sootsimRoot
1637
+ if (root) {
1638
+ const walk = (n) => {
1639
+ if (n.layout && n.layout.width > 0) {
1640
+ nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
1641
+ }
1642
+ notePreviewProgress(
1643
+ n.testID || n.props?.testID || n.props?.testId,
1644
+ n.textContent || (typeof n.props?.children === 'string' ? n.props.children : ''),
1645
+ )
1646
+ for (const c of n.children || []) walk(c)
1647
+ }
1648
+ walk(root)
1649
+ }
1650
+ }
1651
+ if (!webViewStarting && typeof document !== 'undefined') {
1652
+ const progressEl = document.querySelector(
1653
+ '[data-testid$="-preview-progress"], [data-testid="web-preview-progress"], [data-testid="ios-preview-progress"], [data-testid="design-preview-progress"]'
1654
+ )
1655
+ if (progressEl) {
1656
+ webViewStarting = true
1657
+ webViewBlocker = 'preview progress element displayed'
1658
+ } else {
1659
+ const unreadyWebView = document.querySelector(
1660
+ '[data-sootsim-webview-loading="true"], [data-sootsim-webview-mode="placeholder"]'
1661
+ )
1662
+ if (unreadyWebView) {
1663
+ webViewStarting = true
1664
+ webViewBlocker = 'webView document still loading'
1522
1665
  }
1523
- for (const c of n.children || []) walk(c)
1524
1666
  }
1525
- walk(root)
1526
1667
  }
1527
1668
  if (paintStill) {
1528
1669
  const canvas = composite.getCanvas()
@@ -1536,7 +1677,7 @@ async function waitForSootsimIdle({
1536
1677
  pixelFrameToken = token
1537
1678
  }
1538
1679
  }
1539
- return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, renderStatsAvailable, requestTotal, requestInFlight }
1680
+ return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, workerBusy, webViewStarting, webViewBlocker, renderStatsAvailable, requestTotal, requestInFlight, appCommits, nodeCount }
1540
1681
  }
1541
1682
 
1542
1683
  // how long generic background network is allowed to keep us waiting AFTER
@@ -1554,6 +1695,8 @@ async function waitForSootsimIdle({
1554
1695
  let lastScreenPixels = null
1555
1696
  let screenChangedPolls = 0
1556
1697
  let lastRequestTotal = -1
1698
+ let lastAppCommits = null
1699
+ let lastNodeCount = null
1557
1700
  let stable = 0
1558
1701
  let visuallyStillSince = 0
1559
1702
  // counts across the whole budget: a flag that is true on every poll is a
@@ -1563,6 +1706,7 @@ async function waitForSootsimIdle({
1563
1706
  let dirtyPolls = 0
1564
1707
  let animatingPolls = 0
1565
1708
  let layoutChangedPolls = 0
1709
+ let webViewStartingPolls = 0
1566
1710
  const screenUnchanged = (pixels) => {
1567
1711
  if (!pixels || !lastScreenPixels || pixels.width !== lastScreenPixels.width || pixels.height !== lastScreenPixels.height) return false
1568
1712
  if (pixels === lastScreenPixels) return true
@@ -1573,9 +1717,11 @@ async function waitForSootsimIdle({
1573
1717
  }
1574
1718
  while (Date.now() < deadline) {
1575
1719
  const snapshot = await readSnapshot()
1720
+ if (snapshot.runtimeUnsupported) return snapshot.runtimeUnsupported
1576
1721
  polls++
1577
1722
  if (snapshot.layoutDirty) dirtyPolls++
1578
1723
  if (snapshot.animating || snapshot.shellAnimating) animatingPolls++
1724
+ if (snapshot.webViewStarting) webViewStartingPolls++
1579
1725
  if (polls > 1 && snapshot.layout !== lastLayout) layoutChangedPolls++
1580
1726
  const screenChanged = paintStill && !screenUnchanged(snapshot.screenPixels)
1581
1727
  if (polls > 1 && screenChanged) screenChangedPolls++
@@ -1585,12 +1731,24 @@ async function waitForSootsimIdle({
1585
1731
  !snapshot.animating &&
1586
1732
  !snapshot.shellAnimating &&
1587
1733
  !snapshot.layoutDirty)
1588
- // visually settled: no animations, no image content loading, layout
1589
- // unchanged since the last poll.
1734
+ // visually settled: no worker motion or layout work, no new layout
1735
+ // commits, a stable mounted node count, no image content loading,
1736
+ // no webview startup in progress, layout unchanged since the last
1737
+ // poll. both modes wait out finite worker motion now; strict
1738
+ // additionally implies the flags through strictOk and adds shell
1739
+ // motion plus the blocking-stats floor. a null count or commit
1740
+ // reading means the runtime does not report it, which reads as
1741
+ // stable the way a missing stats block does.
1590
1742
  const visuallyStill =
1591
1743
  strictOk &&
1744
+ !snapshot.animating &&
1745
+ !snapshot.layoutDirty &&
1746
+ (snapshot.appCommits === null || lastAppCommits === null || snapshot.appCommits === lastAppCommits) &&
1747
+ (snapshot.nodeCount === null || lastNodeCount === null || snapshot.nodeCount === lastNodeCount) &&
1592
1748
  !screenChanged &&
1593
1749
  snapshot.pendingFetches === 0 &&
1750
+ !snapshot.workerBusy &&
1751
+ !snapshot.webViewStarting &&
1594
1752
  snapshot.layout === lastLayout
1595
1753
  // generic network quiet: nothing in flight and no new requests issued.
1596
1754
  const networkQuiet =
@@ -1615,15 +1773,22 @@ async function waitForSootsimIdle({
1615
1773
  lastLayout = snapshot.layout
1616
1774
  lastScreenPixels = snapshot.screenPixels
1617
1775
  lastRequestTotal = snapshot.requestTotal
1776
+ lastAppCommits = snapshot.appCommits
1777
+ lastNodeCount = snapshot.nodeCount
1618
1778
  await sleep(pollMs)
1619
1779
  }
1620
1780
  const last = await readSnapshot()
1781
+ if (last.runtimeUnsupported) return last.runtimeUnsupported
1621
1782
  const blockers = []
1622
1783
  if (strict && !last.renderStatsAvailable) blockers.push('render stats unavailable')
1623
1784
  if (last.animating) blockers.push('animations still running')
1624
1785
  if (last.shellAnimating) blockers.push('shell animations still running')
1625
1786
  if (last.layoutDirty) blockers.push('layout still dirty')
1787
+ if (last.appCommits !== null && lastAppCommits !== null && last.appCommits !== lastAppCommits) blockers.push('layout commits still landing')
1788
+ if (last.nodeCount !== null && lastNodeCount !== null && last.nodeCount !== lastNodeCount) blockers.push('node count still changing')
1626
1789
  if (last.pendingFetches > 0) blockers.push(last.pendingFetches + ' image fetches pending')
1790
+ if (last.workerBusy) blockers.push('a render worker too busy to report')
1791
+ if (last.webViewStarting) blockers.push(last.webViewBlocker || 'webView still starting')
1627
1792
  if (last.layout !== lastLayout) blockers.push('layout still changing')
1628
1793
  if (paintStill && !last.screenPixels) blockers.push('screen pixels unavailable')
1629
1794
  else if (paintStill && !screenUnchanged(last.screenPixels)) blockers.push('screen pixels still changing')
@@ -1636,17 +1801,31 @@ async function waitForSootsimIdle({
1636
1801
  blockedBy:
1637
1802
  (blockers.length ? blockers.join(', ') : 'unknown') +
1638
1803
  ' over ' + polls + ' polls (layout changed ' + layoutChangedPolls +
1639
- 'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
1804
+ 'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, webViewStarting ' + webViewStartingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
1640
1805
  }
1641
1806
  } finally {
1642
1807
  unsubscribe?.()
1643
1808
  }
1644
1809
  })()`
1645
- },
1646
- {
1647
- timeoutMs: maxMs + 1e3
1648
- }
1649
- );
1810
+ },
1811
+ {
1812
+ timeoutMs: Math.max(5e3, maxMs + 2e3)
1813
+ }
1814
+ );
1815
+ } catch (error) {
1816
+ const message = error instanceof Error ? error.message : String(error);
1817
+ return {
1818
+ settled: false,
1819
+ elapsed: maxMs,
1820
+ blockedBy: message
1821
+ };
1822
+ }
1823
+ if (result?.error === "runtime_readiness_unsupported" && typeof result.runtimeVersion === "string" && Array.isArray(result.missingFields) && result.missingFields.every((field) => typeof field === "string")) {
1824
+ throw new RuntimeReadinessUnsupportedError(
1825
+ result.runtimeVersion,
1826
+ result.missingFields
1827
+ );
1828
+ }
1650
1829
  const { elapsed, settled, blockedBy } = result ?? {};
1651
1830
  return {
1652
1831
  elapsed: typeof elapsed === "number" ? elapsed : maxMs,
@@ -1664,6 +1843,7 @@ async function waitReadyAndSettle(bridge, timeoutMs, options = {}) {
1664
1843
  });
1665
1844
  let idle = null;
1666
1845
  for (; ; ) {
1846
+ idle = null;
1667
1847
  const ready = await inspectWaitReady(bridge, remaining(), options);
1668
1848
  if (!ready.ready) return result(ready, idle);
1669
1849
  idle = await waitForSootsimIdle({
@@ -2164,7 +2344,7 @@ function buildSimOpenUrl(currentUrl, target) {
2164
2344
  const url = new URL(currentUrl);
2165
2345
  for (const param of TARGET_SEARCH_PARAMS) url.searchParams.delete(param);
2166
2346
  const pathname = url.pathname.replace(/\/+$/, "") || "/";
2167
- const prefix = pathname === "/__soot" || pathname.startsWith("/__soot/") ? "/__soot" : "";
2347
+ const prefix = pathname === "/__peachsim" || pathname.startsWith("/__peachsim/") ? "/__peachsim" : "";
2168
2348
  const normalized = String(target).trim();
2169
2349
  if (/^\d+$/.test(normalized)) {
2170
2350
  url.pathname = `${prefix}/rn/${normalized}`;