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
@@ -0,0 +1,80 @@
1
+ package dev.contrast.kotlinanimation
2
+
3
+ import androidx.compose.animation.AnimatedContent
4
+ import androidx.compose.animation.AnimatedVisibility
5
+ import androidx.compose.animation.animateColorAsState
6
+ import androidx.compose.animation.core.animateDp
7
+ import androidx.compose.animation.core.animateDpAsState
8
+ import androidx.compose.animation.core.updateTransition
9
+ import androidx.compose.foundation.background
10
+ import androidx.compose.foundation.layout.Arrangement
11
+ import androidx.compose.foundation.layout.Box
12
+ import androidx.compose.foundation.layout.Column
13
+ import androidx.compose.foundation.layout.fillMaxSize
14
+ import androidx.compose.foundation.layout.height
15
+ import androidx.compose.foundation.layout.padding
16
+ import androidx.compose.foundation.layout.width
17
+ import androidx.compose.material3.Button
18
+ import androidx.compose.material3.MaterialTheme
19
+ import androidx.compose.material3.Surface
20
+ import androidx.compose.material3.Text
21
+ import androidx.compose.material3.lightColorScheme
22
+ import androidx.compose.runtime.Composable
23
+ import androidx.compose.runtime.LaunchedEffect
24
+ import androidx.compose.runtime.getValue
25
+ import androidx.compose.runtime.mutableStateOf
26
+ import androidx.compose.runtime.remember
27
+ import androidx.compose.runtime.setValue
28
+ import androidx.compose.runtime.withFrameNanos
29
+ import androidx.compose.ui.Modifier
30
+ import androidx.compose.ui.graphics.Color
31
+ import androidx.compose.ui.graphics.toArgb
32
+ import androidx.compose.ui.layout.onGloballyPositioned
33
+ import androidx.compose.ui.platform.testTag
34
+ import androidx.compose.ui.unit.dp
35
+ import kotlin.math.roundToInt
36
+
37
+ @Composable
38
+ fun Animation(title: String, onStep: ((Int) -> Unit)? = null) {
39
+ var count by remember { mutableStateOf(0) }
40
+ var expanded by remember { mutableStateOf(false) }
41
+ var frameSeen by remember { mutableStateOf(false) }
42
+ var boxWidth by remember { mutableStateOf(0) }
43
+ var boxHeight by remember { mutableStateOf(0) }
44
+ val width by animateDpAsState(if (expanded) 160.dp else 80.dp, label = "width")
45
+ val color by animateColorAsState(if (expanded) Color(0xFF3F51B5) else Color(0xFFE91E63), label = "color")
46
+ val transition = updateTransition(expanded, label = "panel")
47
+ val height by transition.animateDp(label = "height") { if (it) 48.dp else 24.dp }
48
+ LaunchedEffect(expanded) {
49
+ frameSeen = false
50
+ withFrameNanos { frameSeen = true }
51
+ }
52
+ MaterialTheme(colorScheme = lightColorScheme()) {
53
+ Surface(Modifier.fillMaxSize()) {
54
+ Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
55
+ Text(title, Modifier.testTag("animation-title"))
56
+ Text("Count: $count", Modifier.testTag("animation-count"))
57
+ Text(
58
+ "expanded=${if (expanded) 1 else 0};width=${width.value.roundToInt()};height=${height.value.roundToInt()};color=${color.toArgb()};box=$boxWidth,$boxHeight;running=${if (transition.isRunning) 1 else 0};frame=${if (frameSeen) 1 else 0}",
59
+ Modifier.testTag("animation-state"),
60
+ )
61
+ Button(onClick = { expanded = !expanded; count += 1; onStep?.invoke(count) }, modifier = Modifier.testTag("animation-toggle")) {
62
+ Text(if (expanded) "Compact animation" else "Expand animation")
63
+ }
64
+ Button(onClick = { count += 1000; onStep?.invoke(count) }, enabled = false, modifier = Modifier.testTag("animation-disabled")) {
65
+ Text("Disabled animation step")
66
+ }
67
+ Box(Modifier.width(width).height(height).background(color).testTag("animation-box").onGloballyPositioned {
68
+ boxWidth = it.size.width
69
+ boxHeight = it.size.height
70
+ })
71
+ AnimatedVisibility(expanded) {
72
+ Text("Animated panel", Modifier.testTag("animation-panel"))
73
+ }
74
+ AnimatedContent(expanded, label = "content") { target ->
75
+ Text(if (target) "Expanded content" else "Compact content", Modifier.testTag(if (target) "animation-expanded-content" else "animation-compact-content"))
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,13 @@
1
+ import { useState } from 'react'
2
+ import { Text, View } from 'react-native'
3
+ import { Animation } from './Animation.kt'
4
+
5
+ export default function Index() {
6
+ const [step, setStep] = useState(0)
7
+ return (
8
+ <View style={{ flex: 1, backgroundColor: '#fff' }}>
9
+ <Animation title={`Animation step ${step}`} onStep={setStep} />
10
+ <Text testID="animation-react-step">React step: {step}</Text>
11
+ </View>
12
+ )
13
+ }
@@ -0,0 +1,24 @@
1
+ # Imported Compose animation fixture
2
+
3
+ A typed React import drives AnimatedVisibility, AnimatedContent, animateDpAsState,
4
+ animateColorAsState and updateTransition. Real toggles update the React callback
5
+ and title while retaining Compose state. A disabled action preserves both.
6
+
7
+ RAN: fresh One Android, then Peach, then an actual Contrast import passed six
8
+ states: initial0, expanded1, disabled1, compact2, again3 and reset4. Compact states
9
+ settle at width80/height24, ARGB -1499549 and measured box210x63; expanded states
10
+ at width160/height48, ARGB -12627531 and box420x126. Every state delivers a frame,
11
+ settles the transition and shows the matching panel and exclusive content.
12
+
13
+ [Proof and captures](https://r2.sootsim.com/kotlin-evidence/import-animation/badd8e7d78b5327501b5223bd3bc6903e5376b592b077de2073781bdc0faa5c0/proof.json)
14
+ bind source commit `67b7bd59e0c84377574dc4f3cde348c76008b7e2`, Kotlin SHA256
15
+ `5275bda78f9f82a6df9ce807c5d95f2296d8e14d5d015b23b1c8aa0eeccac381`,
16
+ and rebuilt runtime SHA256
17
+ `129e6fa055dd4fcabf03386e5b811af59590c96b92f1a7594bd3413ed25df2d7`.
18
+ All 64 objects passed hash readback. Negative controls reject a wrong animated
19
+ width and a callback from the disabled action.
20
+
21
+ Native proof uses debug Android API37 and One canary
22
+ `2.0.0-0.canary.1791729656331`. This fixture does not establish intermediate
23
+ frames, easing, motion duration, frame rate, text glyph or full-frame pixel
24
+ parity. Contrast shell chrome and production delivery are outside this receipt.
@@ -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 '../ImportAnimation.native'
@@ -0,0 +1,18 @@
1
+ // deno-lint-ignore-file
2
+ /* eslint-disable */
3
+ // biome-ignore: needed import
4
+ import type { OneRouter } from 'one'
5
+
6
+ declare module 'one' {
7
+ export namespace OneRouter {
8
+ export interface __routes<T extends string = string> extends Record<string, unknown> {
9
+ StaticRoutes:
10
+ | `/`
11
+ | `/_sitemap`
12
+ DynamicRoutes: never
13
+ DynamicRouteTemplate: never
14
+ IsTyped: true
15
+
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-animation-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: 'KotlinAnimation',
12
+ scheme: 'kotlinanimation',
13
+ android: { applicationId: 'dev.contrast.kotlinanimation' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }
@@ -0,0 +1,7 @@
1
+ // generated by one typegen; edits will be replaced
2
+ import type { ReactElement } from 'react'
3
+
4
+ export declare function Editor(props: {
5
+ title: string
6
+ onEdit?: ((value0: string, value1: boolean) => void) | null
7
+ }): ReactElement
@@ -0,0 +1,59 @@
1
+ package dev.contrast.kotlineditor
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.fillMaxWidth
7
+ import androidx.compose.foundation.layout.padding
8
+ import androidx.compose.foundation.text.KeyboardActions
9
+ import androidx.compose.foundation.text.KeyboardOptions
10
+ import androidx.compose.material3.MaterialTheme
11
+ import androidx.compose.material3.OutlinedTextField
12
+ import androidx.compose.material3.Surface
13
+ import androidx.compose.material3.Text
14
+ import androidx.compose.material3.lightColorScheme
15
+ import androidx.compose.runtime.Composable
16
+ import androidx.compose.runtime.getValue
17
+ import androidx.compose.runtime.mutableStateOf
18
+ import androidx.compose.runtime.remember
19
+ import androidx.compose.runtime.setValue
20
+ import androidx.compose.ui.Modifier
21
+ import androidx.compose.ui.focus.onFocusChanged
22
+ import androidx.compose.ui.platform.testTag
23
+ import androidx.compose.ui.semantics.contentDescription
24
+ import androidx.compose.ui.semantics.semantics
25
+ import androidx.compose.ui.text.input.ImeAction
26
+ import androidx.compose.ui.unit.dp
27
+
28
+ @Composable
29
+ fun Editor(title: String, onEdit: ((String, Boolean) -> Unit)? = null) {
30
+ var value by remember { mutableStateOf("") }
31
+ var focused by remember { mutableStateOf(false) }
32
+ var done by remember { mutableStateOf(0) }
33
+ MaterialTheme(colorScheme = lightColorScheme()) {
34
+ Surface(Modifier.fillMaxSize()) {
35
+ Column(
36
+ Modifier.fillMaxSize().padding(24.dp),
37
+ verticalArrangement = Arrangement.spacedBy(16.dp),
38
+ ) {
39
+ Text(title, style = MaterialTheme.typography.headlineSmall)
40
+ Text("$title|$value|$focused|$done", Modifier.testTag("editor-state"))
41
+ OutlinedTextField(
42
+ value = value,
43
+ onValueChange = { value = it; onEdit?.invoke(it, false) },
44
+ label = { Text("Name") },
45
+ singleLine = true,
46
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
47
+ keyboardActions = KeyboardActions(onDone = {
48
+ done += 1
49
+ onEdit?.invoke(value, true)
50
+ defaultKeyboardAction(ImeAction.Done)
51
+ }),
52
+ modifier = Modifier.fillMaxWidth().testTag("editor-input")
53
+ .semantics { contentDescription = "editor-input" }
54
+ .onFocusChanged { focused = it.isFocused },
55
+ )
56
+ }
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,23 @@
1
+ import { useState } from 'react'
2
+ import { Text, View } from 'react-native'
3
+ import { Editor } from './Editor.kt'
4
+
5
+ type EditEvent = [string, boolean]
6
+
7
+ export default function Index() {
8
+ const [events, setEvents] = useState<EditEvent[]>([])
9
+ return (
10
+ <View style={{ flex: 1, paddingTop: 48, backgroundColor: '#fff' }}>
11
+ <View style={{ flex: 1 }}>
12
+ <Editor
13
+ title="Imported editor"
14
+ onEdit={(value, done) => setEvents((previous) => [...previous, [value, done]])}
15
+ />
16
+ </View>
17
+ <View style={{ height: 160, padding: 24 }}>
18
+ <Text>Editor callbacks</Text>
19
+ <Text testID="editor-events">{JSON.stringify(events)}</Text>
20
+ </View>
21
+ </View>
22
+ )
23
+ }
@@ -0,0 +1,27 @@
1
+ # Imported Compose editor
2
+
3
+ This fixture imports a named public composable into a React Native app. It
4
+ extends the existing pure Kotlin Form fixture to cover text editing and an IME
5
+ Done action across the source-import bridge. Its field retains focus after Done,
6
+ hides the keyboard, and reports typed edit and completion callbacks to React.
7
+
8
+ Run One here with `bunx one dev --port 8081`, then open that port with
9
+ `peach open 8081 --device pixel-8`. Generate native Android with
10
+ `bunx one prebuild --platform android`; build `android/` with
11
+ `./gradlew assembleDebug` on the repository's remote builder.
12
+
13
+ Focus `editor-input`, type `H` then `i`, and press Done. The Compose state must
14
+ read `Imported editor|Hi|true|1`; `editor-events` must contain
15
+ `[["H",false],["Hi",false],["Hi",true]]`. A successful compile or a static
16
+ screen alone does not establish editing acceptance. Compare the same interaction
17
+ in One Android, Peach, and the Contrast native bundle producer.
18
+
19
+ RAN 2026-10-11: Android debug and Kotlin/Wasm builds passed, followed in order
20
+ by One Android, Peach, and Contrast's native bundle producer. All three produced
21
+ the same five states (initial, focused, H, Hi, Done) and callback tuples above.
22
+ Peach and Contrast reported no preview errors, exposed a Done return key while
23
+ editing, and hid the keyboard after Done with focus retained. Contrast compiled
24
+ `Editor.kt` through its Kotlin import route and produced a complete bundle graph.
25
+ These runs establish import and interaction behavior; they do not grade pixels
26
+ or the signed-in editor. Source and artifact hashes, captures and run receipts
27
+ are retained in task `t-mv3tuag4-17xu0`.
@@ -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 '../ImportEditor.native'
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-editor-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: 'KotlinEditor',
12
+ scheme: 'kotlineditor',
13
+ android: { applicationId: 'dev.contrast.kotlineditor' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }
@@ -0,0 +1,7 @@
1
+ // generated by one typegen; edits will be replaced
2
+ import type { ReactElement } from 'react'
3
+
4
+ export declare function Effects(props: {
5
+ title: string
6
+ onStep?: ((value0: number) => void) | null
7
+ }): ReactElement
@@ -0,0 +1,87 @@
1
+ package dev.contrast.kotlineffects
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.MaterialTheme
9
+ import androidx.compose.material3.Surface
10
+ import androidx.compose.material3.Text
11
+ import androidx.compose.material3.lightColorScheme
12
+ import androidx.compose.runtime.Composable
13
+ import androidx.compose.runtime.DisposableEffect
14
+ import androidx.compose.runtime.LaunchedEffect
15
+ import androidx.compose.runtime.getValue
16
+ import androidx.compose.runtime.mutableStateOf
17
+ import androidx.compose.runtime.remember
18
+ import androidx.compose.runtime.rememberCoroutineScope
19
+ import androidx.compose.runtime.setValue
20
+ import androidx.compose.ui.Modifier
21
+ import androidx.compose.ui.platform.testTag
22
+ import androidx.compose.ui.unit.dp
23
+ import kotlinx.coroutines.awaitCancellation
24
+ import kotlinx.coroutines.launch
25
+
26
+ private class EffectEvents {
27
+ var entered by mutableStateOf(0)
28
+ var launched by mutableStateOf(0)
29
+ var disposed by mutableStateOf(0)
30
+ var cancelled by mutableStateOf(0)
31
+ var scoped by mutableStateOf(0)
32
+ var scopeCancelled by mutableStateOf(0)
33
+ }
34
+
35
+ @Composable
36
+ private fun LifecycleChild(events: EffectEvents, onStart: () -> Unit) {
37
+ val scope = rememberCoroutineScope()
38
+ DisposableEffect(Unit) {
39
+ events.entered += 1
40
+ onDispose { events.disposed += 1 }
41
+ }
42
+ LaunchedEffect(Unit) {
43
+ events.launched += 1
44
+ try { awaitCancellation() } finally { events.cancelled += 1 }
45
+ }
46
+ Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
47
+ Text("Effect child", Modifier.testTag("effects-child"))
48
+ Button(
49
+ onClick = {
50
+ scope.launch {
51
+ events.scoped += 1
52
+ try { awaitCancellation() } finally { events.scopeCancelled += 1 }
53
+ }
54
+ onStart()
55
+ },
56
+ modifier = Modifier.testTag("effects-start"),
57
+ ) { Text("Start scoped job") }
58
+ }
59
+ }
60
+
61
+ @Composable
62
+ fun Effects(title: String, onStep: ((Int) -> Unit)? = null) {
63
+ var count by remember { mutableStateOf(0) }
64
+ var visible by remember { mutableStateOf(true) }
65
+ val events = remember { EffectEvents() }
66
+ MaterialTheme(colorScheme = lightColorScheme()) {
67
+ Surface(Modifier.fillMaxSize()) {
68
+ Column(Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
69
+ Text(title, Modifier.testTag("effects-title"))
70
+ Text("Count: $count", Modifier.testTag("effects-count"))
71
+ Text(
72
+ "visible=${if (visible) 1 else 0};entered=${events.entered};launched=${events.launched};disposed=${events.disposed};cancelled=${events.cancelled};scoped=${events.scoped};scopeCancelled=${events.scopeCancelled}",
73
+ Modifier.testTag("effects-state"),
74
+ )
75
+ Button(onClick = { visible = !visible; count += 1; onStep?.invoke(count) }, modifier = Modifier.testTag("effects-toggle")) {
76
+ Text(if (visible) "Hide child" else "Show child")
77
+ }
78
+ Button(onClick = { count += 1000; onStep?.invoke(count) }, enabled = false, modifier = Modifier.testTag("effects-disabled")) {
79
+ Text("Disabled effects step")
80
+ }
81
+ if (visible) {
82
+ LifecycleChild(events) { count += 1; onStep?.invoke(count) }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
@@ -0,0 +1,13 @@
1
+ import { useState } from 'react'
2
+ import { Text, View } from 'react-native'
3
+ import { Effects } from './Effects.kt'
4
+
5
+ export default function Index() {
6
+ const [step, setStep] = useState(0)
7
+ return (
8
+ <View style={{ flex: 1, backgroundColor: '#fff' }}>
9
+ <Effects title={`Effects step ${step}`} onStep={setStep} />
10
+ <Text testID="effects-react-step">React step: {step}</Text>
11
+ </View>
12
+ )
13
+ }
@@ -0,0 +1,19 @@
1
+ # Imported Compose effects
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
+ Start a scoped job, hide the child, try the disabled button, show the child,
8
+ start another scoped job and hide it again. Capture all seven states. Removing
9
+ the child must dispose its DisposableEffect and cancel both its LaunchedEffect
10
+ and remembered-scope job. Remounting starts each effect once more. Callback
11
+ updates to React and the imported title must preserve effect identity.
12
+ Compare exact lifecycle counters and actual child semantics across all hosts.
13
+ This fixture claims child composition lifecycle, without whole React-root
14
+ unmount, frame timing or full-frame pixel fidelity.
15
+
16
+ RAN 2026-10-11: all seven states match in One Android, Peach and Contrast.
17
+ Each removal increments disposal and both cancellation counters once; remount
18
+ starts fresh effects. Disabled input preserves state two.
19
+ [Receipts and captures](https://r2.sootsim.com/kotlin-evidence/import-effects/c151fca7d8e1a2067ee4517160db511aa6178ddfde1dc39b8ec130701e68ecb9/proof.json) include changed-output controls for missing scope cancellation and an unexpected disabled callback.
@@ -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 '../ImportEffects.native'
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "peach-kotlin-import-effects-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: 'KotlinEffects',
12
+ scheme: 'kotlineffects',
13
+ android: { applicationId: 'dev.contrast.kotlineffects' },
14
+ },
15
+ },
16
+ }),
17
+ peachPlugin(),
18
+ ],
19
+ server: { host: '0.0.0.0' },
20
+ }
@@ -0,0 +1,13 @@
1
+ import { useState } from 'react'
2
+ import { Text, View } from 'react-native'
3
+ import { Layout } from './Layout.kt'
4
+
5
+ export default function Index() {
6
+ const [step, setStep] = useState(0)
7
+ return (
8
+ <View style={{ flex: 1, backgroundColor: '#fff' }}>
9
+ <Layout title={`Layout step ${step}`} onStep={setStep} />
10
+ <Text testID="layout-react-step">React step: {step}</Text>
11
+ </View>
12
+ )
13
+ }
@@ -0,0 +1,7 @@
1
+ // generated by one typegen; edits will be replaced
2
+ import type { ReactElement } from 'react'
3
+
4
+ export declare function Layout(props: {
5
+ title: string
6
+ onStep?: ((value0: number) => void) | null
7
+ }): ReactElement