agent-device 0.20.9 → 0.21.0
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 +2 -2
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.apk → agent-device-android-ime-helper-0.21.0.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.0.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.manifest.json → agent-device-android-ime-helper-0.21.0.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.manifest.json → agent-device-android-snapshot-helper-0.21.0.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AudioProbe.swift +35 -33
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +6 -1
- package/apple/snapshot-bridge/LICENSE.idb +23 -0
- package/apple/snapshot-bridge/README.md +49 -0
- package/apple/snapshot-bridge/SnapshotBridge.m +280 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +33 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +382 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +58 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAlertVerification.swift +36 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerStringNormalization.swift +8 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +12 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +100 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +2 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +21 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -88
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +124 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +110 -107
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +6 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +85 -114
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +13 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +72 -175
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +10 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXElementTypes.swift +12 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +78 -64
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +17 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +47 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +232 -438
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +98 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +229 -168
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationInvariant.swift +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +110 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +147 -25
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +21 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +24 -307
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +158 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +49 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +2 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +4 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -20
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +111 -0
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +42 -81
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +35 -82
- package/dist/apple/snapshot-presentation/Package.swift +21 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +56 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +259 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentation.swift +153 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationFailure.swift +27 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +91 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +161 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotScopePolicy.swift +53 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +242 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +97 -0
- package/dist/src/adapter.js +1 -0
- package/dist/src/adb-executor.js +2 -0
- package/dist/src/adb-failure.js +1 -0
- package/dist/src/adb-host.js +1 -0
- package/dist/src/adb.js +1 -0
- package/dist/src/agent-browser-lifecycle.js +1 -0
- package/dist/src/agent-browser-process-record.js +1 -0
- package/dist/src/agent-browser-provider.js +1 -0
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.d.ts +61 -0
- package/dist/src/ai-sdk.js +1 -0
- package/dist/src/alert-contract.js +1 -0
- package/dist/src/alert-runtime.js +1 -0
- package/dist/src/android-adb.d.ts +27 -19
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-ownership.js +1 -0
- package/dist/src/android-system-chrome.js +1 -0
- package/dist/src/android.js +1 -1
- package/dist/src/api.js +11 -0
- package/dist/src/app-catalog.js +1 -0
- package/dist/src/app-deployment-resolution.js +2 -0
- package/dist/src/app-helpers.js +1 -1
- package/dist/src/app-inventory-contract.js +1 -0
- package/dist/src/app-inventory.js +1 -0
- package/dist/src/app-launch.js +2 -0
- package/dist/src/app-lifecycle-facade.js +1 -0
- package/dist/src/app-lifecycle.js +3 -6
- package/dist/src/app-lifecycle2.js +2 -2
- package/dist/src/app-lifecycle3.js +1 -0
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +1 -4
- package/dist/src/app-log-runtime2.js +4 -0
- package/dist/src/app-parsers.js +4 -0
- package/dist/src/app-resolution-cache.js +1 -0
- package/dist/src/app-resolution-facade.js +1 -0
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/app-state.js +1 -2
- package/dist/src/application-lifecycle-interaction.js +1 -0
- package/dist/src/application-lifecycle-runtime.js +1 -0
- package/dist/src/apps-simctl.js +1 -0
- package/dist/src/archive.js +4 -0
- package/dist/src/artifact-download.js +1 -0
- package/dist/src/artifacts.d.ts +6 -2
- package/dist/src/artifacts.js +1 -1
- package/dist/src/async-lifecycle.js +1 -0
- package/dist/src/audio-probe-result.js +1 -0
- package/dist/src/audio-probe-runtime.js +1 -0
- package/dist/src/audio-probe-support.js +1 -0
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/back-mode.js +1 -0
- package/dist/src/{url.js → base-url.js} +1 -1
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/byte-limit-stream.js +1 -1
- package/dist/src/capabilities.js +1 -0
- package/dist/src/capture.js +1 -0
- package/dist/src/catalog.js +1 -0
- package/dist/src/cli-command-aliases.js +1 -0
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +77 -51
- package/dist/src/cli-output.js +1 -1
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +5 -7
- package/dist/src/click-button.js +1 -0
- package/dist/src/client-metro-companion.js +1 -0
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +1606 -0
- package/dist/src/clipboard.js +1 -0
- package/dist/src/code-signature-cache.js +1 -0
- package/dist/src/code-signature.js +1 -0
- package/dist/src/color.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-surface.js +1 -1
- package/dist/src/command-tools.js +2 -0
- package/dist/src/command.js +1 -0
- package/dist/src/{selector-vocabulary.js → compatibility-policy.js} +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/config2.js +1 -0
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +5 -5
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -0
- package/dist/src/daemon-process.js +1 -0
- package/dist/src/daemon-registration.js +1 -0
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +2 -2
- package/dist/src/debug-symbols-facade.js +5 -0
- package/dist/src/deploy-result-target.js +1 -0
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -0
- package/dist/src/device-input-state.d.ts +190 -3
- package/dist/src/device-inventory-context.js +1 -0
- package/dist/src/device-isolation.js +1 -0
- package/dist/src/device-release.js +1 -0
- package/dist/src/device-rotation.js +1 -0
- package/dist/src/device-selection-resolver.js +1 -0
- package/dist/src/device-session.js +1 -0
- package/dist/src/device.js +1 -1
- package/dist/src/device2.js +3 -2
- package/dist/src/diagnostics.js +3 -0
- package/dist/src/diagnostics2.js +1 -0
- package/dist/src/dispatch-resolve.js +1 -0
- package/dist/src/doctor-facade.js +1 -0
- package/dist/src/doctor-output.js +1 -0
- package/dist/src/doctor.js +1 -0
- package/dist/src/doctor2.js +1 -0
- package/dist/src/doctor3.js +1 -0
- package/dist/src/durable-resource.js +1 -0
- package/dist/src/entities.js +1 -1
- package/dist/src/error.js +2 -0
- package/dist/src/exec.js +1 -0
- package/dist/src/file.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/format.js +2 -0
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-admission.js +1 -0
- package/dist/src/gesture-plan-types.js +1 -0
- package/dist/src/gesture-plan.js +1 -0
- package/dist/src/gesture-runtime.js +1 -0
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/hdc.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/host-file.js +1 -0
- package/dist/src/human-control-contract.js +1 -0
- package/dist/src/human-control.js +1 -0
- package/dist/src/index.d.ts +2 -1578
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -4
- package/dist/src/input-actions2.js +2 -1
- package/dist/src/install-artifact-facade.js +1 -0
- package/dist/src/install-source-network-transport.js +1 -0
- package/dist/src/install-source.d.ts +3 -10
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-positionals.js +1 -0
- package/dist/src/interaction-ref-policy.js +1 -0
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-catalog.js +1 -0
- package/dist/src/interactor-types.js +1 -0
- package/dist/src/interactor.js +6 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.d.ts +1 -1
- package/dist/src/internal/bin.js +1 -2
- package/dist/src/internal/companion-tunnel.d.ts +1 -1
- package/dist/src/internal/companion-tunnel.js +1 -1
- package/dist/src/internal/daemon.d.ts +1 -1
- package/dist/src/internal/daemon.js +2 -4
- package/dist/src/internal/png-worker.d.ts +4 -4
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.d.ts +4 -0
- package/dist/src/internal/run-script-http-child.js +1 -0
- package/dist/src/internal/update-check-entry.d.ts +1 -1
- package/dist/src/inventory.js +4 -4
- package/dist/src/inventory2.js +1 -1
- package/dist/src/inventory3.js +1 -1
- package/dist/src/inventory5.js +1 -1
- package/dist/src/inventory6.js +1 -1
- package/dist/src/ios-client.js +16 -0
- package/dist/src/ios-snapshot-acquisition.js +1 -0
- package/dist/src/ios-snapshot-adapter.js +1 -0
- package/dist/src/ios-snapshot-planning.js +1 -0
- package/dist/src/ios-snapshot-runtime.js +1 -0
- package/dist/src/json.js +1 -0
- package/dist/src/keyboard-actions.js +1 -0
- package/dist/src/launch-console.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease-scope.js +1 -0
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +1618 -7
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/local-interactor-operation-set.js +1 -0
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/logcat.js +1 -1
- package/dist/src/macos-facade.js +1 -0
- package/dist/src/managed-device-scope.js +1 -0
- package/dist/src/mechanics.js +19 -0
- package/dist/src/metro.d.ts +4 -2
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -1
- package/dist/src/mobile-snapshot-semantics.js +1 -0
- package/dist/src/multitouch-support.js +1 -0
- package/dist/src/numeric.js +1 -0
- package/dist/src/observability.js +1 -1
- package/dist/src/observation.js +2 -0
- package/dist/src/output-path.js +1 -1
- package/dist/src/owner-identity.js +3 -1
- package/dist/src/parameterized-recorded-fill.js +1 -0
- package/dist/src/parser.js +1 -1
- package/dist/src/perf-facade.js +2 -0
- package/dist/src/perf-runtime-operation-builder.js +1 -0
- package/dist/src/perf-runtime-plan.js +1 -0
- package/dist/src/perf-runtime.js +1 -0
- package/dist/src/perf.js +1 -4
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/physical-device-facade.js +1 -0
- package/dist/src/platform-request-scope.js +1 -0
- package/dist/src/platform-runtime-android-adb-host.js +1 -0
- package/dist/src/platform-runtime-android-mechanics.js +1 -0
- package/dist/src/platform-runtime-app-log-android-transport.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-apple-resources.js +1 -0
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-managed-owner.js +1 -0
- package/dist/src/platform-runtime-network-web-transport.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +4 -4
- package/dist/src/platform-runtime-runtime-hints.js +2 -2
- package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -0
- package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -0
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/plist.js +1 -1
- package/dist/src/png-worker-contract.js +1 -1
- package/dist/src/prepare-kind.js +1 -15
- package/dist/src/process-exit.js +1 -1
- package/dist/src/process.js +1 -0
- package/dist/src/provider-device-runtime.js +1 -0
- package/dist/src/provider-session-ownership.js +2 -0
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/provider.js +1 -1
- package/dist/src/providers.js +1 -0
- package/dist/src/proxy.js +2 -2
- package/dist/src/react-native-overlay.js +1 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/record-trace.js +1 -1
- package/dist/src/rect-center.js +1 -0
- package/dist/src/register-builtins.js +1 -0
- package/dist/src/registry.js +39 -28
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +2 -0
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +8 -8
- package/dist/src/request-admission.js +1 -0
- package/dist/src/request-cancel.js +1 -0
- package/dist/src/request-cancellation.js +1 -0
- package/dist/src/request-progress-protocol.js +1 -0
- package/dist/src/request-providers.js +1 -0
- package/dist/src/request-runtime-binding.js +1 -0
- package/dist/src/request.js +1 -0
- package/dist/src/result-serialization.js +1 -0
- package/dist/src/retry.js +1 -0
- package/dist/src/rolldown-runtime.js +1 -1
- package/dist/src/runner-cache-metadata.js +2 -0
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -0
- package/dist/src/runner-owner-facade.js +1 -0
- package/dist/src/runner-owner-state.js +1 -0
- package/dist/src/runner-presentation.js +1 -0
- package/dist/src/runner-selector-query.js +1 -0
- package/dist/src/runner.js +1 -0
- package/dist/src/{runtime-transport.js → runtime-transport-hints.js} +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +4 -3
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/scoped-provider.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -0
- package/dist/src/screen-recording-live-handle.js +1 -0
- package/dist/src/screen-recording-options.js +1 -0
- package/dist/src/screen-recording-resource-recovery.js +1 -0
- package/dist/src/screen-recording-runtime.js +1 -0
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-result.js +1 -6
- package/dist/src/screenshot-runtime.js +1 -0
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot2.js +1 -0
- package/dist/src/screenshot3.js +5 -0
- package/dist/src/script.js +1 -0
- package/dist/src/scroll-command.js +1 -0
- package/dist/src/scroll-gesture.js +1 -0
- package/dist/src/scroll-indicator.js +1 -0
- package/dist/src/sdk-batch-runner.d.ts +23 -6
- package/dist/src/sdk-batch-runner.js +2 -3
- package/dist/src/sdk-batch.js +2 -0
- package/dist/src/sdk-contracts.d.ts +222 -99
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +539 -199
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selection.js +1 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/semantic-index.js +1 -0
- package/dist/src/server.js +10 -3
- package/dist/src/session-allocation.js +1 -0
- package/dist/src/session-artifact-paths.js +1 -0
- package/dist/src/session-paths.js +1 -0
- package/dist/src/session-repair-tombstone.js +1 -0
- package/dist/src/session-routing.js +1 -0
- package/dist/src/session-runtime-admission.js +1 -0
- package/dist/src/session-snapshot.js +1 -0
- package/dist/src/session-store.js +4 -0
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session2.js +5 -28
- package/dist/src/settings.js +1 -0
- package/dist/src/shared.js +2 -2
- package/dist/src/simctl-facade.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-facade.js +1 -0
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-capture-annotations.js +1 -0
- package/dist/src/snapshot-desktop-projection.js +1 -0
- package/dist/src/snapshot-diagnostics.js +1 -0
- package/dist/src/snapshot-process.js +1 -0
- package/dist/src/snapshot-quality-backend-capabilities.js +1 -0
- package/dist/src/snapshot-quality-verdict.js +1 -0
- package/dist/src/snapshot-runtime-binding.js +1 -0
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-scope.js +1 -0
- package/dist/src/snapshot-state.js +1 -0
- package/dist/src/snapshot.js +1 -8
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -0
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -2
- package/dist/src/src4.js +1 -0
- package/dist/src/src5.js +1 -0
- package/dist/src/src6.js +1 -0
- package/dist/src/src7.js +2 -0
- package/dist/src/src8.js +115 -0
- package/dist/src/startup-recovery-fence.js +1 -0
- package/dist/src/status-markers.js +1 -0
- package/dist/src/string-enum.js +1 -1
- package/dist/src/success-text.js +1 -0
- package/dist/src/surface-snapshot.js +1 -0
- package/dist/src/surface-snapshot2.js +1 -0
- package/dist/src/takeover.js +5 -0
- package/dist/src/tool-provider-facade.js +1 -0
- package/dist/src/tool-provider.js +4 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/toolchain-probe.js +2 -0
- package/dist/src/touch-runtime.js +1 -0
- package/dist/src/transport.js +3 -0
- package/dist/src/tree.js +1 -0
- package/dist/src/ttl-memo.js +1 -0
- package/dist/src/tv-remote.js +1 -0
- package/dist/src/type-text-runtime.js +1 -0
- package/dist/src/undici.js +99 -0
- package/dist/src/update-check.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/video.js +2 -2
- package/dist/src/web.js +2 -1
- package/dist/src/web2.js +1 -0
- package/dist/src/webdriver-ios-snapshot.js +1 -0
- package/dist/src/webdriver-source.js +1 -0
- package/linux/atspi-dump.py +54 -9
- package/package.json +73 -38
- package/server.json +9 -3
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +0 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CoordinateTextEntryTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -75
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +0 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+RecordingTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SelectorMatchPolicyTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryPolicyTests.swift +0 -4
- package/dist/src/appearance.js +0 -1
- package/dist/src/apps.js +0 -5
- package/dist/src/audio-probe.js +0 -1
- package/dist/src/cancel.js +0 -1
- package/dist/src/cli-grammar.js +0 -1
- package/dist/src/command-catalog.js +0 -1
- package/dist/src/debug-symbols.js +0 -5
- package/dist/src/device-input-state.js +0 -2
- package/dist/src/device-ready.js +0 -1
- package/dist/src/dispatch.js +0 -1
- package/dist/src/handler-utils.js +0 -1
- package/dist/src/helper-package-install.js +0 -1
- package/dist/src/host-process.js +0 -3
- package/dist/src/ime-lifecycle.js +0 -2
- package/dist/src/ime-recovery-marker.js +0 -1
- package/dist/src/input-actions3.js +0 -1
- package/dist/src/install-artifact.js +0 -1
- package/dist/src/install-artifact2.js +0 -1
- package/dist/src/interaction-common.js +0 -1
- package/dist/src/interaction-runtime.js +0 -1
- package/dist/src/interaction-snapshot.js +0 -1
- package/dist/src/manifest.js +0 -1
- package/dist/src/method-scope.js +0 -1
- package/dist/src/png-resize.js +0 -1
- package/dist/src/process-lock.js +0 -1
- package/dist/src/runner-lease.js +0 -1
- package/dist/src/runner-sequence.js +0 -1
- package/dist/src/screenshot-geometry.js +0 -1
- package/dist/src/sdk-android-adb.d.ts +0 -245
- package/dist/src/sdk-android-adb.js +0 -4
- package/dist/src/sdk.js +0 -1
- package/dist/src/setting-state.js +0 -1
- package/dist/src/shell-quote.js +0 -1
- package/dist/src/snapshot-session.js +0 -1
- package/dist/src/timing-safe-equal.js +0 -1
- package/dist/src/unsupported-interactor.js +0 -1
- package/dist/src/verdict.js +0 -1
- /package/dist/src/{recording-telemetry.js → telemetry.js} +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
|
|
3
|
+
enum SnapshotBackendEnvironment {
|
|
4
|
+
case simulator
|
|
5
|
+
case physicalDevice
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
enum SnapshotRegularDepthCapability: String {
|
|
9
|
+
/// The backend can stop acquisition at the requested regular presented-depth frontier.
|
|
10
|
+
case presentedFrontier = "presented-frontier"
|
|
11
|
+
/// The backend is flat; it can answer the root and one presented level, but has no hierarchy
|
|
12
|
+
/// from which to prove deeper regular depth.
|
|
13
|
+
case flat
|
|
14
|
+
/// The backend can return raw traversal depth, but cannot prove regular presented depth.
|
|
15
|
+
case rawOnly = "raw-only"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
enum SnapshotBackendKind: String, CaseIterable {
|
|
19
|
+
case recursiveTree = "tree"
|
|
20
|
+
case querySweep = "queries"
|
|
21
|
+
case privateAX = "private-ax"
|
|
22
|
+
|
|
23
|
+
var isForceable: Bool {
|
|
24
|
+
switch self {
|
|
25
|
+
case .recursiveTree, .privateAX:
|
|
26
|
+
return true
|
|
27
|
+
case .querySweep:
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var hittableSemantics: String {
|
|
33
|
+
"geometric-actionability"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var usesXCTestAccessibilityChannel: Bool {
|
|
37
|
+
switch self {
|
|
38
|
+
case .recursiveTree, .querySweep:
|
|
39
|
+
return true
|
|
40
|
+
case .privateAX:
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// The raw projection is the acquired tree, so only a backend that enumerates a hierarchy can
|
|
46
|
+
/// serve it. The query sweep answers an interactive element query: it has no hierarchy to
|
|
47
|
+
/// return, and planning it for `--raw` is exactly how a raw request gets answered with regular
|
|
48
|
+
/// membership.
|
|
49
|
+
var supportsRawProjection: Bool {
|
|
50
|
+
switch self {
|
|
51
|
+
case .recursiveTree, .privateAX:
|
|
52
|
+
return true
|
|
53
|
+
case .querySweep:
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var regularDepthCapability: SnapshotRegularDepthCapability {
|
|
59
|
+
switch self {
|
|
60
|
+
case .recursiveTree:
|
|
61
|
+
return .presentedFrontier
|
|
62
|
+
case .querySweep:
|
|
63
|
+
return .flat
|
|
64
|
+
case .privateAX:
|
|
65
|
+
return .rawOnly
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func canServeRegularPresentedDepth(_ requestedDepth: Int?) -> Bool {
|
|
70
|
+
guard let requestedDepth else { return true }
|
|
71
|
+
switch regularDepthCapability {
|
|
72
|
+
case .presentedFrontier:
|
|
73
|
+
return true
|
|
74
|
+
case .flat:
|
|
75
|
+
return requestedDepth <= 1
|
|
76
|
+
case .rawOnly:
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
var isAvailableOnCurrentPlatform: Bool {
|
|
82
|
+
#if os(iOS) && targetEnvironment(simulator)
|
|
83
|
+
return isAvailable(on: .simulator)
|
|
84
|
+
#else
|
|
85
|
+
return isAvailable(on: .physicalDevice)
|
|
86
|
+
#endif
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func isAvailable(on environment: SnapshotBackendEnvironment) -> Bool {
|
|
90
|
+
switch self {
|
|
91
|
+
case .recursiveTree, .querySweep:
|
|
92
|
+
return true
|
|
93
|
+
case .privateAX:
|
|
94
|
+
return environment == .simulator
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import XCTest
|
|
2
|
+
import AgentDeviceSnapshotPresentation
|
|
2
3
|
|
|
3
4
|
// MARK: - Snapshot capture plans (ADR 0004)
|
|
4
5
|
//
|
|
@@ -14,9 +15,11 @@ struct SnapshotQuality: Codable {
|
|
|
14
15
|
let state: String
|
|
15
16
|
/// Backend that produced the returned payload: tree | queries | private-ax.
|
|
16
17
|
let backend: String
|
|
17
|
-
/// Why recovery ran (first failure)
|
|
18
|
+
/// Why recovery ran (first failure), why the payload is degraded, or why an internal backend
|
|
19
|
+
/// selection was honored.
|
|
18
20
|
let reason: String?
|
|
19
|
-
/// Machine-readable reason: ax-rejected | sparse-tree | budget | no-nodes
|
|
21
|
+
/// Machine-readable reason: ax-rejected | sparse-tree | budget | no-nodes | capture-failed |
|
|
22
|
+
/// presentation-failed | deferred | requested-backend.
|
|
20
23
|
let reasonCode: String?
|
|
21
24
|
/// Private AX ladder cap when the accepted tree is shallower than requested.
|
|
22
25
|
let effectiveDepth: Int?
|
|
@@ -24,49 +27,8 @@ struct SnapshotQuality: Codable {
|
|
|
24
27
|
let collapsedLeafIndexes: [Int]?
|
|
25
28
|
/// Coverage of the bounded custom-action pass, when the capture asked for one.
|
|
26
29
|
let customActions: SnapshotCustomActionCoverage?
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/// How much of the merged-element set the custom-action pass actually read. An
|
|
30
|
-
/// unread element renders exactly like one with no actions, so a partial pass
|
|
31
|
-
/// has to say so — otherwise absence reads as proof of absence.
|
|
32
|
-
struct SnapshotCustomActionCoverage: Codable {
|
|
33
|
-
let read: Int
|
|
34
|
-
let candidates: Int
|
|
35
|
-
/// Elements whose action list was clipped by the per-element output caps. A
|
|
36
|
-
/// clipped list looks complete, so it is disclosed on the same principle as
|
|
37
|
-
/// an unread element.
|
|
38
|
-
let truncated: Int
|
|
39
|
-
/// The pass stopped early because an earlier read is still hung. Distinct from
|
|
40
|
-
/// a budget stop: the remedy is waiting, not scrolling.
|
|
41
|
-
let blocked: Bool
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
enum SnapshotBackendKind: String, CaseIterable {
|
|
45
|
-
case recursiveTree = "tree"
|
|
46
|
-
case querySweep = "queries"
|
|
47
|
-
case privateAX = "private-ax"
|
|
48
|
-
|
|
49
|
-
var usesXCTestAccessibilityChannel: Bool {
|
|
50
|
-
switch self {
|
|
51
|
-
case .recursiveTree, .querySweep:
|
|
52
|
-
return true
|
|
53
|
-
case .privateAX:
|
|
54
|
-
return false
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
var isAvailableOnCurrentPlatform: Bool {
|
|
59
|
-
switch self {
|
|
60
|
-
case .recursiveTree, .querySweep:
|
|
61
|
-
return true
|
|
62
|
-
case .privateAX:
|
|
63
|
-
#if os(iOS) && targetEnvironment(simulator)
|
|
64
|
-
return true
|
|
65
|
-
#else
|
|
66
|
-
return false
|
|
67
|
-
#endif
|
|
68
|
-
}
|
|
69
|
-
}
|
|
30
|
+
/// Response-level timing for the accepted backend attempt, never repeated per node.
|
|
31
|
+
var timing: SnapshotCaptureTiming? = nil
|
|
70
32
|
}
|
|
71
33
|
|
|
72
34
|
enum SnapshotXCTestChannelPlanState: Equatable {
|
|
@@ -79,6 +41,9 @@ struct EffectiveSnapshotCapturePlan {
|
|
|
79
41
|
let plan: [SnapshotBackendKind]
|
|
80
42
|
let xCTestChannelState: SnapshotXCTestChannelPlanState
|
|
81
43
|
let treeCaptureSliceBudgetOverride: TimeInterval?
|
|
44
|
+
/// Non-nil only when the plan was narrowed by an explicit internal backend preference. This
|
|
45
|
+
/// keeps the quality marker tied to the plan decision rather than to an untrusted request field.
|
|
46
|
+
let preferredBackend: SnapshotBackendKind?
|
|
82
47
|
}
|
|
83
48
|
|
|
84
49
|
/// What the plan runner does when every backend failed or stayed sparse.
|
|
@@ -93,13 +58,26 @@ enum SnapshotCaptureTerminalPolicy {
|
|
|
93
58
|
|
|
94
59
|
struct SnapshotBackendCapture {
|
|
95
60
|
let payload: DataPayload
|
|
96
|
-
/// Set by the private AX backend when the ladder accepted a shallower depth than requested.
|
|
97
61
|
let effectiveDepth: Int?
|
|
98
|
-
/// Set by the private AX backend when the capture asked for custom actions.
|
|
99
62
|
var customActions: SnapshotCustomActionCoverage? = nil
|
|
63
|
+
var qualityPayload: DataPayload? = nil
|
|
64
|
+
var timing: SnapshotCaptureTiming? = nil
|
|
100
65
|
}
|
|
101
66
|
|
|
102
67
|
extension RunnerTests {
|
|
68
|
+
static func makeSnapshotBackendCapture(
|
|
69
|
+
from result: AgentDeviceSnapshotPresentation.SnapshotPresentationResult
|
|
70
|
+
) -> SnapshotBackendCapture {
|
|
71
|
+
SnapshotBackendCapture(
|
|
72
|
+
payload: DataPayload(nodes: result.nodes, truncated: result.truncated),
|
|
73
|
+
effectiveDepth: result.effectiveDepth,
|
|
74
|
+
customActions: result.customActions,
|
|
75
|
+
qualityPayload: result.qualityNodes.map {
|
|
76
|
+
DataPayload(nodes: $0, truncated: result.truncated)
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
103
81
|
static let sparseRecoveryTruncatedNodeThreshold = 8
|
|
104
82
|
/// Umbrella wall-clock budget for one capture plan. Individual backends bound themselves,
|
|
105
83
|
/// but chained recovery tiers must never stack past the 30s main-thread watchdog: when the
|
|
@@ -115,7 +93,10 @@ extension RunnerTests {
|
|
|
115
93
|
// MARK: Plan definitions
|
|
116
94
|
|
|
117
95
|
static let regularVisiblePlan: [SnapshotBackendKind] = [.recursiveTree, .querySweep, .privateAX]
|
|
118
|
-
|
|
96
|
+
/// Derived from the backend trait rather than hand-listed: a backend that cannot serve the raw
|
|
97
|
+
/// projection drops out of the raw plan by construction, and a new one joins it by declaring the
|
|
98
|
+
/// trait instead of by someone remembering this line.
|
|
99
|
+
static let rawDiagnosticPlan: [SnapshotBackendKind] = regularVisiblePlan.filter(\.supportsRawProjection)
|
|
119
100
|
|
|
120
101
|
// MARK: XCTest accessibility channel penalty (cross-attempt memory, #1105/#1156)
|
|
121
102
|
//
|
|
@@ -175,8 +156,15 @@ extension RunnerTests {
|
|
|
175
156
|
/// cause that does not exist.
|
|
176
157
|
static func xcTestChannelStateFirstFailure(
|
|
177
158
|
_ state: SnapshotXCTestChannelPlanState,
|
|
178
|
-
requestPinnedBackend: Bool = false
|
|
159
|
+
requestPinnedBackend: Bool = false,
|
|
160
|
+
preferredBackend: String? = nil
|
|
179
161
|
) -> (reason: String, code: String)? {
|
|
162
|
+
if state == .normal && preferredBackend == SnapshotBackendKind.recursiveTree.rawValue {
|
|
163
|
+
return (
|
|
164
|
+
"the recursive XCTest tree backend was explicitly selected for this capture",
|
|
165
|
+
"requested-backend"
|
|
166
|
+
)
|
|
167
|
+
}
|
|
180
168
|
switch state {
|
|
181
169
|
case .normal:
|
|
182
170
|
return nil
|
|
@@ -210,19 +198,36 @@ extension RunnerTests {
|
|
|
210
198
|
penalized || preferredBackend == SnapshotBackendKind.privateAX.rawValue
|
|
211
199
|
}
|
|
212
200
|
|
|
213
|
-
/// Pure plan-reorder rule:
|
|
214
|
-
///
|
|
215
|
-
///
|
|
201
|
+
/// Pure plan-reorder rule: an internal preferred backend pins the regular plan to that backend;
|
|
202
|
+
/// this is the only force seam used by same-backend evidence and conformance captures. A
|
|
203
|
+
/// penalized XCTest accessibility channel uses independent backends when the platform has one,
|
|
204
|
+
/// otherwise it keeps XCTest work on a short probe. The raw diagnostic plan keeps tree-first
|
|
205
|
+
/// errors, and unknown plans are left untouched.
|
|
216
206
|
static func effectiveSnapshotCapturePlan(
|
|
217
207
|
_ plan: [SnapshotBackendKind],
|
|
218
208
|
xCTestChannelPenalized: Bool,
|
|
219
|
-
availableBackends: Set<SnapshotBackendKind> = Set(SnapshotBackendKind.allCases)
|
|
209
|
+
availableBackends: Set<SnapshotBackendKind> = Set(SnapshotBackendKind.allCases),
|
|
210
|
+
preferredBackend: String? = nil
|
|
220
211
|
) -> EffectiveSnapshotCapturePlan {
|
|
212
|
+
if
|
|
213
|
+
plan == Self.regularVisiblePlan,
|
|
214
|
+
let preferred = preferredBackend.flatMap(SnapshotBackendKind.init(rawValue:)),
|
|
215
|
+
preferred.isForceable,
|
|
216
|
+
availableBackends.contains(preferred)
|
|
217
|
+
{
|
|
218
|
+
return EffectiveSnapshotCapturePlan(
|
|
219
|
+
plan: [preferred],
|
|
220
|
+
xCTestChannelState: preferred == .privateAX ? .deferredToIndependentBackend : .normal,
|
|
221
|
+
treeCaptureSliceBudgetOverride: nil,
|
|
222
|
+
preferredBackend: preferred
|
|
223
|
+
)
|
|
224
|
+
}
|
|
221
225
|
guard xCTestChannelPenalized, plan == Self.regularVisiblePlan else {
|
|
222
226
|
return EffectiveSnapshotCapturePlan(
|
|
223
227
|
plan: plan,
|
|
224
228
|
xCTestChannelState: .normal,
|
|
225
|
-
treeCaptureSliceBudgetOverride: nil
|
|
229
|
+
treeCaptureSliceBudgetOverride: nil,
|
|
230
|
+
preferredBackend: nil
|
|
226
231
|
)
|
|
227
232
|
}
|
|
228
233
|
let availablePlan = plan.filter { availableBackends.contains($0) }
|
|
@@ -231,13 +236,15 @@ extension RunnerTests {
|
|
|
231
236
|
return EffectiveSnapshotCapturePlan(
|
|
232
237
|
plan: recoveryPlan,
|
|
233
238
|
xCTestChannelState: .deferredToIndependentBackend,
|
|
234
|
-
treeCaptureSliceBudgetOverride: nil
|
|
239
|
+
treeCaptureSliceBudgetOverride: nil,
|
|
240
|
+
preferredBackend: nil
|
|
235
241
|
)
|
|
236
242
|
}
|
|
237
243
|
return EffectiveSnapshotCapturePlan(
|
|
238
244
|
plan: availablePlan.filter(\.usesXCTestAccessibilityChannel),
|
|
239
245
|
xCTestChannelState: .boundedXCTestProbe,
|
|
240
|
-
treeCaptureSliceBudgetOverride: Self.penalizedXCTestProbeTreeSliceBudget
|
|
246
|
+
treeCaptureSliceBudgetOverride: Self.penalizedXCTestProbeTreeSliceBudget,
|
|
247
|
+
preferredBackend: nil
|
|
241
248
|
)
|
|
242
249
|
}
|
|
243
250
|
|
|
@@ -250,7 +257,7 @@ extension RunnerTests {
|
|
|
250
257
|
func runSnapshotCapturePlan(
|
|
251
258
|
_ plan: [SnapshotBackendKind],
|
|
252
259
|
app: XCUIApplication,
|
|
253
|
-
options:
|
|
260
|
+
options: PresentationOptions,
|
|
254
261
|
terminal: SnapshotCaptureTerminalPolicy,
|
|
255
262
|
deadline: Date? = nil
|
|
256
263
|
) throws -> DataPayload {
|
|
@@ -279,14 +286,16 @@ extension RunnerTests {
|
|
|
279
286
|
let effective = Self.effectiveSnapshotCapturePlan(
|
|
280
287
|
plan,
|
|
281
288
|
xCTestChannelPenalized: xCTestChannelPenalized,
|
|
282
|
-
availableBackends: Set(SnapshotBackendKind.allCases.filter(\.isAvailableOnCurrentPlatform))
|
|
289
|
+
availableBackends: Set(SnapshotBackendKind.allCases.filter(\.isAvailableOnCurrentPlatform)),
|
|
290
|
+
preferredBackend: options.preferredBackend
|
|
283
291
|
)
|
|
284
292
|
let effectivePlan = effective.plan
|
|
285
293
|
// Only a customActions-implied pin is request-pinned; the daemon's
|
|
286
294
|
// same-backend evidence probe pins for its own reasons and keeps 'deferred'.
|
|
287
295
|
firstFailure = Self.xcTestChannelStateFirstFailure(
|
|
288
296
|
effective.xCTestChannelState,
|
|
289
|
-
requestPinnedBackend: options.customActions && !xCTestChannelPenalizedByBreaker
|
|
297
|
+
requestPinnedBackend: options.customActions && !xCTestChannelPenalizedByBreaker,
|
|
298
|
+
preferredBackend: effective.preferredBackend?.rawValue
|
|
290
299
|
)
|
|
291
300
|
switch effective.xCTestChannelState {
|
|
292
301
|
case .normal:
|
|
@@ -317,45 +326,22 @@ extension RunnerTests {
|
|
|
317
326
|
}
|
|
318
327
|
continue
|
|
319
328
|
}
|
|
320
|
-
let
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
kind,
|
|
334
|
-
startedAt: backendStartedAt,
|
|
335
|
-
penaltySuppressed: suppressXCTestPenalty
|
|
336
|
-
)
|
|
337
|
-
continue
|
|
338
|
-
}
|
|
339
|
-
capture = result
|
|
340
|
-
recordSlowXCTestSnapshotBackendIfNeeded(
|
|
341
|
-
kind,
|
|
342
|
-
startedAt: backendStartedAt,
|
|
343
|
-
penaltySuppressed: suppressXCTestPenalty
|
|
344
|
-
)
|
|
345
|
-
} catch let failure as SnapshotCaptureFailure {
|
|
346
|
-
recordXCTestSnapshotBackendFailureIfNeeded(
|
|
347
|
-
kind,
|
|
348
|
-
failure: failure,
|
|
349
|
-
penaltySuppressed: suppressXCTestPenalty
|
|
350
|
-
)
|
|
351
|
-
recordSlowXCTestSnapshotBackendIfNeeded(
|
|
352
|
-
kind,
|
|
353
|
-
startedAt: backendStartedAt,
|
|
354
|
-
penaltySuppressed: suppressXCTestPenalty
|
|
355
|
-
)
|
|
329
|
+
let attempt = try captureWithBackend(
|
|
330
|
+
kind,
|
|
331
|
+
app: app,
|
|
332
|
+
options: options,
|
|
333
|
+
deadline: deadline,
|
|
334
|
+
treeCaptureSliceBudgetOverride: effective.treeCaptureSliceBudgetOverride
|
|
335
|
+
)
|
|
336
|
+
recordXCTestSnapshotBackendAttemptIfNeeded(
|
|
337
|
+
kind,
|
|
338
|
+
attempt: attempt,
|
|
339
|
+
penaltySuppressed: suppressXCTestPenalty
|
|
340
|
+
)
|
|
341
|
+
if case let .failed(failure, phase: _) = attempt.outcome {
|
|
356
342
|
if Self.isAxSnapshotFailure(failure) { axFailure = failure }
|
|
357
343
|
if firstFailure == nil {
|
|
358
|
-
firstFailure = (failure.message, Self.
|
|
344
|
+
firstFailure = (failure.message, Self.snapshotQualityReasonCode(for: failure))
|
|
359
345
|
}
|
|
360
346
|
NSLog(
|
|
361
347
|
"AGENT_DEVICE_RUNNER_SNAPSHOT_BACKEND_FAILED backend=%@ error=%@",
|
|
@@ -364,8 +350,9 @@ extension RunnerTests {
|
|
|
364
350
|
)
|
|
365
351
|
continue
|
|
366
352
|
}
|
|
353
|
+
guard case let .captured(capture) = attempt.outcome else { continue }
|
|
367
354
|
|
|
368
|
-
if let sparseReason = Self.sparsePayloadReason(capture.payload) {
|
|
355
|
+
if let sparseReason = Self.sparsePayloadReason(capture.qualityPayload ?? capture.payload) {
|
|
369
356
|
if firstFailure == nil { firstFailure = sparseReason }
|
|
370
357
|
if Self.payloadNodeCount(capture.payload) > Self.payloadNodeCount(best?.capture.payload) {
|
|
371
358
|
best = (kind, capture)
|
|
@@ -385,7 +372,7 @@ extension RunnerTests {
|
|
|
385
372
|
capture,
|
|
386
373
|
backend: kind,
|
|
387
374
|
state: recovered ? "recovered" : "healthy",
|
|
388
|
-
reason: recovered ? firstFailure : nil
|
|
375
|
+
reason: recovered || firstFailure?.code == "requested-backend" ? firstFailure : nil
|
|
389
376
|
)
|
|
390
377
|
}
|
|
391
378
|
|
|
@@ -419,77 +406,136 @@ extension RunnerTests {
|
|
|
419
406
|
return fallbackPayload
|
|
420
407
|
}
|
|
421
408
|
|
|
422
|
-
/// Marks XCTest-backed snapshot tiers as penalized when one attempt ground past the slow-capture
|
|
423
|
-
/// threshold — even a successful one: the next capture of this screen must not re-grind.
|
|
424
|
-
private func recordSlowXCTestSnapshotBackendIfNeeded(
|
|
425
|
-
_ kind: SnapshotBackendKind,
|
|
426
|
-
startedAt: Date,
|
|
427
|
-
penaltySuppressed: Bool
|
|
428
|
-
) {
|
|
429
|
-
guard !penaltySuppressed else { return }
|
|
430
|
-
guard kind.usesXCTestAccessibilityChannel else { return }
|
|
431
|
-
let elapsed = Date().timeIntervalSince(startedAt)
|
|
432
|
-
guard elapsed > snapshotXCTestSlowCaptureThreshold else { return }
|
|
433
|
-
penalizeSnapshotXCTestChannel(
|
|
434
|
-
bundleId: currentBundleId,
|
|
435
|
-
reason: "slow_\(kind.rawValue)_capture_\(Int(elapsed * 1000))ms"
|
|
436
|
-
)
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
private func recordXCTestSnapshotBackendFailureIfNeeded(
|
|
440
|
-
_ kind: SnapshotBackendKind,
|
|
441
|
-
failure: SnapshotCaptureFailure,
|
|
442
|
-
penaltySuppressed: Bool
|
|
443
|
-
) {
|
|
444
|
-
guard !penaltySuppressed else { return }
|
|
445
|
-
guard kind.usesXCTestAccessibilityChannel, failure.code == Self.xCTestSnapshotTimeoutCode else { return }
|
|
446
|
-
penalizeSnapshotXCTestChannel(
|
|
447
|
-
bundleId: currentBundleId,
|
|
448
|
-
reason: "\(kind.rawValue)_backend_timeout"
|
|
449
|
-
)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
409
|
private func captureWithBackend(
|
|
453
410
|
_ kind: SnapshotBackendKind,
|
|
454
411
|
app: XCUIApplication,
|
|
455
|
-
options:
|
|
412
|
+
options: PresentationOptions,
|
|
456
413
|
deadline: Date,
|
|
457
414
|
treeCaptureSliceBudgetOverride: TimeInterval?
|
|
458
|
-
) throws ->
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
)
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
415
|
+
) throws -> SnapshotBackendAttempt {
|
|
416
|
+
let hint = SnapshotPresentation.captureHint(for: options)
|
|
417
|
+
var timer = SnapshotPhaseTimer()
|
|
418
|
+
// Scoped depth is relative to a presentation-selected root, so its hint stays broad and the
|
|
419
|
+
// backend capability gate applies only to an unscoped regular frontier.
|
|
420
|
+
let requestedRegularDepth = options.raw || SnapshotScopePolicy.isActive(options.scope)
|
|
421
|
+
? nil
|
|
422
|
+
: options.depth
|
|
423
|
+
guard kind.canServeRegularPresentedDepth(requestedRegularDepth) else {
|
|
424
|
+
NSLog(
|
|
425
|
+
"AGENT_DEVICE_RUNNER_SNAPSHOT_BACKEND_DEPTH_UNSUPPORTED backend=%@ depth=%ld",
|
|
426
|
+
kind.rawValue,
|
|
427
|
+
requestedRegularDepth ?? -1
|
|
428
|
+
)
|
|
429
|
+
return SnapshotBackendAttempt(
|
|
430
|
+
outcome: .noCapture,
|
|
431
|
+
timing: timer.timing
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
let acquisition: SnapshotAcquisition?
|
|
435
|
+
do {
|
|
436
|
+
acquisition = try timer.measure(.acquisition) {
|
|
437
|
+
switch kind {
|
|
438
|
+
case .recursiveTree:
|
|
439
|
+
guard
|
|
440
|
+
let context = try self.makeSnapshotTraversalContext(
|
|
441
|
+
app: app,
|
|
442
|
+
hint: hint,
|
|
443
|
+
captureDeadline: deadline,
|
|
444
|
+
treeCaptureSliceBudgetOverride: treeCaptureSliceBudgetOverride
|
|
445
|
+
)
|
|
446
|
+
else {
|
|
447
|
+
return nil
|
|
448
|
+
}
|
|
449
|
+
return try self.runMainThreadWork(
|
|
450
|
+
timeout: min(self.treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
|
|
451
|
+
timeoutError: self.snapshotMainThreadTimeoutError("processing tree snapshot")
|
|
452
|
+
) {
|
|
453
|
+
hint.isRaw
|
|
454
|
+
? try self.rawTreeSnapshotAcquisition(context: context, hint: hint)
|
|
455
|
+
: self.recursiveTreeSnapshotAcquisition(context: context, hint: hint)
|
|
456
|
+
}
|
|
457
|
+
case .querySweep:
|
|
458
|
+
return try self.runMainThreadWork(
|
|
459
|
+
timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
|
|
460
|
+
timeoutError: self.snapshotMainThreadTimeoutError("running query-sweep snapshot")
|
|
461
|
+
) {
|
|
462
|
+
self.querySweepSnapshotAcquisition(
|
|
463
|
+
app: app,
|
|
464
|
+
hint: hint,
|
|
465
|
+
planDeadline: deadline
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
case .privateAX:
|
|
469
|
+
return self.privateAXSnapshotAcquisition(
|
|
470
|
+
app: app,
|
|
471
|
+
hint: hint,
|
|
472
|
+
deadline: deadline
|
|
473
|
+
)
|
|
474
|
+
}
|
|
479
475
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
476
|
+
} catch let failure as SnapshotCaptureFailure {
|
|
477
|
+
return SnapshotBackendAttempt(
|
|
478
|
+
outcome: .failed(failure, phase: .acquisition),
|
|
479
|
+
timing: timer.timing
|
|
480
|
+
)
|
|
481
|
+
}
|
|
482
|
+
guard let acquisition else {
|
|
483
|
+
return SnapshotBackendAttempt(
|
|
484
|
+
outcome: .noCapture,
|
|
485
|
+
timing: timer.timing
|
|
486
|
+
)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let presented: SnapshotBackendCapture
|
|
490
|
+
do {
|
|
491
|
+
presented = try timer.measure(.presentation) {
|
|
492
|
+
guard let result = try SnapshotPresentation.present(acquisition, options: options) else {
|
|
493
|
+
NSLog(
|
|
494
|
+
"AGENT_DEVICE_RUNNER_SNAPSHOT_PROJECTION_MISMATCH requested=%@ acquired=%@",
|
|
495
|
+
hint.projection.rawValue,
|
|
496
|
+
acquisition.hint.projection.rawValue
|
|
497
|
+
)
|
|
498
|
+
throw Self.snapshotProjectionMismatchFailure(
|
|
499
|
+
kind,
|
|
500
|
+
requested: hint.projection,
|
|
501
|
+
acquired: acquisition.hint.projection
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
return Self.makeSnapshotBackendCapture(from: result)
|
|
488
505
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
506
|
+
} catch let failure as SnapshotPresentationFailure {
|
|
507
|
+
return SnapshotBackendAttempt(
|
|
508
|
+
outcome: .failed(Self.snapshotCaptureFailure(for: failure), phase: .presentation),
|
|
509
|
+
timing: timer.timing
|
|
510
|
+
)
|
|
511
|
+
} catch let failure as SnapshotCaptureFailure {
|
|
512
|
+
return SnapshotBackendAttempt(
|
|
513
|
+
outcome: .failed(failure, phase: .presentation),
|
|
514
|
+
timing: timer.timing
|
|
515
|
+
)
|
|
492
516
|
}
|
|
517
|
+
|
|
518
|
+
var capture = presented
|
|
519
|
+
capture.timing = timer.timing
|
|
520
|
+
return SnapshotBackendAttempt(
|
|
521
|
+
outcome: .captured(capture),
|
|
522
|
+
timing: timer.timing
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/// A backend that answers a request with the other projection loses its tier and says why, so
|
|
527
|
+
/// the miss lands in the quality verdict instead of shipping as a correct-looking capture.
|
|
528
|
+
static func snapshotProjectionMismatchFailure(
|
|
529
|
+
_ kind: SnapshotBackendKind,
|
|
530
|
+
requested: CaptureHint.Projection,
|
|
531
|
+
acquired: CaptureHint.Projection
|
|
532
|
+
) -> SnapshotCaptureFailure {
|
|
533
|
+
SnapshotCaptureFailure(
|
|
534
|
+
code: "IOS_SNAPSHOT_PROJECTION_MISMATCH",
|
|
535
|
+
message:
|
|
536
|
+
"the \(kind.rawValue) backend returned a \(acquired.rawValue) capture for a \(requested.rawValue) snapshot request",
|
|
537
|
+
hint: "This is a runner bug: report it with the failing command and the app under test."
|
|
538
|
+
)
|
|
493
539
|
}
|
|
494
540
|
|
|
495
541
|
// MARK: Quality classifier (the single source of "is this snapshot degraded")
|
|
@@ -529,7 +575,7 @@ extension RunnerTests {
|
|
|
529
575
|
}
|
|
530
576
|
}
|
|
531
577
|
|
|
532
|
-
static func isSparseApplicationWindowTree(_ nodes: [
|
|
578
|
+
static func isSparseApplicationWindowTree(_ nodes: [PresentedNode]) -> Bool {
|
|
533
579
|
guard !nodes.isEmpty else { return false }
|
|
534
580
|
let rootRects = nodes.compactMap { node in
|
|
535
581
|
node.type == "Application" || node.type == "Window" ? node.rect : nil
|
|
@@ -564,7 +610,7 @@ extension RunnerTests {
|
|
|
564
610
|
/// A leaf whose label joins many short segments is a container marked as an accessibility
|
|
565
611
|
/// element: the platform folds every descendant into one merged node. Nothing below it can
|
|
566
612
|
/// be addressed — by automation or by assistive tech. This is app-side; no backend recovers it.
|
|
567
|
-
static func collapsedLeafIndexes(_ nodes: [
|
|
613
|
+
static func collapsedLeafIndexes(_ nodes: [PresentedNode]) -> [Int]? {
|
|
568
614
|
let parents = Set(nodes.compactMap { $0.parentIndex })
|
|
569
615
|
let collapsed = nodes.filter { node in
|
|
570
616
|
guard !parents.contains(node.index) else { return false }
|
|
@@ -592,13 +638,22 @@ extension RunnerTests {
|
|
|
592
638
|
reasonCode: reason?.code,
|
|
593
639
|
effectiveDepth: capture.effectiveDepth,
|
|
594
640
|
collapsedLeafIndexes: Self.collapsedLeafIndexes(payload.nodes ?? []),
|
|
595
|
-
customActions: capture.customActions
|
|
641
|
+
customActions: capture.customActions,
|
|
642
|
+
timing: capture.timing
|
|
596
643
|
)
|
|
597
644
|
return DataPayload(
|
|
598
645
|
// Legacy human text for older daemons that read message instead of snapshotQuality.
|
|
599
646
|
message: Self.legacyQualityMessage(quality) ?? payload.message,
|
|
600
647
|
nodes: payload.nodes,
|
|
601
|
-
|
|
648
|
+
// Completeness, never provenance: a whole tree that a later backend produced (state
|
|
649
|
+
// "recovered") stays untruncated, so strict absence reads can trust it. Only a real cap
|
|
650
|
+
// (payload truncation, a depth-limited private AX capture) or a sparse terminal payload
|
|
651
|
+
// is truncated.
|
|
652
|
+
truncated: payload.truncated == true || state == "sparse" || capture.effectiveDepth != nil,
|
|
653
|
+
qualityPayload: capture.qualityPayload.flatMap { quality in
|
|
654
|
+
guard let nodes = quality.nodes else { return nil }
|
|
655
|
+
return SnapshotQualityPayload(nodes: nodes, truncated: quality.truncated == true)
|
|
656
|
+
},
|
|
602
657
|
snapshotQuality: quality,
|
|
603
658
|
runnerFatal: payload.runnerFatal,
|
|
604
659
|
runnerFatalReason: payload.runnerFatalReason
|
|
@@ -640,9 +695,15 @@ extension RunnerTests {
|
|
|
640
695
|
else { return nil }
|
|
641
696
|
var parts: [String] = []
|
|
642
697
|
if quality.state == "recovered" {
|
|
643
|
-
let meaning
|
|
644
|
-
|
|
645
|
-
|
|
698
|
+
let meaning: String
|
|
699
|
+
switch quality.reasonCode {
|
|
700
|
+
case "budget", "deferred":
|
|
701
|
+
meaning = " The primary capture ran out of its time budget (busy app or simulator); the recovered tree is authoritative for this screen."
|
|
702
|
+
case "presentation-failed":
|
|
703
|
+
meaning = " The runner rejected a regular presentation because its cumulative clip invariant failed; report this as a runner bug and treat screenshot as visual truth."
|
|
704
|
+
default:
|
|
705
|
+
meaning = " This usually means the app publishes an unhealthy accessibility tree — fixing the app's accessibility is the real cure. Treat screenshot as visual truth when this warning appears."
|
|
706
|
+
}
|
|
646
707
|
parts.append(
|
|
647
708
|
"Detected an overly complex or slow accessibility tree. Fell back to the \(quality.backend) snapshot backend"
|
|
648
709
|
+ (quality.reason.map { " after: \($0)." } ?? ".")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import AgentDeviceSnapshotPresentation
|
|
2
|
+
|
|
3
|
+
extension RunnerTests {
|
|
4
|
+
static func snapshotCaptureFailure(
|
|
5
|
+
for failure: SnapshotPresentationFailure
|
|
6
|
+
) -> SnapshotCaptureFailure {
|
|
7
|
+
SnapshotCaptureFailure(
|
|
8
|
+
code: failure.code,
|
|
9
|
+
message: failure.message,
|
|
10
|
+
hint: failure.hint,
|
|
11
|
+
qualityReasonCode: failure.qualityReasonCode
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static func snapshotQualityReasonCode(for failure: SnapshotCaptureFailure) -> String {
|
|
16
|
+
failure.qualityReasonCode
|
|
17
|
+
?? (Self.isAxSnapshotFailure(failure) ? "ax-rejected" : "capture-failed")
|
|
18
|
+
}
|
|
19
|
+
}
|