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
@@ -19,7 +19,7 @@ import { maybeHint } from '../hints'
19
19
  import { shouldPrintInspectNotice } from '../inspect-notice-state'
20
20
  import { levenshtein } from '../levenshtein'
21
21
  import { TOP_LEVEL_RUNTIME_COMMANDS } from '../parse-args'
22
- import { rethrowIfExit, rnxExit } from '../run-rnx'
22
+ import { rethrowIfExit, peachExit } from '../run-rnx'
23
23
  import { collectRuntimeDiagnostics } from '../runtime-diagnostics'
24
24
  import { trackCliError } from '../telemetry'
25
25
  import {
@@ -869,7 +869,7 @@ async function performCloudKeys(
869
869
  console.error(
870
870
  ` ${actionLabel} failed: ${failed?.error ?? result.error ?? 'no text input had focus'}. focus an input first with peach do tap-id or peach do type-into.`,
871
871
  )
872
- rnxExit(1)
872
+ peachExit(1)
873
873
  }
874
874
 
875
875
  async function requireVisualKeyboard(bridge: WsBridge, actionLabel: string) {
@@ -879,12 +879,12 @@ async function requireVisualKeyboard(bridge: WsBridge, actionLabel: string) {
879
879
  console.error(
880
880
  ` ${actionLabel} requires a focused editable control. the iOS keyboard is visible, but no input owns focus.`,
881
881
  )
882
- rnxExit(1)
882
+ peachExit(1)
883
883
  }
884
884
  console.error(
885
885
  ` ${actionLabel} requires the iOS keyboard to be visible. focus an input first with peach do tap-id/tap-text or peach do type-into.`,
886
886
  )
887
- rnxExit(1)
887
+ peachExit(1)
888
888
  }
889
889
 
890
890
  async function runShellVisualCommand(
@@ -1132,7 +1132,8 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1132
1132
  ],
1133
1133
  })
1134
1134
  const positional = parsed.positional
1135
- const subcommand = positional[0]
1135
+ const subcommand =
1136
+ verbPrefix === 'debug' && positional[0] === 'eval' ? 'js' : positional[0]
1136
1137
  // used by inspectCommand() below to format usage/error strings with the
1137
1138
  // same prefix the user actually typed. null when they typed a top-level
1138
1139
  // command, and inspectCommand asks the registry for the group instead.
@@ -1155,6 +1156,17 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1155
1156
  const inspectUsage = (name: string, tail: string) =>
1156
1157
  ` usage: ${inspectCommand(name)}${tail ? ` ${tail}` : ''}`
1157
1158
 
1159
+ if (
1160
+ invocationPrefix === 'wait' &&
1161
+ !subcommand &&
1162
+ effectiveArgs.length > 0 &&
1163
+ !args.includes('--help') &&
1164
+ !args.includes('-h')
1165
+ ) {
1166
+ console.error(inspectUsage('selector', '<testid> [--max-ms <ms>]'))
1167
+ peachExit(1)
1168
+ }
1169
+
1158
1170
  if (!subcommand || args.includes('--help') || args.includes('-h')) {
1159
1171
  // all help output comes from the registry in packages/peach-skills
1160
1172
  // so `peach do --help`, `peach get --help`, the website docs, and
@@ -1175,7 +1187,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1175
1187
  const groupHelp = renderCliGroupHelp(invocationPrefix, docContext)
1176
1188
  if (groupHelp) {
1177
1189
  console.log(`${groupHelp}\n`)
1178
- rnxExit(0)
1190
+ peachExit(0)
1179
1191
  }
1180
1192
  }
1181
1193
 
@@ -1183,7 +1195,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1183
1195
  const shellHelp = renderCliCommandHelp('shell', docContext)
1184
1196
  if (shellHelp) {
1185
1197
  console.log(`${shellHelp}\n`)
1186
- rnxExit(0)
1198
+ peachExit(0)
1187
1199
  }
1188
1200
  }
1189
1201
 
@@ -1193,7 +1205,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1193
1205
  .filter((s): s is string => s != null)
1194
1206
  .join('\n\n')
1195
1207
  console.log(`${groupSections}\n`)
1196
- rnxExit(0)
1208
+ peachExit(0)
1197
1209
  }
1198
1210
 
1199
1211
  const wsPort = parsed.wsPort
@@ -1212,7 +1224,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1212
1224
  : effectiveArgs
1213
1225
  const { runDiagnose } = await import('./diagnose')
1214
1226
  const code = await runDiagnose(['recent', ...diagnosisArgs], opts)
1215
- if (code !== 0) rnxExit(code)
1227
+ if (code !== 0) peachExit(code)
1216
1228
  return
1217
1229
  }
1218
1230
 
@@ -1221,7 +1233,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1221
1233
  // runCamera returns a code instead of exiting, so `do scan` has to carry
1222
1234
  // it out. dropping it made a failed scan exit 0.
1223
1235
  const code = await runCamera(effectiveArgs, { port: opts.port })
1224
- if (code !== 0) rnxExit(code)
1236
+ if (code !== 0) peachExit(code)
1225
1237
  return
1226
1238
  }
1227
1239
 
@@ -1669,7 +1681,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1669
1681
  (args.includes('--verbose') || args.includes('-v')) && !args.includes('--json')
1670
1682
  if (invocationPrefix === 'do' && subcommand === 'shell') {
1671
1683
  console.error(' `peach do shell` was removed. use `peach shell ...` instead.')
1672
- rnxExit(1)
1684
+ peachExit(1)
1673
1685
  }
1674
1686
  if (writeCommands.has(subcommand)) {
1675
1687
  await checkSimHealth(bridge)
@@ -1880,7 +1892,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1880
1892
  console.error(
1881
1893
  ' samples an averaged color from the canvas. coords are logical peach units.',
1882
1894
  )
1883
- rnxExit(1)
1895
+ peachExit(1)
1884
1896
  }
1885
1897
  const result = await bridge.send({
1886
1898
  type: 'evaluate',
@@ -1913,7 +1925,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1913
1925
  if (!matcher) {
1914
1926
  console.error(inspectUsage('node', '<matcher>'))
1915
1927
  console.error(' resolves testID, id, then text — dumps full node info as JSON')
1916
- rnxExit(1)
1928
+ peachExit(1)
1917
1929
  }
1918
1930
  if (bridge.plane === 'cloud') {
1919
1931
  const byTestId = await inspectFind(bridge, { testId: matcher })
@@ -1987,11 +1999,11 @@ export async function runInspect(args: string[], opts: InspectOptions) {
1987
1999
  const payload = outcome.payload
1988
2000
  if (!payload || typeof payload.cx !== 'number') {
1989
2001
  await reportMissingTarget(bridge, 'tap', target)
1990
- rnxExit(1)
2002
+ peachExit(1)
1991
2003
  }
1992
2004
  if (!isTapSuccess(outcome.result)) {
1993
2005
  printTapFailure(`${target.mode} "${target.value}"`, outcome)
1994
- rnxExit(1)
2006
+ peachExit(1)
1995
2007
  }
1996
2008
  const candidate = buildTapCandidateFromResult(
1997
2009
  payload.cx,
@@ -2017,7 +2029,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2017
2029
  console.error(
2018
2030
  inspectUsage('tap', '<testid> | <x> <y> | --testid <id> | --text <t>'),
2019
2031
  )
2020
- rnxExit(1)
2032
+ peachExit(1)
2021
2033
  }
2022
2034
  const result = await tapCoordinates(bridge, x, y)
2023
2035
  const candidate = buildTapCandidateFromResult(x, y, result)
@@ -2047,7 +2059,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2047
2059
  !Number.isFinite(stepMs)
2048
2060
  ) {
2049
2061
  console.error(inspectUsage(subcommand, '<x1> <y1> <x2> <y2> [steps] [stepMs]'))
2050
- rnxExit(1)
2062
+ peachExit(1)
2051
2063
  }
2052
2064
  const result = await performSingleStep(bridge, {
2053
2065
  type: 'drag',
@@ -2108,7 +2120,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2108
2120
  "<x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]",
2109
2121
  ),
2110
2122
  )
2111
- rnxExit(1)
2123
+ peachExit(1)
2112
2124
  }
2113
2125
  const result = await performSingleStep(bridge, {
2114
2126
  type: 'pinch',
@@ -2145,7 +2157,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2145
2157
  const query = positional[1]
2146
2158
  if (!query) {
2147
2159
  console.error(inspectUsage('tap-text', '<text>'))
2148
- rnxExit(1)
2160
+ peachExit(1)
2149
2161
  }
2150
2162
 
2151
2163
  const findFlagValue = (name: string): string | null => {
@@ -2158,7 +2170,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2158
2170
  const nthIndex = nthArg !== null ? Number(nthArg) : null
2159
2171
  if (nthIndex !== null && !Number.isFinite(nthIndex)) {
2160
2172
  console.error(` --nth/--index requires an integer, got: ${nthArg}`)
2161
- rnxExit(1)
2173
+ peachExit(1)
2162
2174
  }
2163
2175
  const within = findFlagValue('--within')
2164
2176
  const roleFlag = findFlagValue('--role')
@@ -2176,7 +2188,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2176
2188
  ] as const) {
2177
2189
  if (val !== null && !Number.isFinite(Number(val))) {
2178
2190
  console.error(` ${flag} requires a number, got: ${val}`)
2179
- rnxExit(1)
2191
+ peachExit(1)
2180
2192
  }
2181
2193
  }
2182
2194
  const nearIdx = args.indexOf('--near')
@@ -2186,7 +2198,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2186
2198
  const ny = Number(args[nearIdx + 2])
2187
2199
  if (!Number.isFinite(nx) || !Number.isFinite(ny)) {
2188
2200
  console.error(' --near requires two numbers: --near <x> <y>')
2189
- rnxExit(1)
2201
+ peachExit(1)
2190
2202
  }
2191
2203
  near = { x: nx, y: ny }
2192
2204
  }
@@ -2211,7 +2223,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2211
2223
 
2212
2224
  if (payload?.error === 'bridge-not-ready') {
2213
2225
  console.error(' peach test bridge not ready')
2214
- rnxExit(1)
2226
+ peachExit(1)
2215
2227
  }
2216
2228
 
2217
2229
  if (payload?.ambiguous) {
@@ -2260,23 +2272,23 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2260
2272
  console.error(
2261
2273
  ' --first keep the old pick-first-silently behavior',
2262
2274
  )
2263
- rnxExit(2)
2275
+ peachExit(2)
2264
2276
  }
2265
2277
 
2266
2278
  if (payload?.nthOutOfRange) {
2267
2279
  console.error(
2268
2280
  ` not found: nth ${payload.nth} of ${payload.total} match${payload.total === 1 ? '' : 'es'} for "${query}"`,
2269
2281
  )
2270
- rnxExit(1)
2282
+ peachExit(1)
2271
2283
  }
2272
2284
 
2273
2285
  if (!payload || typeof payload.cx !== 'number') {
2274
2286
  console.error(` not found: ${query}`)
2275
- rnxExit(1)
2287
+ peachExit(1)
2276
2288
  }
2277
2289
  if (!isTapSuccess(outcome.result)) {
2278
2290
  printTapFailure(`text "${query}"`, outcome)
2279
- rnxExit(1)
2291
+ peachExit(1)
2280
2292
  }
2281
2293
  const candidate = buildTapCandidateFromNode(
2282
2294
  query,
@@ -2336,7 +2348,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2336
2348
  const query = positional[1]
2337
2349
  if (!query) {
2338
2350
  console.error(inspectUsage('tap-best', '<query>'))
2339
- rnxExit(1)
2351
+ peachExit(1)
2340
2352
  }
2341
2353
  const outcome = await tapBest(bridge, query, { agent: isAgentEnv() })
2342
2354
  const payload = outcome.payload as
@@ -2359,22 +2371,22 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2359
2371
  console.error(
2360
2372
  ` tap-best: no testID or visible text matched "${query}". try \`peach find --interactive-targets\` to list candidates.`,
2361
2373
  )
2362
- rnxExit(1)
2374
+ peachExit(1)
2363
2375
  }
2364
2376
  if ('error' in payload) {
2365
2377
  console.error(` ${payload.error}`)
2366
- rnxExit(1)
2378
+ peachExit(1)
2367
2379
  }
2368
2380
  if (payload.strategy === 'none') {
2369
2381
  console.error(
2370
2382
  ` tap-best: no testID or visible text matched "${query}". try \`peach find --interactive-targets\` to list candidates.`,
2371
2383
  )
2372
- rnxExit(1)
2384
+ peachExit(1)
2373
2385
  }
2374
2386
  const node = payload.node
2375
2387
  if (!isTapSuccess(outcome.result)) {
2376
2388
  printTapFailure(`best "${query}"`, outcome)
2377
- rnxExit(1)
2389
+ peachExit(1)
2378
2390
  }
2379
2391
  const candidate = buildTapCandidateFromNode(
2380
2392
  query,
@@ -2415,18 +2427,18 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2415
2427
  const text = positional.slice(2).join(' ')
2416
2428
  if (!targetId || !text) {
2417
2429
  console.error(inspectUsage('type-into', '<id> <text>'))
2418
- rnxExit(1)
2430
+ peachExit(1)
2419
2431
  }
2420
2432
  if (bridge.plane === 'cloud') {
2421
2433
  const outcome = await tapById(bridge, targetId, { agent: isAgentEnv() })
2422
2434
  if (!outcome.payload || typeof outcome.payload.cx !== 'number') {
2423
2435
  console.error(` not found: ${targetId}`)
2424
2436
  await printSimilarTestIds(bridge, targetId)
2425
- rnxExit(1)
2437
+ peachExit(1)
2426
2438
  }
2427
2439
  if (!isTapSuccess(outcome.result)) {
2428
2440
  printTapFailure(`id "${targetId}"`, outcome)
2429
- rnxExit(1)
2441
+ peachExit(1)
2430
2442
  }
2431
2443
  const nodeId: unknown = outcome.payload.target?.nodeId
2432
2444
  if (
@@ -2435,7 +2447,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2435
2447
  nodeId === 0
2436
2448
  ) {
2437
2449
  console.error(' type-into requires a resolved text input node identity')
2438
- rnxExit(1)
2450
+ peachExit(1)
2439
2451
  }
2440
2452
  const typed = await performCloudKeys(
2441
2453
  bridge,
@@ -2449,7 +2461,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2449
2461
  typeof Reflect.get(receipt, 'secureTextEntry') !== 'boolean'
2450
2462
  ) {
2451
2463
  console.error(' type-into did not return its matched input secure state')
2452
- rnxExit(1)
2464
+ peachExit(1)
2453
2465
  }
2454
2466
  const recordedText =
2455
2467
  Reflect.get(receipt, 'secureTextEntry') === true
@@ -2486,7 +2498,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2486
2498
  })
2487
2499
  if (!tiPayload || typeof tiPayload.cx !== 'number') {
2488
2500
  console.error(` not found: ${targetId}`)
2489
- rnxExit(1)
2501
+ peachExit(1)
2490
2502
  }
2491
2503
  if (!tiPayload.isTextInput) {
2492
2504
  console.error(` warning: ${targetId} is not a text input (isTextInput: false)`)
@@ -2510,7 +2522,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2510
2522
  })
2511
2523
  if (!keyboardState.visible) {
2512
2524
  console.error(` keyboard did not open after tapping ${targetId}`)
2513
- rnxExit(1)
2525
+ peachExit(1)
2514
2526
  }
2515
2527
  // step 2.5: confirm the tap actually focused the requested input.
2516
2528
  // the keyboard being visible is necessary but not sufficient — a
@@ -2530,7 +2542,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2530
2542
  focusCheck.testID ?? focusCheck.id ?? null,
2531
2543
  )}. did the tap land on an outer Pressable wrapper?`,
2532
2544
  )
2533
- rnxExit(1)
2545
+ peachExit(1)
2534
2546
  }
2535
2547
  }
2536
2548
  // step 3: clear existing text then type through the visible keyboard
@@ -2586,7 +2598,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2586
2598
  const text = positional.slice(1).join(' ')
2587
2599
  if (!text) {
2588
2600
  console.error(inspectUsage('type', '<text>'))
2589
- rnxExit(1)
2601
+ peachExit(1)
2590
2602
  }
2591
2603
  if (bridge.plane === 'cloud') {
2592
2604
  await performCloudKeys(bridge, [{ type: 'type', text }], 'type')
@@ -2620,7 +2632,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2620
2632
  const name = positional[1]
2621
2633
  if (!name) {
2622
2634
  console.error(inspectUsage('key', '<name>'))
2623
- rnxExit(1)
2635
+ peachExit(1)
2624
2636
  }
2625
2637
  if (bridge.plane === 'cloud') {
2626
2638
  await performCloudKeys(bridge, [{ type: 'key', key: name }], 'key')
@@ -2637,7 +2649,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2637
2649
  const keys = positional.slice(1)
2638
2650
  if (keys.length === 0) {
2639
2651
  console.error(inspectUsage('key-sequence', '<key> [<key> ...]'))
2640
- rnxExit(1)
2652
+ peachExit(1)
2641
2653
  }
2642
2654
  if (bridge.plane === 'cloud') {
2643
2655
  await performCloudKeys(
@@ -2664,7 +2676,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2664
2676
  const codes = positional.slice(1)
2665
2677
  if (codes.length === 0) {
2666
2678
  console.error(inspectUsage('keycode', '<code> [<code> ...]'))
2667
- rnxExit(1)
2679
+ peachExit(1)
2668
2680
  }
2669
2681
  const mapped = codes.map((code) => ({ code, key: keyCodeToVisualKey(code) }))
2670
2682
  const unsupported = mapped.filter((entry) => !entry.key)
@@ -2676,7 +2688,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2676
2688
  console.error(
2677
2689
  ` unsupported keycode(s): ${unsupported.map((entry) => entry.code).join(', ')}`,
2678
2690
  )
2679
- rnxExit(1)
2691
+ peachExit(1)
2680
2692
  }
2681
2693
  await requireVisualKeyboard(bridge, 'keycode')
2682
2694
  for (const entry of keys) {
@@ -2695,7 +2707,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2695
2707
  const ch = positional[1]
2696
2708
  if (!ch) {
2697
2709
  console.error(inspectUsage('dispatch', '<char>'))
2698
- rnxExit(1)
2710
+ peachExit(1)
2699
2711
  }
2700
2712
  await bridge.send({ type: 'keyboard', action: 'dispatchKey', text: ch })
2701
2713
  await recordInspectAction(
@@ -2726,12 +2738,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2726
2738
  const resolved = await resolveTargetCoords(bridge, target)
2727
2739
  if (!resolved) {
2728
2740
  await reportMissingTarget(bridge, 'double-tap', target)
2729
- rnxExit(1)
2741
+ peachExit(1)
2730
2742
  }
2731
2743
  const refusal = offscreenTargetRefusal(bridge.plane, resolved)
2732
2744
  if (refusal) {
2733
2745
  console.error(` double-tap: ${refusal}`)
2734
- rnxExit(1)
2746
+ peachExit(1)
2735
2747
  }
2736
2748
  x = resolved.x
2737
2749
  y = resolved.y
@@ -2741,7 +2753,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2741
2753
  console.error(
2742
2754
  inspectUsage('double-tap', '<testid> | <x> <y> [gapMs] | --testid <id>'),
2743
2755
  )
2744
- rnxExit(1)
2756
+ peachExit(1)
2745
2757
  }
2746
2758
  const waitMs = Math.max(0, Math.round(gapMs))
2747
2759
  const single = await performSingleStep(bridge, {
@@ -2771,12 +2783,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2771
2783
  const resolved = await resolveTargetCoords(bridge, target)
2772
2784
  if (!resolved) {
2773
2785
  await reportMissingTarget(bridge, 'long-press', target)
2774
- rnxExit(1)
2786
+ peachExit(1)
2775
2787
  }
2776
2788
  const refusal = offscreenTargetRefusal(bridge.plane, resolved)
2777
2789
  if (refusal) {
2778
2790
  console.error(` long-press: ${refusal}`)
2779
- rnxExit(1)
2791
+ peachExit(1)
2780
2792
  }
2781
2793
  x = resolved.x
2782
2794
  y = resolved.y
@@ -2799,7 +2811,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2799
2811
  '<testid> [durationMs] | <x> <y> [durationMs] | --testid <id>',
2800
2812
  ),
2801
2813
  )
2802
- rnxExit(1)
2814
+ peachExit(1)
2803
2815
  }
2804
2816
  const roundedDurationMs = Math.max(0, Math.round(durationMs))
2805
2817
  const result = await bridge.send({
@@ -2826,7 +2838,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2826
2838
  console.error(
2827
2839
  ' error: a touch lives within one batch; chain its phases, e.g. peach do touch down 200 720 --then touch move 200 400 --then touch up 200 400',
2828
2840
  )
2829
- rnxExit(1)
2841
+ peachExit(1)
2830
2842
  }
2831
2843
 
2832
2844
  case 'gesture': {
@@ -2845,12 +2857,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2845
2857
  if (!preset || !Number.isFinite(durationMs)) {
2846
2858
  console.error(inspectUsage('gesture', '<preset> [durationMs]'))
2847
2859
  console.error(` presets: ${GESTURE_PRESETS.join(', ')}`)
2848
- rnxExit(1)
2860
+ peachExit(1)
2849
2861
  }
2850
2862
  if (!(GESTURE_PRESETS as readonly string[]).includes(preset)) {
2851
2863
  console.error(` unknown gesture preset: ${preset}`)
2852
2864
  console.error(` presets: ${GESTURE_PRESETS.join(', ')}`)
2853
- rnxExit(1)
2865
+ peachExit(1)
2854
2866
  }
2855
2867
  const frame = await bridge.send({
2856
2868
  type: 'evaluate',
@@ -2957,7 +2969,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2957
2969
  if (args.some((arg) => arg === '--node-id' || arg.startsWith('--node-id='))) {
2958
2970
  console.error(' scroll takes a testID; --node-id is not supported')
2959
2971
  console.error(inspectUsage('scroll', '<id> <x> <y> | --testid <id> <x> <y>'))
2960
- rnxExit(1)
2972
+ peachExit(1)
2961
2973
  }
2962
2974
  const target = readTargetFlag(args)
2963
2975
  const id = target?.mode === 'testid' ? target.value : positional[1]
@@ -2966,7 +2978,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
2966
2978
  const y = Number(positional[offset + 1])
2967
2979
  if (!id || !Number.isFinite(x) || !Number.isFinite(y)) {
2968
2980
  console.error(inspectUsage('scroll', '<id> <x> <y> | --testid <id> <x> <y>'))
2969
- rnxExit(1)
2981
+ peachExit(1)
2970
2982
  }
2971
2983
  const resolved = await resolveTargetCoords(bridge, { mode: 'testid', value: id })
2972
2984
  const result = await performSingleStep(bridge, {
@@ -3125,7 +3137,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3125
3137
  const id = positional[2]
3126
3138
  if (!id) {
3127
3139
  console.error(` usage: ${inspectCommand('state')} node <id>`)
3128
- rnxExit(1)
3140
+ peachExit(1)
3129
3141
  }
3130
3142
  result =
3131
3143
  (await callTestBridge(bridge, 'findByTestId', id)) ||
@@ -3136,7 +3148,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3136
3148
  const id = positional[2]
3137
3149
  if (!id) {
3138
3150
  console.error(` usage: ${inspectCommand('state')} scroll <id>`)
3139
- rnxExit(1)
3151
+ peachExit(1)
3140
3152
  }
3141
3153
  result = await callTestBridge(bridge, 'getScrollState', id)
3142
3154
  break
@@ -3146,7 +3158,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3146
3158
  const y = Number(positional[3])
3147
3159
  if (!Number.isFinite(x) || !Number.isFinite(y)) {
3148
3160
  console.error(` usage: ${inspectCommand('state')} scroll-hit <x> <y>`)
3149
- rnxExit(1)
3161
+ peachExit(1)
3150
3162
  }
3151
3163
  result = await callTestBridge(bridge, 'getScrollStateAt', x, y)
3152
3164
  break
@@ -3156,7 +3168,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3156
3168
  const y = Number(positional[3])
3157
3169
  if (!Number.isFinite(x) || !Number.isFinite(y)) {
3158
3170
  console.error(` usage: ${inspectCommand('state')} hit <x> <y>`)
3159
- rnxExit(1)
3171
+ peachExit(1)
3160
3172
  }
3161
3173
  result = await callTestBridge(bridge, 'debugHitAt', x, y)
3162
3174
  break
@@ -3166,7 +3178,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3166
3178
  const y = Number(positional[3])
3167
3179
  if (!Number.isFinite(x) || !Number.isFinite(y)) {
3168
3180
  console.error(` usage: ${inspectCommand('state')} gesture <x> <y>`)
3169
- rnxExit(1)
3181
+ peachExit(1)
3170
3182
  }
3171
3183
  result = await callTestBridge(bridge, 'debugGestureAt', x, y)
3172
3184
  break
@@ -3211,7 +3223,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3211
3223
  break
3212
3224
  default:
3213
3225
  console.error(` unknown state subcommand: ${stateCmd}`)
3214
- rnxExit(1)
3226
+ peachExit(1)
3215
3227
  }
3216
3228
  console.log(JSON.stringify(result, null, 2))
3217
3229
  break
@@ -3267,7 +3279,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3267
3279
  : '<home|switcher> [settleMs]',
3268
3280
  ),
3269
3281
  )
3270
- rnxExit(1)
3282
+ peachExit(1)
3271
3283
  }
3272
3284
 
3273
3285
  let ok = false
@@ -3280,7 +3292,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3280
3292
  console.error(
3281
3293
  inspectUsage('shell', 'launch <appId> [settleMs] [--clear-state]'),
3282
3294
  )
3283
- rnxExit(1)
3295
+ peachExit(1)
3284
3296
  }
3285
3297
  if (clearState) {
3286
3298
  await bridge.send({
@@ -3345,7 +3357,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3345
3357
  const appId = positional[2]
3346
3358
  if (!appId) {
3347
3359
  console.error(inspectUsage('shell', 'open-card <appId> [settleMs]'))
3348
- rnxExit(1)
3360
+ peachExit(1)
3349
3361
  }
3350
3362
  ok = !!(await callShellCommandWhenReady(
3351
3363
  bridge,
@@ -3378,7 +3390,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3378
3390
  const mode = positional[2]
3379
3391
  if (!mode || !['light', 'dark', 'auto', 'toggle'].includes(mode)) {
3380
3392
  console.error(inspectUsage('shell', 'appearance <light|dark|auto|toggle>'))
3381
- rnxExit(1)
3393
+ peachExit(1)
3382
3394
  }
3383
3395
  const result = await runShellVisualCommand(bridge, 'appearance', mode)
3384
3396
  ok = !!result?.ok
@@ -3396,7 +3408,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3396
3408
  state = { [shellCmd]: result }
3397
3409
  } else {
3398
3410
  console.error(` unknown shell subcommand: ${shellCmd}`)
3399
- rnxExit(1)
3411
+ peachExit(1)
3400
3412
  }
3401
3413
  console.log(JSON.stringify({ ok, settled, state }, null, 2))
3402
3414
  break
@@ -3422,7 +3434,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3422
3434
  } else {
3423
3435
  console.error(` ${message}`)
3424
3436
  }
3425
- rnxExit(1)
3437
+ peachExit(1)
3426
3438
  }
3427
3439
  // reload waits for the guest app's `sootsim:externalAppReady` signal
3428
3440
  // (not just a live ws connection) within RELOAD_READY_TIMEOUT_MS. fatal
@@ -3559,7 +3571,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3559
3571
  }
3560
3572
  }
3561
3573
  if (!readyResult?.ready) {
3562
- rnxExit(1)
3574
+ peachExit(1)
3563
3575
  }
3564
3576
  break
3565
3577
  }
@@ -3582,7 +3594,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3582
3594
  ' storage clear failed: external app reload bridge is unavailable',
3583
3595
  )
3584
3596
  }
3585
- rnxExit(1)
3597
+ peachExit(1)
3586
3598
  }
3587
3599
 
3588
3600
  const readyResult = await pollForReloadReady(bridge, {
@@ -3591,7 +3603,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3591
3603
 
3592
3604
  if (wantsJson(effectiveArgs)) {
3593
3605
  printJson({ cleared: true, ready: readyResult.ready, reload: readyResult })
3594
- if (!readyResult.ready) rnxExit(1)
3606
+ if (!readyResult.ready) peachExit(1)
3595
3607
  break
3596
3608
  }
3597
3609
 
@@ -3635,7 +3647,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3635
3647
  // ignore errors checking for errors
3636
3648
  }
3637
3649
  if (!readyResult.ready) {
3638
- rnxExit(1)
3650
+ peachExit(1)
3639
3651
  }
3640
3652
  break
3641
3653
  }
@@ -3659,7 +3671,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3659
3671
  ` ${inspectCommand('js')} SootSim.bridges.keyboard.type("hello")`,
3660
3672
  )
3661
3673
  console.error(` ${inspectCommand('js')} SootSim.state.root.children.length`)
3662
- rnxExit(1)
3674
+ peachExit(1)
3663
3675
  }
3664
3676
  // --tenant: evaluate inside the TENANT worker's global scope (guest
3665
3677
  // bundle, metro module table, compat stubs) via the test bridge's
@@ -3784,7 +3796,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3784
3796
  case 'perf': {
3785
3797
  if (invocationPrefix === 'debug' && !opts.internalPerfCommand) {
3786
3798
  console.error(' `peach debug perf` was removed. use `peach perf shell ...`.')
3787
- rnxExit(1)
3799
+ peachExit(1)
3788
3800
  }
3789
3801
  const perfCmd = positional[1]
3790
3802
  if (opts.internalPerfCommand === 'scroll') {
@@ -3816,7 +3828,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3816
3828
  const parsedLimit = limitValue === undefined ? 6000 : Number(limitValue)
3817
3829
  if (!Number.isFinite(parsedLimit) || parsedLimit < 120) {
3818
3830
  console.error(' error: --limit must be a number of at least 120')
3819
- rnxExit(1)
3831
+ peachExit(1)
3820
3832
  }
3821
3833
  const pressTestID = effectiveArgs.find(
3822
3834
  (_, index) => effectiveArgs[index - 1] === '--press-testid',
@@ -3832,7 +3844,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3832
3844
  })
3833
3845
  if (result?.error) {
3834
3846
  console.error(` error: ${result.error}`)
3835
- rnxExit(1)
3847
+ peachExit(1)
3836
3848
  }
3837
3849
  console.log(
3838
3850
  ` scroll profiling started: perform consecutive swipes, then run '${inspectCommand('perf')} stop'`,
@@ -3850,7 +3862,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3850
3862
  })
3851
3863
  if (result?.error) {
3852
3864
  console.error(` error: ${result.error}`)
3853
- rnxExit(1)
3865
+ peachExit(1)
3854
3866
  }
3855
3867
  const trace: SootSimScrollPerformanceTrace = result
3856
3868
  if (wantsJson(effectiveArgs)) {
@@ -3891,7 +3903,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3891
3903
  break
3892
3904
  }
3893
3905
  console.error(` unknown scroll perf command: ${perfCmd}`)
3894
- rnxExit(1)
3906
+ peachExit(1)
3895
3907
  }
3896
3908
  if (!perfCmd || perfCmd === '--help' || perfCmd === '-h') {
3897
3909
  console.log(`
@@ -3932,7 +3944,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3932
3944
  })
3933
3945
  if (result?.error) {
3934
3946
  console.error(` error: ${result.error}`)
3935
- rnxExit(1)
3947
+ peachExit(1)
3936
3948
  }
3937
3949
  console.log(
3938
3950
  ` shell profiling started — interact with the app, then run '${inspectCommand('perf')} stop'`,
@@ -3957,7 +3969,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
3957
3969
  ' (shell worker did not answer within 5s — is a sim loaded?)',
3958
3970
  )
3959
3971
  }
3960
- rnxExit(1)
3972
+ peachExit(1)
3961
3973
  }
3962
3974
  if (wantsJson(effectiveArgs)) {
3963
3975
  printJson(result)
@@ -4013,7 +4025,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4013
4025
  })
4014
4026
  if (result?.error) {
4015
4027
  console.error(` error: ${result.error}`)
4016
- rnxExit(1)
4028
+ peachExit(1)
4017
4029
  }
4018
4030
  if (wantsJson(effectiveArgs)) {
4019
4031
  printJson(result)
@@ -4046,7 +4058,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4046
4058
  ` use 'perf start' / 'perf stop' (worst frames are in the stop report).`,
4047
4059
  )
4048
4060
  }
4049
- rnxExit(1)
4061
+ peachExit(1)
4050
4062
  }
4051
4063
  break
4052
4064
  }
@@ -4151,12 +4163,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4151
4163
  const raw = positional[1]
4152
4164
  if (!raw || raw === '--help' || raw === '-h') {
4153
4165
  console.error(` usage: ${inspectCommand('animation')} <id>`)
4154
- rnxExit(1)
4166
+ peachExit(1)
4155
4167
  }
4156
4168
  const id = Number(raw)
4157
4169
  if (!Number.isFinite(id)) {
4158
4170
  console.error(` invalid id: ${raw}`)
4159
- rnxExit(1)
4171
+ peachExit(1)
4160
4172
  }
4161
4173
  const result = await callTestBridge(bridge, 'getAnimation', id)
4162
4174
  console.log(JSON.stringify(result, null, 2))
@@ -4167,12 +4179,12 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4167
4179
  const raw = positional[1]
4168
4180
  if (!raw || raw === '--help' || raw === '-h') {
4169
4181
  console.error(` usage: ${inspectCommand('stop-animation')} <id|all>`)
4170
- rnxExit(1)
4182
+ peachExit(1)
4171
4183
  }
4172
4184
  const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
4173
4185
  if (target !== 'all' && !Number.isFinite(target)) {
4174
4186
  console.error(` invalid id: ${raw}`)
4175
- rnxExit(1)
4187
+ peachExit(1)
4176
4188
  }
