peachsim 0.1.940 → 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 +981 -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 +670 -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 +304 -25
  133. package/dist-lib/native-app-identity.mjs +302 -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 +367 -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
@@ -0,0 +1,72 @@
1
+ package dev.contrast.kotlinlayout
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Arrangement
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.Column
7
+ import androidx.compose.foundation.layout.Row
8
+ import androidx.compose.foundation.layout.Spacer
9
+ import androidx.compose.foundation.layout.fillMaxSize
10
+ import androidx.compose.foundation.layout.padding
11
+ import androidx.compose.foundation.layout.size
12
+ import androidx.compose.foundation.layout.width
13
+ import androidx.compose.material3.Button
14
+ import androidx.compose.material3.MaterialTheme
15
+ import androidx.compose.material3.Surface
16
+ import androidx.compose.material3.Text
17
+ import androidx.compose.material3.lightColorScheme
18
+ import androidx.compose.runtime.Composable
19
+ import androidx.compose.runtime.getValue
20
+ import androidx.compose.runtime.mutableStateOf
21
+ import androidx.compose.runtime.remember
22
+ import androidx.compose.runtime.setValue
23
+ import androidx.compose.ui.Alignment
24
+ import androidx.compose.ui.Modifier
25
+ import androidx.compose.ui.graphics.Color
26
+ import androidx.compose.ui.layout.onGloballyPositioned
27
+ import androidx.compose.ui.layout.positionInParent
28
+ import androidx.compose.ui.platform.testTag
29
+ import androidx.compose.ui.unit.dp
30
+
31
+ @Composable
32
+ fun Layout(title: String, onStep: ((Int) -> Unit)? = null) {
33
+ var count by remember { mutableStateOf(0) }
34
+ var geometry by remember { mutableStateOf(mapOf<String, List<Int>>()) }
35
+ fun measured(name: String, modifier: Modifier): Modifier = modifier.onGloballyPositioned {
36
+ val position = it.positionInParent()
37
+ val value = listOf(position.x.toInt(), position.y.toInt(), it.size.width, it.size.height)
38
+ if (geometry[name] != value) geometry = geometry + (name to value)
39
+ }
40
+ MaterialTheme(colorScheme = lightColorScheme()) {
41
+ Surface(Modifier.fillMaxSize()) {
42
+ Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
43
+ Text(title, modifier = Modifier.testTag("layout-title"))
44
+ Text("Count: $count", modifier = Modifier.testTag("layout-count"))
45
+ Row(
46
+ measured("row", Modifier.size(280.dp, 60.dp).background(Color(0xFFE8DEF8))),
47
+ verticalAlignment = Alignment.CenterVertically,
48
+ ) {
49
+ Box(measured("first", Modifier.weight(1f).size(height = 20.dp, width = 1.dp).background(Color(0xFF6750A4))))
50
+ Spacer(measured("spacer", Modifier.width(8.dp)))
51
+ Box(measured("second", Modifier.weight(2f).size(height = 40.dp, width = 1.dp).background(Color(0xFF625B71))))
52
+ }
53
+ Box(measured("box", Modifier.size(280.dp, 80.dp).background(Color(0xFFEADDFF)))) {
54
+ Box(measured("aligned", Modifier.align(Alignment.BottomEnd).size(40.dp, 24.dp).background(Color(0xFF7D5260))))
55
+ }
56
+ Button(
57
+ onClick = { count += 1; onStep?.invoke(count) },
58
+ modifier = Modifier.testTag("layout-step"),
59
+ ) { Text("Next layout step") }
60
+ Button(
61
+ onClick = { count += 1000; onStep?.invoke(count) },
62
+ enabled = false,
63
+ modifier = Modifier.testTag("layout-disabled"),
64
+ ) { Text("Disabled layout step") }
65
+ Text(
66
+ geometry.entries.sortedBy { it.key }.joinToString(";") { (name, value) -> "$name=${value.joinToString(",")}" },
67
+ modifier = Modifier.testTag("layout-geometry"),
68
+ )
69
+ }
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,24 @@
1
+ # Imported Compose layout
2
+
3
+ Run One from this directory with `bunx one dev --port 8081`. Build Android
4
+ through the repository's remote builder after `bunx one prebuild --platform android`.
5
+ Open the same server in Peach with `peach open <port> --device pixel-8`.
6
+ For Contrast, import the fixture with catalog versions materialized.
7
+
8
+ The unchanged Kotlin import lays out a weighted Row, Spacer and aligned Box
9
+ inside a padded Column. `layout-geometry` reports child positions and sizes in
10
+ physical pixels. Compare it between hosts at the same device density.
11
+
12
+ Tap `layout-step`. Compose's count and React's step must both advance once,
13
+ and the callback must update the imported title to `Layout step 1` while the
14
+ remembered count stays at one. Tapping `layout-disabled` must preserve that
15
+ state. A second enabled tap must advance every readout to two.
16
+ Capture each state and bind its source, bundle and compiled artifacts.
17
+
18
+ RAN, 2026-10-11: fresh One Android API 37, Peach and Contrast Android import
19
+ runs pass all four states with identical measured geometry. The
20
+ [functional receipt](https://r2.sootsim.com/kotlin-evidence/import-layout/44494c189ca794bbf49431d924c9e77dcf9c04af54a25a38ef06bf642ced1461/proof.json)
21
+ binds the Kotlin source, compiled artifact, native APK, captures, trees and
22
+ probes. Wrong geometry and a disabled callback change both fail the saved
23
+ receipt verdict. This covers geometry and callback state, with no full-frame
24
+ pixel, glyph, release APK or production-delivery claim.
@@ -0,0 +1,4 @@
1
+ import { Slot } from 'one'
2
+ export default function Layout() {
3
+ return <Slot />
4
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../ImportLayout.native'
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-layout-fixture",
3
+ "private": true,
4
+ "type": "module",
5
+ "targets": [
6
+ "native"
7
+ ],
8
+ "dependencies": {
9
+ "@react-navigation/core": "catalog:",
10
+ "@react-navigation/native": "catalog:",
11
+ "one": "catalog:",
12
+ "react": "catalog:",
13
+ "react-native": "catalog:",
14
+ "react-native-reanimated": "catalog:",
15
+ "react-native-screens": "catalog:",
16
+ "react-native-worklets": "catalog:"
17
+ },
18
+ "devDependencies": {
19
+ "@react-native-community/template": "catalog:",
20
+ "peachsim": "workspace:*",
21
+ "vite": "catalog:"
22
+ }
23
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "paths": {
4
+ "~/*": ["./*"]
5
+ },
6
+ "strict": true,
7
+ "allowArbitraryExtensions": true,
8
+ "rootDir": ".",
9
+ "module": "Preserve",
10
+ // allows react-native style imports without path extensions, for compat with platform-specific files
11
+ "moduleResolution": "Bundler",
12
+ "preserveSymlinks": true,
13
+ "skipLibCheck": true,
14
+ "jsx": "react-jsx",
15
+ "noImplicitAny": false,
16
+ "types": ["node", "react", "vite/client"],
17
+ "lib": ["dom", "esnext"]
18
+ },
19
+ "exclude": ["node_modules", "**/test", "**/dist", "**/types", "**/__tests__"]
20
+ }
@@ -0,0 +1,20 @@
1
+ import { one } from 'one/vite'
2
+ import { peachPlugin } from 'peachsim/vite'
3
+ export default {
4
+ root: import.meta.dirname,
5
+ plugins: [
6
+ one({
7
+ web: { defaultRenderMode: 'spa' },
8
+ native: {
9
+ bundler: 'vite',
10
+ app: {
11
+ name: 'KotlinLayout',
12
+ scheme: 'kotlinlayout',
13
+ android: { applicationId: 'dev.contrast.kotlinlayout' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }
@@ -0,0 +1,18 @@
1
+ import { useState } from 'react'
2
+ import { Text, View, type ViewStyle } from 'react-native'
3
+ import { Navigation } from './Navigation.kt'
4
+
5
+ export default function Index() {
6
+ const [step, setStep] = useState(0)
7
+ const navigationProps = {
8
+ title: `Navigation step ${step}`,
9
+ onStep: setStep,
10
+ style: { flex: 1 } satisfies ViewStyle,
11
+ }
12
+ return (
13
+ <View style={{ flex: 1, backgroundColor: '#fff' }}>
14
+ <Navigation {...navigationProps} />
15
+ <Text testID="navigation-react-step">React step: {step}</Text>
16
+ </View>
17
+ )
18
+ }
@@ -0,0 +1,7 @@
1
+ // generated by one typegen; edits will be replaced
2
+ import type { ReactElement } from 'react'
3
+
4
+ export declare function Navigation(props: {
5
+ title: string
6
+ onStep?: ((value0: number) => void) | null
7
+ }): ReactElement
@@ -0,0 +1,104 @@
1
+ package dev.contrast.kotlinnavigation
2
+
3
+ import androidx.compose.foundation.layout.Arrangement
4
+ import androidx.compose.foundation.layout.Column
5
+ import androidx.compose.foundation.layout.fillMaxSize
6
+ import androidx.compose.foundation.layout.padding
7
+ import androidx.compose.material3.Button
8
+ import androidx.compose.material3.ExperimentalMaterial3Api
9
+ import androidx.compose.material3.MaterialTheme
10
+ import androidx.compose.material3.NavigationBar
11
+ import androidx.compose.material3.NavigationBarItem
12
+ import androidx.compose.material3.Scaffold
13
+ import androidx.compose.material3.Text
14
+ import androidx.compose.material3.TopAppBar
15
+ import androidx.compose.material3.lightColorScheme
16
+ import androidx.compose.runtime.Composable
17
+ import androidx.compose.runtime.getValue
18
+ import androidx.compose.runtime.mutableStateOf
19
+ import androidx.compose.runtime.remember
20
+ import androidx.compose.runtime.saveable.rememberSaveable
21
+ import androidx.compose.runtime.setValue
22
+ import androidx.compose.ui.Modifier
23
+ import androidx.compose.ui.platform.testTag
24
+ import androidx.compose.ui.unit.dp
25
+ import androidx.navigation.compose.NavHost
26
+ import androidx.navigation.compose.composable
27
+ import androidx.navigation.compose.currentBackStackEntryAsState
28
+ import androidx.navigation.compose.rememberNavController
29
+
30
+ @OptIn(ExperimentalMaterial3Api::class)
31
+ @Composable
32
+ fun Navigation(title: String, onStep: ((Int) -> Unit)? = null) {
33
+ var count by remember { mutableStateOf(0) }
34
+ val nav = rememberNavController()
35
+ val entry by nav.currentBackStackEntryAsState()
36
+ val route = entry?.destination?.route
37
+ MaterialTheme(colorScheme = lightColorScheme()) {
38
+ Scaffold(
39
+ modifier = Modifier.fillMaxSize(),
40
+ topBar = {
41
+ TopAppBar(
42
+ title = { Text(title, Modifier.testTag("navigation-title")) },
43
+ navigationIcon = {
44
+ Button(
45
+ onClick = { nav.popBackStack(); count += 1; onStep?.invoke(count) },
46
+ enabled = route == "detail",
47
+ modifier = Modifier.testTag("navigation-back"),
48
+ ) { Text("Return home") }
49
+ },
50
+ )
51
+ },
52
+ bottomBar = {
53
+ NavigationBar {
54
+ NavigationBarItem(
55
+ selected = route == "home",
56
+ onClick = {
57
+ if (route != "home") {
58
+ nav.popBackStack()
59
+ count += 1
60
+ onStep?.invoke(count)
61
+ }
62
+ },
63
+ icon = { Text("H") },
64
+ label = { Text("Home tab") },
65
+ modifier = Modifier.testTag("navigation-home-tab"),
66
+ )
67
+ NavigationBarItem(
68
+ selected = route == "detail",
69
+ onClick = {
70
+ if (route != "detail") {
71
+ nav.navigate("detail")
72
+ count += 1
73
+ onStep?.invoke(count)
74
+ }
75
+ },
76
+ icon = { Text("D") },
77
+ label = { Text("Detail tab") },
78
+ modifier = Modifier.testTag("navigation-open-detail"),
79
+ )
80
+ }
81
+ },
82
+ ) { padding ->
83
+ Column(Modifier.fillMaxSize().padding(padding).padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
84
+ Text("Count: $count", Modifier.testTag("navigation-count"))
85
+ Text("route=$route;step=$count", Modifier.testTag("navigation-state"))
86
+ Button(onClick = { count += 1000; onStep?.invoke(count) }, enabled = false, modifier = Modifier.testTag("navigation-disabled")) {
87
+ Text("Disabled navigation step")
88
+ }
89
+ NavHost(nav, startDestination = "home", modifier = Modifier.weight(1f)) {
90
+ composable("home") {
91
+ var taps by rememberSaveable { mutableStateOf(0) }
92
+ Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
93
+ Text("Saved home: $taps", Modifier.testTag("navigation-home-count"))
94
+ Button(onClick = { taps += 1; count += 1; onStep?.invoke(count) }, modifier = Modifier.testTag("navigation-increment")) {
95
+ Text("Increment home")
96
+ }
97
+ }
98
+ }
99
+ composable("detail") { Text("Detail screen", Modifier.testTag("navigation-detail")) }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,31 @@
1
+ # Imported Compose navigation
2
+
3
+ Run One in this fixture, then open its Android bundle in Peach on Pixel 8.
4
+ Build the native Android target on a remote builder. Import the same files in
5
+ Contrast with catalog versions materialized.
6
+
7
+ Increment the home counter, tap the detail navigation item, try the disabled
8
+ button, return with the top app bar button, then increment home again. The
9
+ home counter must survive the NavHost push/pop as one, then advance to two.
10
+ Each enabled action updates React and the imported title while Compose retains
11
+ the action count. Capture all six states and read the actual destination route.
12
+ This fixture claims settled navigation and saveable state, without system-back,
13
+ transition timing, activity restoration or full-frame pixel fidelity.
14
+
15
+ RAN One Android, Peach and Contrast: initial, increment, detail, disabled,
16
+ returned and second increment. Counts are 0, 1, 2, 2, 3 and 4; the saved home
17
+ count returns as one, then advances to two. React callback/title/footer values
18
+ match in all states. Contrast loads its initial preview document once, with no
19
+ browser errors, failed requests or failed responses.
20
+
21
+ [Hash-verified three-host proof](https://r2.sootsim.com/kotlin-evidence/import-navigation/8046f59ff6e63ae4c3e0eb21cf58852ab63b0900550f7ffc1f1d3b179618b437/proof.json) contains 71 objects and rejecting
22
+ controls for wrong saved state, disabled callbacks, runtime and duplicate loads.
23
+ Kotlin SHA256 `ab8c24c7540fc1916caa6581e8e63231c03e81c411837fb7ae971d1cc843a974`;
24
+ runtime `dd802e83b984a06811f4998c1a66c187dad7404b3f73077cf285f01a5accdff4`.
25
+ One native proof uses family canary `2.0.0-0.canary.1791736959809`, whose host
26
+ bounds intrinsic measurement and includes navigation-compose. The family pin
27
+ stays on the isolated helper branch until the dependency lane adopts it.
28
+ This receipt covers debug Android API37 and settled state. System back,
29
+ transition timing, activity restoration, text glyphs, shell and full-frame
30
+ pixel fidelity remain outside this fixture's grade. Images live in the proof,
31
+ with existing native captures converted losslessly to WebP without resizing.
@@ -0,0 +1,4 @@
1
+ import { Slot } from 'one'
2
+ export default function Layout() {
3
+ return <Slot />
4
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../ImportNavigation.native'
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-navigation-fixture",
3
+ "private": true,
4
+ "type": "module",
5
+ "targets": [
6
+ "native"
7
+ ],
8
+ "dependencies": {
9
+ "@react-navigation/core": "catalog:",
10
+ "@react-navigation/native": "catalog:",
11
+ "one": "catalog:",
12
+ "react": "catalog:",
13
+ "react-native": "catalog:",
14
+ "react-native-reanimated": "catalog:",
15
+ "react-native-screens": "catalog:",
16
+ "react-native-worklets": "catalog:"
17
+ },
18
+ "devDependencies": {
19
+ "@react-native-community/template": "catalog:",
20
+ "peachsim": "workspace:*",
21
+ "vite": "catalog:"
22
+ }
23
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "paths": {
4
+ "~/*": ["./*"]
5
+ },
6
+ "strict": true,
7
+ "allowArbitraryExtensions": true,
8
+ "rootDir": ".",
9
+ "module": "Preserve",
10
+ // allows react-native style imports without path extensions, for compat with platform-specific files
11
+ "moduleResolution": "Bundler",
12
+ "preserveSymlinks": true,
13
+ "skipLibCheck": true,
14
+ "jsx": "react-jsx",
15
+ "noImplicitAny": false,
16
+ "types": ["node", "react", "vite/client"],
17
+ "lib": ["dom", "esnext"]
18
+ },
19
+ "exclude": ["node_modules", "**/test", "**/dist", "**/types", "**/__tests__"]
20
+ }
@@ -0,0 +1,20 @@
1
+ import { one } from 'one/vite'
2
+ import { peachPlugin } from 'peachsim/vite'
3
+ export default {
4
+ root: import.meta.dirname,
5
+ plugins: [
6
+ one({
7
+ web: { defaultRenderMode: 'spa' },
8
+ native: {
9
+ bundler: 'vite',
10
+ app: {
11
+ name: 'KotlinNavigation',
12
+ scheme: 'kotlinnavigation',
13
+ android: { applicationId: 'dev.contrast.kotlinnavigation' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }
@@ -0,0 +1,29 @@
1
+ import { useState } from 'react'
2
+ import { Pressable, Text, View } from 'react-native'
3
+ import { Overlays } from './Overlays.kt'
4
+
5
+ type DecisionEvent = [string, number]
6
+
7
+ export default function Index() {
8
+ const [title, setTitle] = useState('Imported overlays')
9
+ const [events, setEvents] = useState<DecisionEvent[]>([])
10
+ return (
11
+ <View style={{ flex: 1, paddingTop: 48, backgroundColor: '#fff' }}>
12
+ <View style={{ flex: 1 }}>
13
+ <Overlays
14
+ title={title}
15
+ onDecision={(value, count) =>
16
+ setEvents((previous) => [...previous, [value, count]])
17
+ }
18
+ />
19
+ </View>
20
+ <View style={{ height: 200, padding: 24 }}>
21
+ <Text testID="overlays-props">{JSON.stringify({ title })}</Text>
22
+ <Text testID="overlays-events">{JSON.stringify(events)}</Text>
23
+ <Pressable testID="overlays-title" onPress={() => setTitle('Updated overlays')}>
24
+ <Text>Update title</Text>
25
+ </Pressable>
26
+ </View>
27
+ </View>
28
+ )
29
+ }
@@ -0,0 +1,7 @@
1
+ // generated by one typegen; edits will be replaced
2
+ import type { ReactElement } from 'react'
3
+
4
+ export declare function Overlays(props: {
5
+ title: string
6
+ onDecision?: ((value0: string, value1: number) => void) | null
7
+ }): ReactElement
@@ -0,0 +1,93 @@
1
+ package dev.contrast.kotlinoverlays
2
+
3
+ import androidx.compose.foundation.layout.Arrangement
4
+ import androidx.compose.foundation.layout.Box
5
+ import androidx.compose.foundation.layout.Column
6
+ import androidx.compose.foundation.layout.fillMaxSize
7
+ import androidx.compose.foundation.layout.padding
8
+ import androidx.compose.material3.AlertDialog
9
+ import androidx.compose.material3.Button
10
+ import androidx.compose.material3.DropdownMenu
11
+ import androidx.compose.material3.DropdownMenuItem
12
+ import androidx.compose.material3.MaterialTheme
13
+ import androidx.compose.material3.Surface
14
+ import androidx.compose.material3.Text
15
+ import androidx.compose.material3.TextButton
16
+ import androidx.compose.material3.lightColorScheme
17
+ import androidx.compose.runtime.Composable
18
+ import androidx.compose.runtime.getValue
19
+ import androidx.compose.runtime.mutableStateOf
20
+ import androidx.compose.runtime.remember
21
+ import androidx.compose.runtime.setValue
22
+ import androidx.compose.ui.Modifier
23
+ import androidx.compose.ui.platform.testTag
24
+ import androidx.compose.ui.semantics.contentDescription
25
+ import androidx.compose.ui.semantics.semantics
26
+ import androidx.compose.ui.unit.dp
27
+
28
+ @Composable
29
+ fun Overlays(title: String, onDecision: ((String, Int) -> Unit)? = null) {
30
+ var dialog by remember { mutableStateOf(false) }
31
+ var menu by remember { mutableStateOf(false) }
32
+ var result by remember { mutableStateOf("none") }
33
+ var decisions by remember { mutableStateOf(0) }
34
+ fun decide(value: String) {
35
+ result = value
36
+ decisions += 1
37
+ onDecision?.invoke(value, decisions)
38
+ }
39
+ val state = "$title|$result|$decisions|$dialog|$menu"
40
+ MaterialTheme(colorScheme = lightColorScheme()) {
41
+ Surface(Modifier.fillMaxSize()) {
42
+ Column(
43
+ Modifier.fillMaxSize().padding(24.dp),
44
+ verticalArrangement = Arrangement.spacedBy(16.dp),
45
+ ) {
46
+ Text(title, style = MaterialTheme.typography.headlineSmall)
47
+ Text(state, Modifier.testTag("overlays-state"))
48
+ Button(
49
+ onClick = { dialog = true },
50
+ modifier = Modifier.testTag("overlays-dialog").semantics { contentDescription = "overlays-dialog" },
51
+ ) { Text("Open dialog") }
52
+ Box {
53
+ Button(
54
+ onClick = { menu = true },
55
+ modifier = Modifier.testTag("overlays-menu").semantics { contentDescription = "overlays-menu" },
56
+ ) { Text("Open menu") }
57
+ DropdownMenu(
58
+ expanded = menu,
59
+ onDismissRequest = { menu = false; decide("menu-dismissed") },
60
+ ) {
61
+ Text(state, Modifier.padding(12.dp).testTag("overlays-menu-state"))
62
+ listOf("First", "Second", "Third").forEach { item ->
63
+ DropdownMenuItem(
64
+ text = { Text(item) },
65
+ onClick = { menu = false; decide(item) },
66
+ modifier = Modifier.testTag("overlays-$item").semantics { contentDescription = "overlays-$item" },
67
+ )
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ if (dialog) {
74
+ AlertDialog(
75
+ onDismissRequest = { dialog = false; decide("dialog-dismissed") },
76
+ title = { Text("Discard draft?") },
77
+ text = { Text(state, Modifier.testTag("overlays-dialog-state")) },
78
+ confirmButton = {
79
+ TextButton(
80
+ onClick = { dialog = false; decide("confirmed") },
81
+ modifier = Modifier.testTag("overlays-confirm").semantics { contentDescription = "overlays-confirm" },
82
+ ) { Text("Discard") }
83
+ },
84
+ dismissButton = {
85
+ TextButton(
86
+ onClick = { dialog = false; decide("kept") },
87
+ modifier = Modifier.testTag("overlays-keep").semantics { contentDescription = "overlays-keep" },
88
+ ) { Text("Keep") }
89
+ },
90
+ )
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,34 @@
1
+ # Imported Compose overlays
2
+
3
+ This fixture imports a public composable into React Native and reports dialog
4
+ and menu decisions to React. Compose retains its decision count when React
5
+ changes the title prop.
6
+
7
+ Run One here with `bunx one dev --port 8081`, then open that port with
8
+ `peach open 8081 --device pixel-8`. Generate Android with
9
+ `bunx one prebuild --platform android`; send Gradle builds through `bun remote`.
10
+
11
+ Open the dialog and choose Keep. Update the React title, reopen the dialog and
12
+ choose Discard. Open the menu and choose Second. Reopen the menu and dismiss it
13
+ with Android Back, then open the dialog and dismiss it with Back. The final
14
+ state is `Updated overlays|dialog-dismissed|5|false|false`; React receives
15
+ `[["kept",1],["confirmed",2],["Second",3],["menu-dismissed",4],["dialog-dismissed",5]]`.
16
+ Native popup windows hide the React footer, so callbacks are checked after close.
17
+
18
+ RAN 2026-10-11: Android debug and Kotlin/Wasm builds passed. Fresh One Android,
19
+ then Peach, then Contrast's native bundle producer matched all twelve states
20
+ and five callbacks. Peach and Contrast reported no preview errors; Contrast
21
+ compiled `Overlays.kt` and produced a complete bundle graph. These runs used
22
+ One `2.0.0-0.canary.1791724440037` and one complete shell, engine and tenant
23
+ runtime build. Runtime pairs must stay together: newly bundled CanvasKit
24
+ loaders reject older paired Wasm, and mixing ordinary CanvasKit versions also
25
+ prevented captures.
26
+
27
+ The imported host measures the root separately from popup layers, constrains
28
+ popups to the laid-out view bounds, and gives imported views a navigation
29
+ dispatcher that receives hardware Back. Dialog opening previously failed its
30
+ minimum constraints; menu opening rejected an infinite scroll height; Back
31
+ previously left the app instead of dismissing its menu. The retained probe
32
+ reproduces those failures and verifies the repaired behavior. This establishes
33
+ import and interaction behavior, without grading pixels or the signed-in
34
+ editor. Captures, hashes and receipts are retained in task `t-mv3ww8ql-120u0`.
@@ -0,0 +1,4 @@
1
+ import { Slot } from 'one'
2
+ export default function Layout() {
3
+ return <Slot />
4
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../ImportOverlays.native'
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-overlays-fixture",
3
+ "private": true,
4
+ "type": "module",
5
+ "targets": [
6
+ "native"
7
+ ],
8
+ "dependencies": {
9
+ "@react-navigation/core": "catalog:",
10
+ "@react-navigation/native": "catalog:",
11
+ "one": "catalog:",
12
+ "react": "catalog:",
13
+ "react-native": "catalog:",
14
+ "react-native-reanimated": "catalog:",
15
+ "react-native-screens": "catalog:",
16
+ "react-native-worklets": "catalog:"
17
+ },
18
+ "devDependencies": {
19
+ "@react-native-community/template": "catalog:",
20
+ "peachsim": "workspace:*",
21
+ "vite": "catalog:"
22
+ }
23
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "paths": {
4
+ "~/*": ["./*"]
5
+ },
6
+ "strict": true,
7
+ "allowArbitraryExtensions": true,
8
+ "rootDir": ".",
9
+ "module": "Preserve",
10
+ // allows react-native style imports without path extensions, for compat with platform-specific files
11
+ "moduleResolution": "Bundler",
12
+ "preserveSymlinks": true,
13
+ "skipLibCheck": true,
14
+ "jsx": "react-jsx",
15
+ "noImplicitAny": false,
16
+ "types": ["node", "react", "vite/client"],
17
+ "lib": ["dom", "esnext"]
18
+ },
19
+ "exclude": ["node_modules", "**/test", "**/dist", "**/types", "**/__tests__"]
20
+ }
@@ -0,0 +1,20 @@
1
+ import { one } from 'one/vite'
2
+ import { peachPlugin } from 'peachsim/vite'
3
+ export default {
4
+ root: import.meta.dirname,
5
+ plugins: [
6
+ one({
7
+ web: { defaultRenderMode: 'spa' },
8
+ native: {
9
+ bundler: 'vite',
10
+ app: {
11
+ name: 'KotlinOverlays',
12
+ scheme: 'kotlinoverlays',
13
+ android: { applicationId: 'dev.contrast.kotlinoverlays' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }