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
@@ -14,7 +14,7 @@ import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
14
14
  import { composeFramedScreenshot } from '../../src/screenshots/frame-compose'
15
15
  import { buildResolveRectEval, type SampleRect } from '../browser-evals'
16
16
  import { createCloudBridgeForParsed } from '../cloud-client'
17
- import { rnxExit } from '../run-rnx'
17
+ import { peachExit } from '../run-rnx'
18
18
  import {
19
19
  callInBridge,
20
20
  checkSimHealth,
@@ -64,7 +64,7 @@ examples:
64
64
  peach screenshot --area 0,200,393,400 --output hero.png
65
65
  peach screenshot --id loginButton --output button.png
66
66
  `)
67
- rnxExit(0)
67
+ peachExit(0)
68
68
  }
69
69
 
70
70
  const unknown = findUnknownFlags(args)
@@ -77,7 +77,7 @@ examples:
77
77
  )
78
78
  }
79
79
  console.error(' run `peach screenshot --help` for the list of supported flags')
80
- rnxExit(1)
80
+ peachExit(1)
81
81
  }
82
82
 
83
83
  const allowLoading = args.includes('--allow-loading')
@@ -90,7 +90,7 @@ examples:
90
90
  ) {
91
91
  console.error(' --with-frame only supports full-screen capture for now')
92
92
  console.error(' remove --area / --id / --text, or capture raw and compose later')
93
- rnxExit(1)
93
+ peachExit(1)
94
94
  }
95
95
 
96
96
  // share the standard bridge arg parser so --sim / --port / saved sims
@@ -126,7 +126,7 @@ examples:
126
126
  console.error(
127
127
  ` screenshot failed: ${error instanceof Error ? error.message : String(error)}`,
128
128
  )
129
- rnxExit(1)
129
+ peachExit(1)
130
130
  } finally {
131
131
  cloudBridge.close()
132
132
  }
@@ -145,7 +145,7 @@ examples:
145
145
  console.error(
146
146
  ` screenshot failed: ${err instanceof Error ? err.message : String(err)}`,
147
147
  )
148
- rnxExit(1)
148
+ peachExit(1)
149
149
  }
150
150
  return
151
151
  }
@@ -153,7 +153,7 @@ examples:
153
153
  if (withFrame) {
154
154
  console.error(' --with-frame requires a running peach bridge')
155
155
  console.error(' open the app in a live sim first, then rerun the command')
156
- rnxExit(1)
156
+ peachExit(1)
157
157
  }
158
158
 
159
159
  if (rect) {
@@ -161,7 +161,7 @@ examples:
161
161
  console.error(
162
162
  ' start one with `peach serve`, `peach desktop`, or your project dev server',
163
163
  )
164
- rnxExit(1)
164
+ peachExit(1)
165
165
  }
166
166
 
167
167
  await runPlaywrightScreenshot(args, opts)
@@ -25,7 +25,7 @@ import { chromium, type Frame, type Page } from 'playwright-core'
25
25
  import { launchReapedChromeScoped } from '../../../../scripts/lib/reap-browser'
26
26
  import { rnxPublicBrand } from '../../src/public-brand'
27
27
  import { resolveCliAuth, type CliAuth } from '../auth'
28
- import { rnxExit } from '../run-rnx'
28
+ import { peachExit } from '../run-rnx'
29
29
 
30
30
  const HELP = `
31
31
  peach screenshot appstore capture — headlessly capture + upload App Store slides
@@ -129,7 +129,7 @@ function resolveSessionAuth(): { token: string; origin: string } {
129
129
  '\n peach screenshot appstore capture needs a logged-in session.\n' +
130
130
  ' run `peach login` first (the captured slides upload to that account).\n\n',
131
131
  )
132
- rnxExit(1)
132
+ peachExit(1)
133
133
  }
134
134
 
135
135
  function isLoopback(hostname: string): boolean {
@@ -15,15 +15,12 @@ import {
15
15
  readDaemonLockfile,
16
16
  } from '../../src/home-paths'
17
17
  import { SootSimBridgeHost } from '../../src/host/bridge-host'
18
- import {
19
- findMonorepoRoot,
20
- resolveDevCheckoutRuntimeRoot,
21
- } from '../../src/runtime-assets'
22
- import { rnxExit } from '../run-rnx'
18
+ import { findMonorepoRoot, resolveDevCheckoutRuntimeRoot } from '../../src/runtime-assets'
23
19
  import {
24
20
  DEV_BUILD_REBUILD_COMMAND,
25
21
  findStaleDevBuildRoutes,
26
22
  } from '../dev-build-freshness'
23
+ import { peachExit } from '../run-rnx'
27
24
  import { resolveDefaultUploadOrigin } from './upload'
28
25
 
29
26
  interface ServeOptions {
@@ -52,7 +49,7 @@ examples:
52
49
  peach serve --port 7668 --quiet
53
50
  peach serve --host 0.0.0.0
54
51
  `)
55
- rnxExit(0)
52
+ peachExit(0)
56
53
  }
57
54
 
58
55
  const portArgIdx = args.indexOf('--port')
@@ -62,13 +59,13 @@ examples:
62
59
  : (opts.port ?? DEFAULT_SOOTSIM_BRIDGE_PORT)
63
60
  if (Number.isNaN(port)) {
64
61
  console.error(` invalid --port value: ${args[portArgIdx + 1]}`)
65
- rnxExit(1)
62
+ peachExit(1)
66
63
  }
67
64
  const hostArgIdx = args.indexOf('--host')
68
65
  const bindHost = hostArgIdx >= 0 ? args[hostArgIdx + 1] : '127.0.0.1'
69
66
  if (!bindHost || bindHost.startsWith('-')) {
70
67
  console.error(' --host requires a listener address')
71
- rnxExit(1)
68
+ peachExit(1)
72
69
  }
73
70
  const quiet = args.includes('--quiet') || args.includes('-q')
74
71
 
@@ -81,7 +78,7 @@ examples:
81
78
  ` a peach bridge is already running (pid ${existingLock.pid}, port ${existingLock.bridgePort})`,
82
79
  )
83
80
  console.error(` stop it with 'peach daemon stop' first`)
84
- rnxExit(1)
81
+ peachExit(1)
85
82
  }
86
83
 
87
84
  // in a dev checkout serve() serves the dev-stack build directly, so a
@@ -100,9 +97,9 @@ examples:
100
97
  )
101
98
  }
102
99
  console.error(
103
- ` rebuild with \`${DEV_BUILD_REBUILD_COMMAND}\` (or run bun dev so watch:sootsim keeps it current), then try again.`,
100
+ ` rebuild with \`${DEV_BUILD_REBUILD_COMMAND}\` (or run bun dev so watch:peach keeps it current), then try again.`,
104
101
  )
105
- rnxExit(1)
102
+ peachExit(1)
106
103
  }
107
104
  }
108
105
 
@@ -159,7 +156,7 @@ examples:
159
156
  try {
160
157
  await host.close()
161
158
  } catch {}
162
- rnxExit(0)
159
+ peachExit(0)
163
160
  }
164
161
  process.on('SIGINT', () => shutdown('SIGINT'))
165
162
  process.on('SIGTERM', () => shutdown('SIGTERM'))
@@ -6,6 +6,7 @@ import os from 'node:os'
6
6
  import path from 'node:path'
7
7
  import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
8
8
  import { getCliVersion } from '../../src/cli-version'
9
+ import { desktopHostPlatform } from '../../src/desktop-host-delivery'
9
10
  import {
10
11
  readActiveRuntime,
11
12
  readPrivacyPreferences,
@@ -147,8 +148,14 @@ export async function runSetup(
147
148
  serviceInstalled = true
148
149
  }
149
150
 
150
- if (simulatorDriver === 'electron' && !options.dryRun && !findDesktopCompanion()) {
151
- await runInstallDesktop(['--yes'])
151
+ if (
152
+ simulatorDriver !== 'playwright' &&
153
+ !options.dryRun &&
154
+ (simulatorDriver === 'desktop' || !findDesktopCompanion({ native: false }))
155
+ ) {
156
+ await runInstallDesktop(
157
+ simulatorDriver === 'desktop' ? ['--yes'] : ['--yes', '--electron'],
158
+ )
152
159
  }
153
160
 
154
161
  if (launchConnectRN) {
@@ -246,7 +253,7 @@ function readSimulatorDriverFlag(args: string[]): SimulatorDriverPreference | un
246
253
  if (desktop && browser) {
247
254
  throw new Error('--desktop and --browser cannot be used together')
248
255
  }
249
- if (desktop) return 'electron'
256
+ if (desktop) return desktopHostPlatform() === 'mac-arm64' ? 'desktop' : 'electron'
250
257
  if (browser) return 'playwright'
251
258
  return undefined
252
259
  }
@@ -314,17 +321,21 @@ async function decideSimulatorDriver(
314
321
  if (options.ci || options.yes || options.dryRun) return 'playwright'
315
322
  requireInteractive(options, '--desktop or --browser')
316
323
  const desktopDescription =
317
- process.platform === 'darwin'
318
- ? 'Desktop downloads a DMG and installs peach.app.'
319
- : process.platform === 'win32'
320
- ? 'Desktop downloads and runs the peach installer.'
321
- : 'Desktop downloads the matching peach AppImage.'
324
+ desktopHostPlatform() === 'mac-arm64'
325
+ ? 'Desktop installs the signed native Peach.app.'
326
+ : process.platform === 'darwin'
327
+ ? 'Desktop downloads a DMG and installs peach.app.'
328
+ : process.platform === 'win32'
329
+ ? 'Desktop downloads and runs the peach installer.'
330
+ : 'Desktop downloads the matching peach AppImage.'
322
331
  const desktopChoice =
323
- process.platform === 'darwin'
324
- ? 'Desktop app Installs peach.app from a DMG'
325
- : process.platform === 'win32'
326
- ? 'Desktop app Runs the peach installer'
327
- : 'Desktop app Installs the matching AppImage'
332
+ desktopHostPlatform() === 'mac-arm64'
333
+ ? 'Desktop app Installs the signed native host'
334
+ : process.platform === 'darwin'
335
+ ? 'Desktop app Installs peach.app from a DMG'
336
+ : process.platform === 'win32'
337
+ ? 'Desktop app Runs the peach installer'
338
+ : 'Desktop app Installs the matching AppImage'
328
339
  printPromptBlock('Simulator window', [
329
340
  'Browser opens immediately in an isolated Chrome window.',
330
341
  desktopDescription,
@@ -334,7 +345,11 @@ async function decideSimulatorDriver(
334
345
  'Browser (recommended) No additional download',
335
346
  desktopChoice,
336
347
  ])
337
- return choice === 0 ? 'playwright' : 'electron'
348
+ return choice === 0
349
+ ? 'playwright'
350
+ : desktopHostPlatform() === 'mac-arm64'
351
+ ? 'desktop'
352
+ : 'electron'
338
353
  }
339
354
 
340
355
  // diagnostics and crash reports are on unless turned off; setup says so once
@@ -1,4 +1,4 @@
1
- import { rnxExit } from '../run-rnx'
1
+ import { peachExit } from '../run-rnx'
2
2
  import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
3
3
 
4
4
  export type ShellBooleanModeAction = 'on' | 'off' | 'toggle'
@@ -24,7 +24,7 @@ export function parseShellBooleanModeAction(args: string[]): ShellBooleanModeAct
24
24
  const action = args[0]?.toLowerCase() ?? 'toggle'
25
25
  if (action !== 'on' && action !== 'off' && action !== 'toggle') {
26
26
  console.error(` unknown argument: "${action}" (expected on | off | toggle)`)
27
- rnxExit(1)
27
+ peachExit(1)
28
28
  }
29
29
  return action
30
30
  }
@@ -1,7 +1,7 @@
1
1
  // peach mode show-touches — toggle OS touch indicators (Show Single Touches / Show taps)
2
2
  // in the running peach sim.
3
3
 
4
- import { rnxExit } from '../run-rnx'
4
+ import { peachExit } from '../run-rnx'
5
5
  import { runShellBooleanMode, type ShellBooleanModeOptions } from './shell-boolean-mode'
6
6
 
7
7
  export async function runShowTouchesMode(args: string[], opts: ShellBooleanModeOptions) {
@@ -22,7 +22,7 @@ examples:
22
22
  peach mode show-touches on
23
23
  peach mode show-touches off
24
24
  `)
25
- rnxExit(0)
25
+ peachExit(0)
26
26
  }
27
27
 
28
28
  await runShellBooleanMode(args, opts, {
@@ -13,7 +13,7 @@ import { fileURLToPath } from 'url'
13
13
  import { getCliVersion } from '../../src/cli-version'
14
14
  import { rnxHomeDir } from '../../src/home-paths'
15
15
  import { rnxPublicBrand } from '../../src/public-brand'
16
- import { rnxExit } from '../run-rnx'
16
+ import { peachExit } from '../run-rnx'
17
17
 
18
18
  declare const __PEACH_BUNDLED_SKILLS__: Record<string, string>
19
19
 
@@ -277,7 +277,7 @@ function agentTarget(target: string): InstallTarget[] {
277
277
  }
278
278
  console.error(` unknown skill install target: ${target}`)
279
279
  console.error(' expected all, codex, or claude')
280
- rnxExit(1)
280
+ peachExit(1)
281
281
  }
282
282
 
283
283
  function parseSkillFrontmatter(
@@ -359,7 +359,7 @@ function matchSkills(skills: SkillInfo[], filters: string[]): SkillInfo[] {
359
359
  if (matched.length === 0) {
360
360
  console.error(` no skills matched: ${filters.join(', ')}`)
361
361
  console.error(' available: ' + skills.map((skill) => skill.name).join(', '))
362
- rnxExit(1)
362
+ peachExit(1)
363
363
  }
364
364
  return matched
365
365
  }
@@ -514,7 +514,7 @@ function parseInstallArgs(args: string[]): {
514
514
  const arg = args[index]
515
515
  if (arg === '--help' || arg === '-h') {
516
516
  printInstallHelp()
517
- rnxExit(0)
517
+ peachExit(0)
518
518
  }
519
519
  if (arg === '--force' || arg === '-f') {
520
520
  force = true
@@ -524,11 +524,11 @@ function parseInstallArgs(args: string[]): {
524
524
  const dir = args[index + 1]
525
525
  if (!dir || dir.startsWith('-')) {
526
526
  console.error(' --target requires a directory')
527
- rnxExit(1)
527
+ peachExit(1)
528
528
  }
529
529
  if (targets) {
530
530
  console.error(' pass only one install target')
531
- rnxExit(1)
531
+ peachExit(1)
532
532
  }
533
533
  targets = [{ label: 'target', dir }]
534
534
  index++
@@ -537,7 +537,7 @@ function parseInstallArgs(args: string[]): {
537
537
  if (arg.startsWith('-')) {
538
538
  console.error(` unknown option: ${arg}`)
539
539
  printInstallHelp()
540
- rnxExit(1)
540
+ peachExit(1)
541
541
  }
542
542
  if (!targets && AGENT_TARGET_IDS.has(arg)) {
543
543
  targets = agentTarget(arg)
@@ -553,7 +553,7 @@ async function runInstall(args: string[]) {
553
553
  const skills = listSkills()
554
554
  if (skills.length === 0) {
555
555
  console.error(' no skills found in peach package')
556
- rnxExit(1)
556
+ peachExit(1)
557
557
  }
558
558
 
559
559
  const parsed = parseInstallArgs(args)
@@ -566,7 +566,7 @@ async function runInstall(args: string[]) {
566
566
  fs.mkdirSync(target.dir, { recursive: true })
567
567
  if (!fs.statSync(target.dir).isDirectory()) {
568
568
  console.error(` target is not a directory: ${target.dir}`)
569
- rnxExit(1)
569
+ peachExit(1)
570
570
  }
571
571
  removeLegacyBundledSkills(target.dir)
572
572
  }
@@ -596,7 +596,7 @@ async function runInstall(args: string[]) {
596
596
  console.error(
597
597
  ` ${conflicts} conflict(s); rerun with --force only if replacing them is intended.\n`,
598
598
  )
599
- rnxExit(1)
599
+ peachExit(1)
600
600
  }
601
601
  console.log(' done. skills are installed and available to your agent.\n')
602
602
  }
@@ -630,5 +630,5 @@ export async function runSkill(args: string[]) {
630
630
 
631
631
  console.error(` unknown skill command: ${command}`)
632
632
  printSkillHelp()
633
- rnxExit(1)
633
+ peachExit(1)
634
634
  }
@@ -16,11 +16,15 @@ import {
16
16
  SWIFT_ICON_PATH,
17
17
  type SwiftHostDiscovery,
18
18
  } from '../../src/swiftDiscoveryContract'
19
- import { findXcodeProject } from '../../src/xcode-project'
19
+ import { findXcodeProject, readXcodeScheme } from '../../src/xcode-project'
20
20
  import { authHeaderValue, resolveCliAuth } from '../auth'
21
21
  import { PeachExit } from '../run-rnx'
22
22
  import { runOpenCommand, type OpenCommandResources } from './control'
23
- import { closeGuestResources, isLoopbackGuestRequest } from './guest-host'
23
+ import {
24
+ closeGuestResources,
25
+ isLoopbackGuestRequest,
26
+ waitForGuestCompletion,
27
+ } from './guest-host'
24
28
  import type { SwiftEntryModuleArgs } from '../../../sootsim-swift/src/entryModule'
25
29
 
26
30
  export async function runSwift(
@@ -38,6 +42,7 @@ export async function runSwift(
38
42
  let uploadSource = false
39
43
  let openPreview = true
40
44
  let target: string | undefined
45
+ let scheme: string | undefined
41
46
  const valueFlags = new Set([
42
47
  '--device',
43
48
  '--driver',
@@ -61,6 +66,9 @@ export async function runSwift(
61
66
  else if (arg === '--target') {
62
67
  target = input[++index]
63
68
  if (!target || target.startsWith('-')) throw new Error('--target requires a value')
69
+ } else if (arg === '--scheme') {
70
+ scheme = input[++index]
71
+ if (!scheme || scheme.startsWith('-')) throw new Error('--scheme requires a value')
64
72
  } else if (arg === '--host-port' || valueFlags.has(arg)) {
65
73
  const value = input[++index]
66
74
  if (!value || value.startsWith('-')) throw new Error(`${arg} requires a value`)
@@ -77,7 +85,7 @@ export async function runSwift(
77
85
  }
78
86
  if (!packagePath) {
79
87
  throw new Error(
80
- 'usage: peach swift <SwiftPM directory | Xcode project or workspace> [--target <app target>]',
88
+ 'usage: peach swift <SwiftPM directory | Xcode project or workspace> [--scheme <scheme> | --target <app target>]',
81
89
  )
82
90
  }
83
91
  // local by default: this machine's swift.org toolchain compiles against the
@@ -101,7 +109,7 @@ export async function runSwift(
101
109
  let module: SwiftModule | null = null
102
110
  if (!hosted) {
103
111
  try {
104
- module = await resolveSwiftModule()
112
+ module = await resolveSwiftModule({ required: true })
105
113
  } catch (error) {
106
114
  console.error(` ${error instanceof Error ? error.message : String(error)}`)
107
115
  return 1
@@ -126,9 +134,21 @@ export async function runSwift(
126
134
  'peach swift needs a directory containing Package.swift, or an Xcode project or workspace',
127
135
  )
128
136
  }
129
- if (target && !xcodeproj)
130
- throw new Error('--target selects an Xcode application target')
131
- if (xcodeproj) packagePath = host.openXcodeProject(xcodeproj, target, module?.root)
137
+ if ((target || scheme) && !xcodeproj)
138
+ throw new Error(
139
+ `${scheme ? '--scheme' : '--target'} selects an Xcode application target`,
140
+ )
141
+ if (target && scheme) throw new Error('--scheme names its own target; pass one of them')
142
+ // a scheme runs its launch action's target in that action's configuration
143
+ const run = scheme && xcodeproj ? readXcodeScheme(xcodeproj, scheme) : null
144
+ if (xcodeproj) {
145
+ packagePath = host.openXcodeProject(
146
+ xcodeproj,
147
+ run?.target ?? target,
148
+ module?.root,
149
+ run?.configuration,
150
+ )
151
+ }
132
152
  // collection preflights every input path before any source bytes are read.
133
153
  host.swiftPackageWatchFiles(packagePath, undefined)
134
154
  const packageName = path.basename(packagePath)
@@ -304,6 +324,7 @@ export async function runSwift(
304
324
  console.log(` Swift preview host: ${origin}`)
305
325
  await refresh()
306
326
  controller.signal.throwIfAborted()
327
+ if (!metadata || compileError) throw new Error(compileError)
307
328
  if (opts.device) openArgs.push('--device', opts.device)
308
329
  if (opts.driver) openArgs.push('--driver', opts.driver)
309
330
  if (opts.headless) openArgs.push('--headless')
@@ -317,10 +338,7 @@ export async function runSwift(
317
338
  ownerPid: process.pid,
318
339
  },
319
340
  )
320
- await new Promise<void>((resolve) => {
321
- if (controller.signal.aborted) resolve()
322
- else controller.signal.addEventListener('abort', () => resolve(), { once: true })
323
- })
341
+ code = await waitForGuestCompletion(resources, controller.signal, 'Swift preview')
324
342
  } catch (error) {
325
343
  if (!controller.signal.aborted) {
326
344
  console.error(
@@ -11,7 +11,7 @@ import {
11
11
  writePrivacyPreferences,
12
12
  } from '../../src/home-paths'
13
13
  import { PRIVACY_CONTENTS } from '../privacy'
14
- import { rnxExit } from '../run-rnx'
14
+ import { peachExit } from '../run-rnx'
15
15
 
16
16
  function printStatus(): void {
17
17
  const preferences = readPrivacyPreferences()
@@ -55,6 +55,6 @@ export async function runTelemetry(args: string[]): Promise<void> {
55
55
  default:
56
56
  console.error(` unknown telemetry action: ${sub}`)
57
57
  console.error(' usage: peach config telemetry [on|off|status]')
58
- rnxExit(1)
58
+ peachExit(1)
59
59
  }
60
60
  }
@@ -1183,6 +1183,11 @@ export async function runCloudTest(
1183
1183
  console.error(
1184
1184
  ` error: cloud test timed out after ${timeoutMs < 1000 ? `${timeoutMs}ms` : `${timeoutMs / 1000}s`}`,
1185
1185
  )
1186
+ if (!tunnelDependent) {
1187
+ console.error(
1188
+ ` the hosted job keeps running and billing; stop it with: peach test --cancel ${id}`,
1189
+ )
1190
+ }
1186
1191
  return 1
1187
1192
  }
1188
1193
 
@@ -10,7 +10,8 @@ import {
10
10
  isThreeModeSetting,
11
11
  THREE_MODE_SETTING_IDS,
12
12
  } from 'peach-engine/screenshots/tokens'
13
- import { rnxExit } from '../run-rnx'
13
+ import { isRecord } from '../../src/is-record'
14
+ import { peachExit } from '../run-rnx'
14
15
  import {
15
16
  callInBridgeWrite,
16
17
  createBridgeFromParsed,
@@ -18,7 +19,6 @@ import {
18
19
  type WsBridge,
19
20
  } from '../ws-bridge'
20
21
  import { runShellBooleanMode, type ShellBooleanModeOptions } from './shell-boolean-mode'
21
- import { isRecord } from '../../src/is-record'
22
22
 
23
23
  type ThreeModeConfig = Record<string, unknown>
24
24
  type ThreeModeState = Record<string, unknown> & {
@@ -113,7 +113,7 @@ examples:
113
113
  peach mode three measure ./cinematic.json --width 450 --height 900 --at 0,1200
114
114
  peach mode three off
115
115
  `)
116
- rnxExit(0)
116
+ peachExit(0)
117
117
  }
118
118
 
119
119
  const timelineAction = findTimelineAction(args)
@@ -16,7 +16,7 @@
16
16
  // see `peach what-happened` for the read side.
17
17
 
18
18
  import { writeFileSync } from 'fs'
19
- import { rnxExit } from '../run-rnx'
19
+ import { peachExit } from '../run-rnx'
20
20
  import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
21
21
 
22
22
  interface TimelineOptions {
@@ -55,7 +55,7 @@ export async function runTimeline(args: string[], opts: TimelineOptions) {
55
55
  const sub = parsed.positional[0]
56
56
  if (!sub || args.includes('--help') || args.includes('-h')) {
57
57
  printHelp()
58
- rnxExit(0)
58
+ peachExit(0)
59
59
  }
60
60
  const json = args.includes('--json')
61
61
  const bridge = createBridgeFromParsed(parsed)
@@ -98,7 +98,7 @@ export async function runTimeline(args: string[], opts: TimelineOptions) {
98
98
  const outPath = rest[0]
99
99
  if (!outPath) {
100
100
  console.error(' usage: peach timeline dump <file>')
101
- rnxExit(1)
101
+ peachExit(1)
102
102
  }
103
103
  const result = await callInBridge<{ events: unknown[] }>(
104
104
  bridge,
@@ -112,7 +112,7 @@ export async function runTimeline(args: string[], opts: TimelineOptions) {
112
112
  default: {
113
113
  console.error(` unknown subcommand: ${sub}`)
114
114
  printHelp()
115
- rnxExit(1)
115
+ peachExit(1)
116
116
  }
117
117
  }
118
118
  } finally {
@@ -15,7 +15,7 @@ import {
15
15
  fetchCliReleaseFile,
16
16
  refreshCliUpdateCache,
17
17
  } from '../cli-update'
18
- import { rnxExit } from '../run-rnx'
18
+ import { peachExit } from '../run-rnx'
19
19
  import { fetchRuntimeReleaseNotes, formatRuntimeReleaseNotes } from '../runtime-notes'
20
20
  import { IS_STANDALONE } from '../standalone'
21
21
  import { runRuntime } from './runtime'
@@ -43,7 +43,7 @@ export async function runUpgrade(
43
43
  const cliVersion = toIdx >= 0 ? args[toIdx + 1]?.replace(/^v/, '') : undefined
44
44
  if (toIdx >= 0 && !(cliVersion && VERSION_PATTERN.test(cliVersion))) {
45
45
  console.error(' peach upgrade: --to takes a CLI version such as 0.1.669')
46
- rnxExit(1)
46
+ peachExit(1)
47
47
  }
48
48
 
49
49
  console.log('peach upgrade\n')