4177
4189
  const count = await callTestBridge<number>(bridge, 'stopAnimation', target)
4178
4190
  console.log(` stopped ${count ?? 0} animation(s)`)
@@ -4275,7 +4287,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4275
4287
  const id = positional[2]
4276
4288
  if (!id) {
4277
4289
  console.error(' usage: peach network get <id>')
4278
- rnxExit(1)
4290
+ peachExit(1)
4279
4291
  }
4280
4292
  const entry = (await bridge.send({
4281
4293
  type: 'evaluate',
@@ -4287,7 +4299,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4287
4299
  })) as NetworkEntryPayload | null
4288
4300
  if (!entry) {
4289
4301
  console.error(` no entry with id ${id}`)
4290
- rnxExit(1)
4302
+ peachExit(1)
4291
4303
  }
4292
4304
  if (jsonOut) {
4293
4305
  console.log(JSON.stringify(entry, null, 2))
@@ -4306,7 +4318,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4306
4318
  ` invalid limit: ${sub} — \`network\` takes a numeric count (e.g. ${inspectCommand('network')} 100).\n` +
4307
4319
  ` to target a specific sim, use \`--sim ${sub}\` instead.`,
4308
4320
  )
4309
- rnxExit(1)
4321
+ peachExit(1)
4310
4322
  }
