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.
- package/README.md +28 -22
- package/cli/app-catalog.ts +29 -14
- package/cli/app-fonts.ts +5 -3
- package/cli/bridge-flow-runner.ts +40 -29
- package/cli/cloud-client.ts +57 -21
- package/cli/cloud-test-tunnel.ts +12 -18
- package/cli/commands/agent.ts +1 -1
- package/cli/commands/app-fonts.ts +3 -3
- package/cli/commands/assert.ts +8 -8
- package/cli/commands/auth.ts +8 -3
- package/cli/commands/box/bundle-plane.ts +13 -1
- package/cli/commands/box.ts +16 -5
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +125 -71
- package/cli/commands/cpu-profile.ts +45 -1
- package/cli/commands/daemon.ts +131 -33
- package/cli/commands/debug.ts +24 -17
- package/cli/commands/desktop.ts +7 -1
- package/cli/commands/detect.ts +101 -0
- package/cli/commands/detox.ts +6 -6
- package/cli/commands/device.ts +12 -12
- package/cli/commands/electron.ts +32 -14
- package/cli/commands/flow.ts +49 -41
- package/cli/commands/guest-host.ts +39 -1
- package/cli/commands/inspect/core.ts +14 -8
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/settle.ts +5 -3
- package/cli/commands/inspect/settling.ts +229 -44
- package/cli/commands/inspect/wait-idle.ts +3 -2
- package/cli/commands/inspect.ts +105 -93
- package/cli/commands/install-cli.ts +36 -15
- package/cli/commands/install-desktop.ts +68 -195
- package/cli/commands/kotlin.ts +6 -5
- package/cli/commands/login.ts +5 -5
- package/cli/commands/maestro-compare.ts +554 -0
- package/cli/commands/maestro-generate.ts +6 -3
- package/cli/commands/maestro.ts +22 -0
- package/cli/commands/mode.ts +2 -2
- package/cli/commands/no-bridge-hint.ts +6 -2
- package/cli/commands/platform.ts +35 -6
- package/cli/commands/preview.ts +6 -0
- package/cli/commands/project-report.ts +10 -12
- package/cli/commands/record.ts +37 -37
- package/cli/commands/runtime.ts +9 -9
- package/cli/commands/screenshot-layers.ts +4 -4
- package/cli/commands/screenshot-mode.ts +2 -2
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +2 -2
- package/cli/commands/serve.ts +9 -12
- package/cli/commands/setup.ts +29 -14
- package/cli/commands/shell-boolean-mode.ts +2 -2
- package/cli/commands/show-touches-mode.ts +2 -2
- package/cli/commands/skills.ts +11 -11
- package/cli/commands/swift.ts +29 -11
- package/cli/commands/telemetry.ts +2 -2
- package/cli/commands/test.ts +5 -0
- package/cli/commands/three-mode.ts +3 -3
- package/cli/commands/timeline.ts +4 -4
- package/cli/commands/upgrade.ts +2 -2
- package/cli/commands/upload.ts +15 -15
- package/cli/commands/what-happened.ts +2 -2
- package/cli/current-sim.ts +6 -3
- package/cli/desktop-companion.ts +55 -149
- package/cli/dev-build-freshness.ts +2 -2
- package/cli/drivers/desktop.ts +17 -9
- package/cli/drivers/electron.ts +1 -2
- package/cli/drivers/playwright-sim-host.ts +11 -2
- package/cli/drivers/playwright.ts +35 -2
- package/cli/drivers/types.ts +8 -0
- package/cli/maestro-compare.ts +670 -0
- package/cli/outbound-endpoints.ts +46 -8
- package/cli/recording-access.ts +6 -6
- package/cli/run-registry.ts +1 -1
- package/cli/runtime-compat.ts +5 -1
- package/cli/send-to-box.ts +3 -3
- package/cli/shell-init.ts +2 -1
- package/cli/ws-bridge.ts +9 -5
- package/detox/element-types.ts +1 -0
- package/detox/gestures.ts +3 -3
- package/detox/index.ts +67 -38
- package/detox/navigation-lifecycle.ts +9 -6
- package/detox/proof-frame.cjs +6 -4
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +42 -17
- package/dist-lib/bridge-contract-input.mjs +41 -16
- package/dist-lib/bridge-contract.cjs +1 -4
- package/dist-lib/bridge-contract.mjs +1 -3
- package/dist-lib/bundle-channel.cjs +2918 -550
- package/dist-lib/capture-contract.cjs +65 -24
- package/dist-lib/capture-contract.mjs +63 -24
- package/dist-lib/cloud-contract.cjs +2 -2
- package/dist-lib/cloud-contract.mjs +2 -2
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +3 -3
- package/dist-lib/cloud.mjs +3 -3
- package/dist-lib/config.cjs +15 -5
- package/dist-lib/config.mjs +154 -0
- package/dist-lib/detox/index.cjs +495 -139
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/expo-swift-bundle.cjs +1168 -238
- package/dist-lib/expo-swift-metadata.cjs +34 -23
- package/dist-lib/expo-swift-metadata.mjs +32 -23
- package/dist-lib/home-paths.cjs +2 -2
- package/dist-lib/host/bridge-host.cjs +2938 -654
- package/dist-lib/host/fetch-proxy-handler.cjs +14 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +7 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +5 -1
- package/dist-lib/host/replacement-module-handler.cjs +2 -2
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +999 -353
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +332 -19
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +7 -7
- package/dist-lib/metro-production-bundle.mjs +5 -5
- package/dist-lib/metro.cjs +688 -250
- package/dist-lib/native-app-identity-project.cjs +2647 -0
- package/dist-lib/native-app-identity-project.mjs +1257 -0
- package/dist-lib/native-app-identity.cjs +325 -25
- package/dist-lib/native-app-identity.mjs +323 -25
- package/dist-lib/native-firebase-metadata.cjs +1 -1
- package/dist-lib/native-firebase-metadata.mjs +1 -1
- package/dist-lib/plist.cjs +1 -1
- package/dist-lib/plist.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +5 -1
- package/dist-lib/react-native-host-modules.mjs +5 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +57 -32
- package/dist-lib/sdk.cjs +231 -51
- package/dist-lib/sdk.mjs +231 -51
- package/dist-lib/skills.cjs +4107 -1374
- package/dist-lib/swift-compile.cjs +290 -30
- package/dist-lib/swift-compile.mjs +290 -30
- package/dist-lib/swift-package.cjs +143 -12
- package/dist-lib/swift-package.mjs +137 -11
- package/dist-lib/swift-submit.cjs +47 -5
- package/dist-lib/swift-submit.mjs +42 -5
- package/dist-lib/swift-toolchain.cjs +7 -2
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1392 -458
- package/dist-lib/vite.cjs +13 -17
- package/dist-lib/worklet-executable.cjs +248 -33
- package/dist-lib/worklet-executable.mjs +248 -33
- package/install.sh +10 -1
- package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Resources.kt +9 -9
- package/kotlin/AndroidViewSources/android/graphics/Canvas.kt +20 -0
- package/kotlin/AndroidViewSources/android/view/View.kt +211 -0
- package/kotlin/AndroidViewSources/android/widget/FrameLayout.kt +61 -0
- package/kotlin/AndroidViewSources/android/widget/LinearLayout.kt +49 -0
- package/kotlin/AppSources/android/view/Window.kt +36 -0
- package/kotlin/AppSources/android/view/WindowInsets.kt +9 -0
- package/kotlin/AppSources/android/view/WindowInsetsController.kt +5 -0
- package/kotlin/AppSources/android/window/OnBackInvokedDispatcher.kt +48 -0
- package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +20 -5
- package/kotlin/AppSources/androidx/compose/foundation/layout/WindowInsets.kt +15 -0
- package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +2 -1
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +42 -50
- package/kotlin/ComposeSources/PeachComposeHost.kt +200 -84
- package/kotlin/ExpoComposeSources/PeachAndroidView.kt +87 -0
- package/kotlin/ExpoComposeSources/PeachExpoViewMount.kt +24 -0
- package/kotlin/ExpoComposeSources/dev/peach/expo/PeachExpoCompose.kt +28 -0
- package/kotlin/ExpoComposeSources/expo/modules/kotlin/views/ExpoComposeView.kt +70 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoRuntime.kt +513 -0
- package/kotlin/ExpoSources/dev/peach/expo/PeachExpoTypes.kt +173 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/AppContext.kt +20 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/Promise.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +198 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/exception/CodedException.kt +126 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/functions/Functions.kt +132 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/jni/JavaScriptTypedArray.kt +81 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/modules/Module.kt +98 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +236 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/records/Record.kt +12 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/runtime/Runtime.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObject.kt +50 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +57 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/sharedobjects/SharedRef.kt +19 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/ConcreteTypedArrays.kt +158 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/GenericTypedArray.kt +8 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArray.kt +29 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/typedarray/TypedArrayIterator.kt +9 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/AnyType.kt +155 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Either.kt +91 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/types/Enumerable.kt +6 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/viewevent/ViewEvent.kt +54 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ExpoView.kt +23 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +71 -0
- package/kotlin/ExpoSources/expo/modules/kotlin/views/ViewProps.kt +35 -0
- package/kotlin/README.md +13 -3
- package/kotlin/Sources/android/os/Build.kt +17 -0
- package/kotlin/Sources/android/os/Handler.kt +35 -0
- package/kotlin/Sources/android/os/Looper.kt +17 -0
- package/kotlin/Sources/android/os/MessageQueue.kt +56 -0
- package/kotlin/Sources/android/os/SystemClock.kt +14 -0
- package/kotlin/Sources/android/util/Log.kt +64 -0
- package/kotlin/Sources/java/security/MessageDigest.kt +114 -0
- package/kotlin/Sources/kotlin/text/StringFormat.kt +9 -0
- package/kotlin/Sources/org/json/JSON.kt +44 -0
- package/kotlin/fixtures/counter/Counter.d.kt.ts +1 -0
- package/kotlin/fixtures/counter/Counter.kt +10 -3
- package/kotlin/fixtures/counter/CounterApp.native.tsx +1 -1
- package/kotlin/fixtures/counter/vite.config.ts +2 -2
- package/kotlin/fixtures/headless-counter/Headless.kt +7 -6
- package/kotlin/fixtures/import-animation/Animation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-animation/Animation.kt +80 -0
- package/kotlin/fixtures/import-animation/ImportAnimation.native.tsx +13 -0
- package/kotlin/fixtures/import-animation/README.md +24 -0
- package/kotlin/fixtures/import-animation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-animation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-animation/app/routes.d.ts +18 -0
- package/kotlin/fixtures/import-animation/package.json +23 -0
- package/kotlin/fixtures/import-animation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-animation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-editor/Editor.d.kt.ts +7 -0
- package/kotlin/fixtures/import-editor/Editor.kt +59 -0
- package/kotlin/fixtures/import-editor/ImportEditor.native.tsx +23 -0
- package/kotlin/fixtures/import-editor/README.md +27 -0
- package/kotlin/fixtures/import-editor/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-editor/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-editor/package.json +23 -0
- package/kotlin/fixtures/import-editor/tsconfig.json +20 -0
- package/kotlin/fixtures/import-editor/vite.config.ts +20 -0
- package/kotlin/fixtures/import-effects/Effects.d.kt.ts +7 -0
- package/kotlin/fixtures/import-effects/Effects.kt +87 -0
- package/kotlin/fixtures/import-effects/ImportEffects.native.tsx +13 -0
- package/kotlin/fixtures/import-effects/README.md +19 -0
- package/kotlin/fixtures/import-effects/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-effects/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-effects/package.json +23 -0
- package/kotlin/fixtures/import-effects/tsconfig.json +20 -0
- package/kotlin/fixtures/import-effects/vite.config.ts +20 -0
- package/kotlin/fixtures/import-layout/ImportLayout.native.tsx +13 -0
- package/kotlin/fixtures/import-layout/Layout.d.kt.ts +7 -0
- package/kotlin/fixtures/import-layout/Layout.kt +72 -0
- package/kotlin/fixtures/import-layout/README.md +24 -0
- package/kotlin/fixtures/import-layout/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-layout/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-layout/package.json +23 -0
- package/kotlin/fixtures/import-layout/tsconfig.json +20 -0
- package/kotlin/fixtures/import-layout/vite.config.ts +20 -0
- package/kotlin/fixtures/import-navigation/ImportNavigation.native.tsx +18 -0
- package/kotlin/fixtures/import-navigation/Navigation.d.kt.ts +7 -0
- package/kotlin/fixtures/import-navigation/Navigation.kt +104 -0
- package/kotlin/fixtures/import-navigation/README.md +31 -0
- package/kotlin/fixtures/import-navigation/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-navigation/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-navigation/package.json +23 -0
- package/kotlin/fixtures/import-navigation/tsconfig.json +20 -0
- package/kotlin/fixtures/import-navigation/vite.config.ts +20 -0
- package/kotlin/fixtures/import-overlays/ImportOverlays.native.tsx +29 -0
- package/kotlin/fixtures/import-overlays/Overlays.d.kt.ts +7 -0
- package/kotlin/fixtures/import-overlays/Overlays.kt +93 -0
- package/kotlin/fixtures/import-overlays/README.md +34 -0
- package/kotlin/fixtures/import-overlays/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-overlays/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-overlays/package.json +23 -0
- package/kotlin/fixtures/import-overlays/tsconfig.json +20 -0
- package/kotlin/fixtures/import-overlays/vite.config.ts +20 -0
- package/kotlin/fixtures/import-scroll/ImportScroll.native.tsx +13 -0
- package/kotlin/fixtures/import-scroll/README.md +23 -0
- package/kotlin/fixtures/import-scroll/Scroll.d.kt.ts +7 -0
- package/kotlin/fixtures/import-scroll/Scroll.kt +91 -0
- package/kotlin/fixtures/import-scroll/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-scroll/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-scroll/package.json +23 -0
- package/kotlin/fixtures/import-scroll/tsconfig.json +20 -0
- package/kotlin/fixtures/import-scroll/vite.config.ts +20 -0
- package/kotlin/fixtures/import-selection/ImportSelection.native.tsx +44 -0
- package/kotlin/fixtures/import-selection/README.md +32 -0
- package/kotlin/fixtures/import-selection/Selection.d.kt.ts +8 -0
- package/kotlin/fixtures/import-selection/Selection.kt +78 -0
- package/kotlin/fixtures/import-selection/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-selection/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-selection/package.json +23 -0
- package/kotlin/fixtures/import-selection/tsconfig.json +20 -0
- package/kotlin/fixtures/import-selection/vite.config.ts +20 -0
- package/kotlin/fixtures/import-surfaces/ImportSurfaces.native.tsx +13 -0
- package/kotlin/fixtures/import-surfaces/README.md +22 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.d.kt.ts +7 -0
- package/kotlin/fixtures/import-surfaces/Surfaces.kt +64 -0
- package/kotlin/fixtures/import-surfaces/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-surfaces/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-surfaces/package.json +23 -0
- package/kotlin/fixtures/import-surfaces/tsconfig.json +20 -0
- package/kotlin/fixtures/import-surfaces/vite.config.ts +20 -0
- package/kotlin/fixtures/import-values/ImportValues.native.tsx +35 -0
- package/kotlin/fixtures/import-values/README.md +23 -0
- package/kotlin/fixtures/import-values/Values.d.kt.ts +11 -0
- package/kotlin/fixtures/import-values/Values.kt +66 -0
- package/kotlin/fixtures/import-values/app/_layout.tsx +4 -0
- package/kotlin/fixtures/import-values/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/import-values/package.json +23 -0
- package/kotlin/fixtures/import-values/tsconfig.json +20 -0
- package/kotlin/fixtures/import-values/vite.config.ts +20 -0
- package/kotlin/fixtures/kotlin-app-variants/BarBehavior.kt +38 -0
- package/kotlin/fixtures/kotlin-app-variants/BarVisibility.kt +36 -0
- package/kotlin/fixtures/kotlin-app-variants/Ime.kt +3 -1
- package/kotlin/fixtures/kotlin-app-variants/TransientInsets.kt +50 -0
- package/kotlin/fork/NOTICE +6 -1
- package/kotlin/fork/README.md +15 -7
- package/kotlin/fork/build.sh +2 -0
- package/kotlin/fork/compose-worker-globals.patch +186 -4
- package/kotlin/fork/fork.json +2 -2
- package/kotlin/fork/skiko-worker-clock.patch +12 -0
- package/kotlin/toolchain.json +12 -12
- package/kotlin/tools/expo-types.main.kts +115 -0
- package/package.json +17 -23
- package/scripts/dev-server-scanner.ts +92 -66
- package/skills/contrast/SKILL.md +2 -2
- package/skills/peach-debug/SKILL.md +1 -1
- package/skills/peach-perf/SKILL.md +1 -1
- package/skills/peach-setup/SKILL.md +2 -1
- package/skills/peach-test/SKILL.md +8 -0
- package/src/assetCatalogContract.ts +43 -1
- package/src/bridge-contract-input.ts +46 -19
- package/src/bridge-contract.ts +0 -1
- package/src/bundle-channel.mjs +197 -84
- package/src/bundleGlobalFooter.ts +38 -0
- package/src/capture-contract.ts +107 -33
- package/src/cloud-contract.ts +5 -1
- package/src/cloud.ts +5 -2
- package/src/config.ts +22 -3
- package/src/configured-bundle-producer.ts +1 -1
- package/src/desktop-host-delivery.ts +95 -1
- package/src/expo-kotlin-bundle.ts +29 -0
- package/src/expo-kotlin-host.ts +201 -0
- package/src/expo-swift-host.ts +96 -76
- package/src/expoKotlinContract.ts +70 -0
- package/src/expoSwiftContract.ts +4 -25
- package/src/home-paths.ts +7 -4
- package/src/host/bridge-host.ts +23 -3
- package/src/host/fetch-proxy-handler.ts +13 -0
- package/src/host/fetch-proxy-overrides.ts +11 -0
- package/src/host/replacement-module-handler.ts +5 -2
- package/src/index.ts +3 -1
- package/src/kotlin-host.ts +463 -19
- package/src/metro-plugin.ts +56 -28
- package/src/metro-production-bundle.ts +2 -2
- package/src/native-app-identity-project.ts +190 -0
- package/src/native-app-identity.ts +398 -34
- package/src/native-firebase-config.ts +69 -15
- package/src/native-seam-manifest.ts +6 -0
- package/src/one-widget-discovery.ts +2 -1
- package/src/openstep-plist.ts +107 -0
- package/src/react-native-host-modules.ts +4 -0
- package/src/runtime-assets.ts +2 -2
- package/src/sim-client.ts +2 -2
- package/src/swift-binary-modules.ts +3 -1
- package/src/swift-compile.ts +286 -38
- package/src/swift-distribution-contract.ts +4 -0
- package/src/swift-distribution.lock.json +123 -12
- package/src/swift-distribution.ts +7 -3
- package/src/swift-host.ts +298 -83
- package/src/swift-package-manifest.ts +29 -2
- package/src/swift-package.ts +180 -10
- package/src/swift-packages.ts +4 -0
- package/src/swift-standin-emit.ts +4 -1
- package/src/swift-standins.ts +274 -15
- package/src/swift-submit.ts +62 -7
- package/src/swift-toolchain.ts +6 -1
- package/src/swiftContract.ts +126 -3
- package/src/vite-plugin-one.ts +13 -16
- package/src/vite-plugin-swift.ts +4 -5
- package/src/vite-plugin.ts +360 -144
- package/src/vite.d.ts +1 -1
- package/src/worker-system-chunks.ts +221 -0
- package/src/worklet-executable.ts +348 -38
- package/src/worklets-babel.ts +1 -1
- package/src/xcode-project.ts +243 -127
- package/dist-lib/agent-identity.cjs +0 -39
- package/dist-lib/agent-sessions.cjs +0 -760
- package/dist-lib/cli-constants.cjs +0 -32
- package/dist-lib/render-mode.cjs +0 -44
- package/kotlin/AppSources/android/view/View.kt +0 -74
- package/kotlin/AppSources/android/widget/FrameLayout.kt +0 -6
- package/src/render-mode.ts +0 -15
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/Context.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/content/res/Configuration.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/graphics/Color.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/android/util/DisplayMetrics.kt +0 -0
- /package/kotlin/{AppSources → AndroidViewSources}/dev/peach/app/JavaFormat.kt +0 -0
- /package/kotlin/{AppSources → Sources}/java/lang/Runnable.kt +0 -0
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
HEADLESS_TENANT_FETCH_HUNG_MARKER,
|
|
16
|
-
PUBLIC_NO_NETWORK_MARKER,
|
|
17
16
|
readyProbeIsReady,
|
|
18
17
|
type SemanticWaitResult,
|
|
19
18
|
type WsBridgeCommand,
|
|
@@ -1197,10 +1196,7 @@ export function waitReadyReason(
|
|
|
1197
1196
|
> & { bridgeError?: string },
|
|
1198
1197
|
): string {
|
|
1199
1198
|
if (status.bridgeError) {
|
|
1200
|
-
if (
|
|
1201
|
-
status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER) ||
|
|
1202
|
-
status.bridgeError.includes(PUBLIC_NO_NETWORK_MARKER)
|
|
1203
|
-
) {
|
|
1199
|
+
if (status.bridgeError.includes(HEADLESS_TENANT_FETCH_HUNG_MARKER)) {
|
|
1204
1200
|
return status.bridgeError
|
|
1205
1201
|
}
|
|
1206
1202
|
return `sim unreachable: ${status.bridgeError} — the target tab is closed or no sim is connected (check \`peach list\`, reopen with \`peach open\`)`
|
|
@@ -1269,7 +1265,7 @@ export async function inspectCaptureReady(
|
|
|
1269
1265
|
}
|
|
1270
1266
|
|
|
1271
1267
|
// how long one snapshot request may take to cross the bridge and read once
|
|
1272
|
-
const READY_SNAPSHOT_SEND_TIMEOUT_MS =
|
|
1268
|
+
const READY_SNAPSHOT_SEND_TIMEOUT_MS = 15_000
|
|
1273
1269
|
|
|
1274
1270
|
// one readiness probe, judged on its own: no stability window, since the
|
|
1275
1271
|
// caller has already let the app settle. any runtime answers it: a wait that
|
|
@@ -1286,8 +1282,18 @@ export async function inspectReadySnapshot(
|
|
|
1286
1282
|
const deadline = Date.now() + budgetMs
|
|
1287
1283
|
let result: SemanticWaitResult
|
|
1288
1284
|
do {
|
|
1289
|
-
|
|
1290
|
-
|
|
1285
|
+
const remaining = Math.max(0, deadline - Date.now())
|
|
1286
|
+
const sendTimeoutMs = Math.max(
|
|
1287
|
+
READY_SNAPSHOT_SEND_TIMEOUT_MS,
|
|
1288
|
+
Math.min(remaining, 60_000),
|
|
1289
|
+
)
|
|
1290
|
+
result = await sendReadyWait(bridge, 1, sendTimeoutMs, simId)
|
|
1291
|
+
} while (
|
|
1292
|
+
result.polls !== 1 &&
|
|
1293
|
+
!result.error?.startsWith('sim disconnected') &&
|
|
1294
|
+
!result.error?.startsWith('bridge never reconnected') &&
|
|
1295
|
+
Date.now() < deadline
|
|
1296
|
+
)
|
|
1291
1297
|
return waitReadyStatus(
|
|
1292
1298
|
result,
|
|
1293
1299
|
result.polls === 1 && result.probe ? readyProbeIsReady(result.probe) : false,
|
|
@@ -154,7 +154,7 @@ function printConnectedSims(sims: BridgeSimInfo[], selectedId?: string) {
|
|
|
154
154
|
// classify which engine a sim is running so dev-vs-published is never ambiguous
|
|
155
155
|
// to agents or humans reading `peach list`. dev shell serves local source on
|
|
156
156
|
// :5173; the Contrast app embeds peach on :3000; the bridge/daemon and the
|
|
157
|
-
// /
|
|
157
|
+
// /__peachsim plugin serve the active runtime dir — which, inside a dev checkout, is
|
|
158
158
|
// the fresh dev-stack build (resolveDevCheckoutRuntimeRoot mode boundary), not a
|
|
159
159
|
// published runtime. keep this label honest so it never says "published" while
|
|
160
160
|
// actually serving local build output.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { waitForSootsimIdle } from './settling'
|
|
2
2
|
import type { WsBridge } from '../../ws-bridge'
|
|
3
3
|
|
|
4
|
-
// default:
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// default: worker stillness plus mounted-root membership; budgets of a
|
|
5
|
+
// second or more also confirm the mounted geometry. --strict additionally
|
|
6
|
+
// requires shell motion to clear and rejects runtimes without blocking
|
|
7
|
+
// animation stats — use when the target app has no perpetual background
|
|
8
|
+
// animation.
|
|
7
9
|
export async function runSettleSubcommand(opts: {
|
|
8
10
|
bridge: WsBridge
|
|
9
11
|
args: string[]
|
|
@@ -30,6 +30,20 @@ export type WaitForSootsimIdleResult = {
|
|
|
30
30
|
blockedBy: string
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export class RuntimeReadinessUnsupportedError extends Error {
|
|
34
|
+
readonly code = 'runtime_readiness_unsupported'
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
readonly runtimeVersion: string,
|
|
38
|
+
readonly missingFields: string[],
|
|
39
|
+
) {
|
|
40
|
+
super(
|
|
41
|
+
`runtime ${runtimeVersion} cannot report animation readiness (${missingFields.join(', ')} missing); run \`peach upgrade\` and reopen the simulator`,
|
|
42
|
+
)
|
|
43
|
+
this.name = 'RuntimeReadinessUnsupportedError'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
export async function waitForSootsimIdle({
|
|
34
48
|
bridge,
|
|
35
49
|
simId,
|
|
@@ -39,16 +53,23 @@ export async function waitForSootsimIdle({
|
|
|
39
53
|
strict = false,
|
|
40
54
|
paintStill = false,
|
|
41
55
|
}: WaitForSootsimIdleOptions): Promise<WaitForSootsimIdleResult> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
let result: any
|
|
57
|
+
try {
|
|
58
|
+
result = await bridge.send(
|
|
59
|
+
{
|
|
60
|
+
type: 'evaluate',
|
|
61
|
+
simId,
|
|
62
|
+
code: `(async () => {
|
|
47
63
|
const start = Date.now()
|
|
48
64
|
const deadline = start + ${Math.max(0, Math.round(maxMs))}
|
|
49
65
|
const pollMs = ${Math.max(1, Math.round(pollMs))}
|
|
50
66
|
const strict = ${strict ? 'true' : 'false'}
|
|
51
67
|
const paintStill = ${paintStill ? 'true' : 'false'}
|
|
68
|
+
// full mounted-geometry observation needs at least two hierarchy reads
|
|
69
|
+
// plus the stillness window, which a sub-second budget cannot afford:
|
|
70
|
+
// tight budgets (auto-wait) settle on worker stillness plus root
|
|
71
|
+
// membership, generous ones confirm the geometry too.
|
|
72
|
+
const fullGeometry = ${maxMs >= 1000 ? 'true' : 'false'}
|
|
52
73
|
const requiredStillMs = paintStill ? 0 : ${Math.max(1, Math.round(stablePolls)) * Math.max(1, Math.round(pollMs))}
|
|
53
74
|
const minimumStablePolls = paintStill ? 1 : ${Math.min(2, Math.max(1, Math.round(stablePolls)))}
|
|
54
75
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
@@ -85,58 +106,177 @@ export async function waitForSootsimIdle({
|
|
|
85
106
|
}
|
|
86
107
|
} catch {}
|
|
87
108
|
|
|
109
|
+
// a worker that cannot answer within the remaining budget is busy, not
|
|
110
|
+
// idle: its poll reads as unsettled. bounding each read by the budget
|
|
111
|
+
// keeps a busy worker from holding a poll past the deadline.
|
|
112
|
+
const BUSY = { busy: true }
|
|
113
|
+
const answer = (read) =>
|
|
114
|
+
Promise.race([
|
|
115
|
+
Promise.resolve().then(read),
|
|
116
|
+
new Promise((resolve) =>
|
|
117
|
+
setTimeout(() => resolve(BUSY), Math.max(deadline - Date.now(), 100)),
|
|
118
|
+
),
|
|
119
|
+
])
|
|
120
|
+
|
|
88
121
|
const readSnapshot = async () => {
|
|
89
122
|
let animating = false
|
|
90
123
|
let layoutDirty = false
|
|
91
124
|
let pendingFetches = 0
|
|
125
|
+
let workerBusy = false
|
|
92
126
|
let requestTotal = 0
|
|
93
127
|
let requestInFlight = 0
|
|
128
|
+
let appCommits = null
|
|
129
|
+
let nodeCount = null
|
|
94
130
|
let renderStatsAvailable = false
|
|
95
131
|
let shellAnimating = false
|
|
132
|
+
let webViewStarting = false
|
|
133
|
+
let webViewBlocker = ''
|
|
96
134
|
// strict also waits out shell motion: a system alert, sheet or menu
|
|
97
135
|
// animates in the shell worker while the app's own stats read still,
|
|
98
136
|
// so its presentation is complete only once the shell's list empties.
|
|
99
137
|
if (strict) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
} catch {}
|
|
138
|
+
const motion = await answer(() => window.__sootsimTest?.listAnimations?.()).catch(() => null)
|
|
139
|
+
if (motion === BUSY) workerBusy = true
|
|
140
|
+
else shellAnimating = Array.isArray(motion) && motion.some((anim) => anim.realm === 'shell' && anim.priority !== 'low')
|
|
104
141
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
? stats.memory.imageLoader.pendingFetches
|
|
121
|
-
: 0
|
|
122
|
-
pendingFetches = typeof pf === 'number' ? pf : 0
|
|
142
|
+
const stats = await answer(() => window.__sootsimRenderHost?.queryStats?.()).catch(() => null)
|
|
143
|
+
if (stats === BUSY) {
|
|
144
|
+
workerBusy = true
|
|
145
|
+
} else if (stats) {
|
|
146
|
+
renderStatsAvailable = true
|
|
147
|
+
const missingFields = ['hasActiveBlockingNativeAnimations', 'hasPendingBlockingAnimationFrames']
|
|
148
|
+
.filter((field) => typeof stats[field] !== 'boolean')
|
|
149
|
+
if (strict && missingFields.length > 0) {
|
|
150
|
+
return {
|
|
151
|
+
runtimeUnsupported: {
|
|
152
|
+
error: 'runtime_readiness_unsupported',
|
|
153
|
+
runtimeVersion: window.__sootsimRuntimeVersion || 'unknown',
|
|
154
|
+
missingFields,
|
|
155
|
+
},
|
|
156
|
+
}
|
|
123
157
|
}
|
|
124
|
-
|
|
158
|
+
// positive checks only: an older runtime without the blocking
|
|
159
|
+
// fields reads as still, and strict rejects that runtime above
|
|
160
|
+
// instead of ever settling on unknown motion.
|
|
161
|
+
animating =
|
|
162
|
+
stats.hasActiveAnims === true ||
|
|
163
|
+
stats.hasActiveBlockingNativeAnimations === true ||
|
|
164
|
+
stats.hasPendingBlockingAnimationFrames === true
|
|
165
|
+
layoutDirty =
|
|
166
|
+
stats.layoutDirty === true && stats.renderRequested === true
|
|
167
|
+
// a freshly-pushed screen showing a skeleton is layout-stable
|
|
168
|
+
// but not actually settled — its data/images are still in
|
|
169
|
+
// flight. treat bounded image-loader fetches as not-idle so
|
|
170
|
+
// settle waits for real content, capped by the budget.
|
|
171
|
+
const pf = stats.memory && stats.memory.imageLoader
|
|
172
|
+
? stats.memory.imageLoader.pendingFetches
|
|
173
|
+
: 0
|
|
174
|
+
pendingFetches = typeof pf === 'number' ? pf : 0
|
|
175
|
+
// tenant layout commits: a screen that keeps committing is still
|
|
176
|
+
// mounting or remounting, even with no animation flag raised.
|
|
177
|
+
appCommits = typeof stats.appCommitCount === 'number' ? stats.appCommitCount : null
|
|
178
|
+
}
|
|
179
|
+
// image preparation ends in the tenant before the compositor decodes
|
|
180
|
+
// and realizes its pixels. both owners must finish before settling.
|
|
181
|
+
// the compositor rejects a stats request it is too busy to answer.
|
|
182
|
+
const compositor = await answer(() => window.__sootsimCompositor.getStats()).catch(() => BUSY)
|
|
183
|
+
if (compositor === BUSY) {
|
|
184
|
+
workerBusy = true
|
|
185
|
+
} else {
|
|
186
|
+
pendingFetches += compositor.images.pendingFetches
|
|
187
|
+
pendingFetches += compositor.imageRealization.pending
|
|
188
|
+
if (compositor.webViewCaptureSettled === false) {
|
|
189
|
+
webViewStarting = true
|
|
190
|
+
webViewBlocker = 'compositor webView capture not settled'
|
|
191
|
+
}
|
|
192
|
+
}
|
|
125
193
|
try {
|
|
126
194
|
const counts = await window.__sootsimTest?.getRequestCounts?.()
|
|
127
195
|
requestTotal = typeof counts?.total === 'number' ? counts.total : 0
|
|
128
196
|
requestInFlight = typeof counts?.inFlight === 'number' ? counts.inFlight : 0
|
|
129
197
|
} catch {}
|
|
130
|
-
|
|
198
|
+
// mounted-root membership: the live node count moves while the tree
|
|
199
|
+
// mounts, unmounts or recycles, in either render mode.
|
|
200
|
+
try {
|
|
201
|
+
const total = await window.__sootsimTest?.getNodeCount?.()
|
|
202
|
+
nodeCount = typeof total === 'number' ? total : null
|
|
203
|
+
} catch {}
|
|
204
|
+
// the mounted hierarchy in render-worker mode comes from the test
|
|
205
|
+
// bridge: window.__sootsimRoot is an empty placeholder there, so a
|
|
206
|
+
// walk over it hashes every screen to the same empty string while
|
|
207
|
+
// it moves. listInspectable is the worker-backed read describe
|
|
208
|
+
// uses; a worker too busy to answer it reads as unsettled. tight
|
|
209
|
+
// budgets skip this read and settle on the cheaper signals above.
|
|
210
|
+
let hierarchy = null
|
|
211
|
+
if (fullGeometry && typeof window.__sootsimTest?.listInspectable === 'function') {
|
|
212
|
+
try {
|
|
213
|
+
hierarchy = await answer(() => window.__sootsimTest.listInspectable({}))
|
|
214
|
+
} catch {
|
|
215
|
+
hierarchy = null
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (hierarchy === BUSY) {
|
|
219
|
+
workerBusy = true
|
|
220
|
+
hierarchy = null
|
|
221
|
+
} else if (!Array.isArray(hierarchy)) {
|
|
222
|
+
hierarchy = null
|
|
223
|
+
}
|
|
131
224
|
const nodes = []
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
225
|
+
const PREVIEW_PROGRESS_REGEX = /^(creating webview|loading html|fetching bundle|waiting for first render|starting preview|loading simulator|fetching app code|waiting for native preview|starting design|loading canvas|fetching screens|painting the canvas|waiting for webview|waiting for preview|waiting for canvas|preview stalled)/i
|
|
226
|
+
const notePreviewProgress = (tid, text) => {
|
|
227
|
+
if (typeof tid === 'string' && (tid === 'web-preview-progress' || tid.endsWith('-preview-progress'))) {
|
|
228
|
+
webViewStarting = true
|
|
229
|
+
if (!webViewBlocker) webViewBlocker = 'preview progress active (' + tid + ')'
|
|
230
|
+
}
|
|
231
|
+
if (typeof text === 'string' && PREVIEW_PROGRESS_REGEX.test(text.trim())) {
|
|
232
|
+
webViewStarting = true
|
|
233
|
+
if (!webViewBlocker) webViewBlocker = 'webView startup in progress ("' + text.trim() + '")'
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (hierarchy) {
|
|
237
|
+
for (const n of hierarchy) {
|
|
238
|
+
const layout = n && n.layout
|
|
239
|
+
if (layout && layout.width > 0) {
|
|
240
|
+
const abs = (n && (n.absolute || n.absolutePosition)) || layout
|
|
241
|
+
nodes.push(Math.round(abs.x) + ',' + Math.round(abs.y) + ',' + Math.round(layout.width))
|
|
242
|
+
}
|
|
243
|
+
notePreviewProgress(
|
|
244
|
+
n.testID || n.testId,
|
|
245
|
+
typeof n.text === 'string' ? n.text : '',
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
const root = window.__sootsimRoot
|
|
250
|
+
if (root) {
|
|
251
|
+
const walk = (n) => {
|
|
252
|
+
if (n.layout && n.layout.width > 0) {
|
|
253
|
+
nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
|
|
254
|
+
}
|
|
255
|
+
notePreviewProgress(
|
|
256
|
+
n.testID || n.props?.testID || n.props?.testId,
|
|
257
|
+
n.textContent || (typeof n.props?.children === 'string' ? n.props.children : ''),
|
|
258
|
+
)
|
|
259
|
+
for (const c of n.children || []) walk(c)
|
|
260
|
+
}
|
|
261
|
+
walk(root)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (!webViewStarting && typeof document !== 'undefined') {
|
|
265
|
+
const progressEl = document.querySelector(
|
|
266
|
+
'[data-testid$="-preview-progress"], [data-testid="web-preview-progress"], [data-testid="ios-preview-progress"], [data-testid="design-preview-progress"]'
|
|
267
|
+
)
|
|
268
|
+
if (progressEl) {
|
|
269
|
+
webViewStarting = true
|
|
270
|
+
webViewBlocker = 'preview progress element displayed'
|
|
271
|
+
} else {
|
|
272
|
+
const unreadyWebView = document.querySelector(
|
|
273
|
+
'[data-sootsim-webview-loading="true"], [data-sootsim-webview-mode="placeholder"]'
|
|
274
|
+
)
|
|
275
|
+
if (unreadyWebView) {
|
|
276
|
+
webViewStarting = true
|
|
277
|
+
webViewBlocker = 'webView document still loading'
|
|
136
278
|
}
|
|
137
|
-
for (const c of n.children || []) walk(c)
|
|
138
279
|
}
|
|
139
|
-
walk(root)
|
|
140
280
|
}
|
|
141
281
|
if (paintStill) {
|
|
142
282
|
const canvas = composite.getCanvas()
|
|
@@ -150,7 +290,7 @@ export async function waitForSootsimIdle({
|
|
|
150
290
|
pixelFrameToken = token
|
|
151
291
|
}
|
|
152
292
|
}
|
|
153
|
-
return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, renderStatsAvailable, requestTotal, requestInFlight }
|
|
293
|
+
return { layout: nodes.join(';'), screenPixels, animating, shellAnimating, layoutDirty, pendingFetches, workerBusy, webViewStarting, webViewBlocker, renderStatsAvailable, requestTotal, requestInFlight, appCommits, nodeCount }
|
|
154
294
|
}
|
|
155
295
|
|
|
156
296
|
// how long generic background network is allowed to keep us waiting AFTER
|
|
@@ -168,6 +308,8 @@ export async function waitForSootsimIdle({
|
|
|
168
308
|
let lastScreenPixels = null
|
|
169
309
|
let screenChangedPolls = 0
|
|
170
310
|
let lastRequestTotal = -1
|
|
311
|
+
let lastAppCommits = null
|
|
312
|
+
let lastNodeCount = null
|
|
171
313
|
let stable = 0
|
|
172
314
|
let visuallyStillSince = 0
|
|
173
315
|
// counts across the whole budget: a flag that is true on every poll is a
|
|
@@ -177,6 +319,7 @@ export async function waitForSootsimIdle({
|
|
|
177
319
|
let dirtyPolls = 0
|
|
178
320
|
let animatingPolls = 0
|
|
179
321
|
let layoutChangedPolls = 0
|
|
322
|
+
let webViewStartingPolls = 0
|
|
180
323
|
const screenUnchanged = (pixels) => {
|
|
181
324
|
if (!pixels || !lastScreenPixels || pixels.width !== lastScreenPixels.width || pixels.height !== lastScreenPixels.height) return false
|
|
182
325
|
if (pixels === lastScreenPixels) return true
|
|
@@ -187,9 +330,11 @@ export async function waitForSootsimIdle({
|
|
|
187
330
|
}
|
|
188
331
|
while (Date.now() < deadline) {
|
|
189
332
|
const snapshot = await readSnapshot()
|
|
333
|
+
if (snapshot.runtimeUnsupported) return snapshot.runtimeUnsupported
|
|
190
334
|
polls++
|
|
191
335
|
if (snapshot.layoutDirty) dirtyPolls++
|
|
192
336
|
if (snapshot.animating || snapshot.shellAnimating) animatingPolls++
|
|
337
|
+
if (snapshot.webViewStarting) webViewStartingPolls++
|
|
193
338
|
if (polls > 1 && snapshot.layout !== lastLayout) layoutChangedPolls++
|
|
194
339
|
const screenChanged = paintStill && !screenUnchanged(snapshot.screenPixels)
|
|
195
340
|
if (polls > 1 && screenChanged) screenChangedPolls++
|
|
@@ -199,12 +344,24 @@ export async function waitForSootsimIdle({
|
|
|
199
344
|
!snapshot.animating &&
|
|
200
345
|
!snapshot.shellAnimating &&
|
|
201
346
|
!snapshot.layoutDirty)
|
|
202
|
-
// visually settled: no
|
|
203
|
-
//
|
|
347
|
+
// visually settled: no worker motion or layout work, no new layout
|
|
348
|
+
// commits, a stable mounted node count, no image content loading,
|
|
349
|
+
// no webview startup in progress, layout unchanged since the last
|
|
350
|
+
// poll. both modes wait out finite worker motion now; strict
|
|
351
|
+
// additionally implies the flags through strictOk and adds shell
|
|
352
|
+
// motion plus the blocking-stats floor. a null count or commit
|
|
353
|
+
// reading means the runtime does not report it, which reads as
|
|
354
|
+
// stable the way a missing stats block does.
|
|
204
355
|
const visuallyStill =
|
|
205
356
|
strictOk &&
|
|
357
|
+
!snapshot.animating &&
|
|
358
|
+
!snapshot.layoutDirty &&
|
|
359
|
+
(snapshot.appCommits === null || lastAppCommits === null || snapshot.appCommits === lastAppCommits) &&
|
|
360
|
+
(snapshot.nodeCount === null || lastNodeCount === null || snapshot.nodeCount === lastNodeCount) &&
|
|
206
361
|
!screenChanged &&
|
|
207
362
|
snapshot.pendingFetches === 0 &&
|
|
363
|
+
!snapshot.workerBusy &&
|
|
364
|
+
!snapshot.webViewStarting &&
|
|
208
365
|
snapshot.layout === lastLayout
|
|
209
366
|
// generic network quiet: nothing in flight and no new requests issued.
|
|
210
367
|
const networkQuiet =
|
|
@@ -229,15 +386,22 @@ export async function waitForSootsimIdle({
|
|
|
229
386
|
lastLayout = snapshot.layout
|
|
230
387
|
lastScreenPixels = snapshot.screenPixels
|
|
231
388
|
lastRequestTotal = snapshot.requestTotal
|
|
389
|
+
lastAppCommits = snapshot.appCommits
|
|
390
|
+
lastNodeCount = snapshot.nodeCount
|
|
232
391
|
await sleep(pollMs)
|
|
233
392
|
}
|
|
234
393
|
const last = await readSnapshot()
|
|
394
|
+
if (last.runtimeUnsupported) return last.runtimeUnsupported
|
|
235
395
|
const blockers = []
|
|
236
396
|
if (strict && !last.renderStatsAvailable) blockers.push('render stats unavailable')
|
|
237
397
|
if (last.animating) blockers.push('animations still running')
|
|
238
398
|
if (last.shellAnimating) blockers.push('shell animations still running')
|
|
239
399
|
if (last.layoutDirty) blockers.push('layout still dirty')
|
|
400
|
+
if (last.appCommits !== null && lastAppCommits !== null && last.appCommits !== lastAppCommits) blockers.push('layout commits still landing')
|
|
401
|
+
if (last.nodeCount !== null && lastNodeCount !== null && last.nodeCount !== lastNodeCount) blockers.push('node count still changing')
|
|
240
402
|
if (last.pendingFetches > 0) blockers.push(last.pendingFetches + ' image fetches pending')
|
|
403
|
+
if (last.workerBusy) blockers.push('a render worker too busy to report')
|
|
404
|
+
if (last.webViewStarting) blockers.push(last.webViewBlocker || 'webView still starting')
|
|
241
405
|
if (last.layout !== lastLayout) blockers.push('layout still changing')
|
|
242
406
|
if (paintStill && !last.screenPixels) blockers.push('screen pixels unavailable')
|
|
243
407
|
else if (paintStill && !screenUnchanged(last.screenPixels)) blockers.push('screen pixels still changing')
|
|
@@ -250,17 +414,37 @@ export async function waitForSootsimIdle({
|
|
|
250
414
|
blockedBy:
|
|
251
415
|
(blockers.length ? blockers.join(', ') : 'unknown') +
|
|
252
416
|
' over ' + polls + ' polls (layout changed ' + layoutChangedPolls +
|
|
253
|
-
'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
|
|
417
|
+
'x, layoutDirty ' + dirtyPolls + 'x, animating ' + animatingPolls + 'x, webViewStarting ' + webViewStartingPolls + 'x, screen changed ' + screenChangedPolls + 'x)',
|
|
254
418
|
}
|
|
255
419
|
} finally {
|
|
256
420
|
unsubscribe?.()
|
|
257
421
|
}
|
|
258
422
|
})()`,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
timeoutMs: Math.max(5_000, maxMs + 2_000),
|
|
426
|
+
},
|
|
427
|
+
)
|
|
428
|
+
} catch (error) {
|
|
429
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
430
|
+
return {
|
|
431
|
+
settled: false,
|
|
432
|
+
elapsed: maxMs,
|
|
433
|
+
blockedBy: message,
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (
|
|
438
|
+
result?.error === 'runtime_readiness_unsupported' &&
|
|
439
|
+
typeof result.runtimeVersion === 'string' &&
|
|
440
|
+
Array.isArray(result.missingFields) &&
|
|
441
|
+
result.missingFields.every((field: unknown) => typeof field === 'string')
|
|
442
|
+
) {
|
|
443
|
+
throw new RuntimeReadinessUnsupportedError(
|
|
444
|
+
result.runtimeVersion,
|
|
445
|
+
result.missingFields,
|
|
446
|
+
)
|
|
447
|
+
}
|
|
264
448
|
|
|
265
449
|
const { elapsed, settled, blockedBy } = (result ??
|
|
266
450
|
{}) as Partial<WaitForSootsimIdleResult>
|
|
@@ -299,6 +483,7 @@ export async function waitReadyAndSettle(
|
|
|
299
483
|
})
|
|
300
484
|
let idle: WaitForSootsimIdleResult | null = null
|
|
301
485
|
for (;;) {
|
|
486
|
+
idle = null
|
|
302
487
|
const ready = await inspectWaitReady(bridge, remaining(), options)
|
|
303
488
|
if (!ready.ready) return result(ready, idle)
|
|
304
489
|
idle = await waitForSootsimIdle({
|
|
@@ -4,8 +4,9 @@ import { waitForSootsimIdle } from './settling'
|
|
|
4
4
|
import type { WsBridge } from '../../ws-bridge'
|
|
5
5
|
|
|
6
6
|
// alias for `do settle` under the discoverable `wait` verb grouping.
|
|
7
|
-
//
|
|
8
|
-
//
|
|
7
|
+
// worker stillness plus mounted-root membership; budgets of a second or
|
|
8
|
+
// more also confirm the mounted geometry. --strict also requires shell
|
|
9
|
+
// motion clear (alerts, sheets, menus) and blocking animation stats.
|
|
9
10
|
export async function runWaitIdleSubcommand(opts: {
|
|
10
11
|
bridge: WsBridge
|
|
11
12
|
args: string[]
|