4311
4323
 
4312
4324
  const fetchEntries = async () => {
@@ -4475,7 +4487,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4475
4487
  ` invalid limit: ${sub} — \`logs\` takes a numeric count (e.g. ${inspectCommand('logs')} 100).\n` +
4476
4488
  ` to target a specific sim, use \`--sim ${sub}\` instead.`,
4477
4489
  )
4478
- rnxExit(1)
4490
+ peachExit(1)
4479
4491
  }
4480
4492
 
4481
4493
  const fetchEntries = () => inspectLogs(bridge)
@@ -4533,7 +4545,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4533
4545
 
4534
4546
  default:
4535
4547
  console.error(` unknown subcommand: ${subcommand}`)
4536
- rnxExit(1)
4548
+ peachExit(1)
4537
4549
  }
4538
4550
 
4539
4551
  // auto-settle after any write command so the next CLI call doesn't see
@@ -4641,7 +4653,7 @@ export async function runInspect(args: string[], opts: InspectOptions) {
4641
4653
  // ignore secondary request summary errors while already failing the command
4642
4654
  }
4643
4655
  }
4644
- rnxExit(1)
4656
+ peachExit(1)
4645
4657
  } finally {
4646
4658
  if (subcommand !== 'list') await collectRuntimeDiagnostics(bridge)
4647
4659
  bridge.close()