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,110 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
struct SnapshotCaptureTiming: Codable, Equatable {
|
|
5
|
+
let acquisitionMs: Double
|
|
6
|
+
let presentationMs: Double
|
|
7
|
+
|
|
8
|
+
init(acquisitionMs: Double, presentationMs: Double) {
|
|
9
|
+
self.acquisitionMs = max(0, acquisitionMs)
|
|
10
|
+
self.presentationMs = max(0, presentationMs)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init(acquisition: TimeInterval, presentation: TimeInterval) {
|
|
14
|
+
self.init(
|
|
15
|
+
acquisitionMs: max(0, acquisition) * 1_000,
|
|
16
|
+
presentationMs: max(0, presentation) * 1_000
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
enum SnapshotCapturePhase: Equatable {
|
|
22
|
+
case acquisition
|
|
23
|
+
case presentation
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
struct SnapshotPhaseTimer {
|
|
27
|
+
private let now: () -> Date
|
|
28
|
+
private var acquisitionSeconds: TimeInterval = 0
|
|
29
|
+
private var presentationSeconds: TimeInterval = 0
|
|
30
|
+
|
|
31
|
+
init(now: @escaping () -> Date = { Date() }) {
|
|
32
|
+
self.now = now
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
mutating func measure<T>(
|
|
36
|
+
_ phase: SnapshotCapturePhase,
|
|
37
|
+
_ operation: () throws -> T
|
|
38
|
+
) rethrows -> T {
|
|
39
|
+
let startedAt = now()
|
|
40
|
+
defer {
|
|
41
|
+
let elapsed = max(0, now().timeIntervalSince(startedAt))
|
|
42
|
+
switch phase {
|
|
43
|
+
case .acquisition:
|
|
44
|
+
acquisitionSeconds += elapsed
|
|
45
|
+
case .presentation:
|
|
46
|
+
presentationSeconds += elapsed
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return try operation()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var timing: SnapshotCaptureTiming {
|
|
53
|
+
SnapshotCaptureTiming(
|
|
54
|
+
acquisition: acquisitionSeconds,
|
|
55
|
+
presentation: presentationSeconds
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
extension RunnerTests {
|
|
61
|
+
struct SnapshotBackendAttempt {
|
|
62
|
+
enum Outcome {
|
|
63
|
+
case noCapture
|
|
64
|
+
case captured(SnapshotBackendCapture)
|
|
65
|
+
case failed(SnapshotCaptureFailure, phase: SnapshotCapturePhase)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// The failure phase is part of the result, so penalty policy cannot infer it from duration
|
|
69
|
+
/// or error text.
|
|
70
|
+
let outcome: Outcome
|
|
71
|
+
let timing: SnapshotCaptureTiming
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// The penalty breaker observes only acquisition facts. Presentation is a separate phase and
|
|
75
|
+
/// cannot arm the breaker, even when it is slower than the acquisition that produced the tree.
|
|
76
|
+
private static func snapshotXCTestPenaltyReason(
|
|
77
|
+
kind: SnapshotBackendKind,
|
|
78
|
+
attempt: SnapshotBackendAttempt,
|
|
79
|
+
slowThresholdMs: Double
|
|
80
|
+
) -> String? {
|
|
81
|
+
guard kind.usesXCTestAccessibilityChannel else { return nil }
|
|
82
|
+
if case let .failed(failure, phase: .acquisition) = attempt.outcome,
|
|
83
|
+
failure.code == Self.xCTestSnapshotTimeoutCode
|
|
84
|
+
{
|
|
85
|
+
return "\(kind.rawValue)_backend_timeout"
|
|
86
|
+
}
|
|
87
|
+
guard attempt.timing.acquisitionMs > slowThresholdMs else { return nil }
|
|
88
|
+
return "slow_\(kind.rawValue)_capture_\(Int(attempt.timing.acquisitionMs))ms"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func recordXCTestSnapshotBackendAttemptIfNeeded(
|
|
92
|
+
_ kind: SnapshotBackendKind,
|
|
93
|
+
attempt: SnapshotBackendAttempt,
|
|
94
|
+
penaltySuppressed: Bool
|
|
95
|
+
) {
|
|
96
|
+
guard !penaltySuppressed else { return }
|
|
97
|
+
guard
|
|
98
|
+
let reason = Self.snapshotXCTestPenaltyReason(
|
|
99
|
+
kind: kind,
|
|
100
|
+
attempt: attempt,
|
|
101
|
+
slowThresholdMs: snapshotXCTestSlowCaptureThreshold * 1_000
|
|
102
|
+
)
|
|
103
|
+
else { return }
|
|
104
|
+
penalizeSnapshotXCTestChannel(
|
|
105
|
+
bundleId: currentBundleId,
|
|
106
|
+
reason: reason
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
|
|
3
|
+
// The synthesized text-entry commit wait, end to end: the deadline that bounds it, the two waits
|
|
4
|
+
// that run it, the observation/pacing they poll through, and the value-free cadence line that path
|
|
5
|
+
// is allowed to log. Split from RunnerTests+SynthesizedTextEntry.swift, which keeps the
|
|
6
|
+
// private-XCTest synthesis boundary and the route policies; the pure outcome functions these wrap
|
|
7
|
+
// stay there next to the rules they encode. Everything that touches the polled field value now
|
|
8
|
+
// lives in this one file, which is the surface apple-runner-log-redaction.test.ts guards.
|
|
9
|
+
extension RunnerTests {
|
|
10
|
+
/// One commit wait's running deadline.
|
|
11
|
+
///
|
|
12
|
+
/// A synthesized burst can be *throttled* rather than dropped: on a loaded simulator the
|
|
13
|
+
/// characters keep landing, just slowly, and everything touching the input system slows with
|
|
14
|
+
/// them (#1874). A flat wall-clock budget cannot tell that apart from a wedged pipeline, so it
|
|
15
|
+
/// condemned both at the same instant — and the throttled case is a working command reported as
|
|
16
|
+
/// `TEXT_INPUT_COMMIT_NOT_OBSERVED`, which is what turned an environment episode into a red
|
|
17
|
+
/// lane on branches touching no iOS code.
|
|
18
|
+
///
|
|
19
|
+
/// So time is granted against *progress* — the observed value's expected-prefix growing, the
|
|
20
|
+
/// same length-only evidence `logCommitCadence` already emits — with an absolute `ceiling`, so a
|
|
21
|
+
/// pipeline delivering one character per stall window cannot hold a command open forever. A
|
|
22
|
+
/// pipeline making no progress at all still expires at exactly the `stallBudget` the flat
|
|
23
|
+
/// deadline used, so nothing that fails today starts passing merely by waiting longer.
|
|
24
|
+
///
|
|
25
|
+
/// Started by the poll loop from its own first `now()`, and held as a local `var` there. The
|
|
26
|
+
/// wait's setup reads the field's placeholder first, an AX round-trip that takes seconds on
|
|
27
|
+
/// exactly the loaded host this exists for; charging that to the deadline made the wait give up
|
|
28
|
+
/// sooner than the flat budget it replaced.
|
|
29
|
+
struct SynthesizedCommitDeadline {
|
|
30
|
+
private let startedAt: Date
|
|
31
|
+
private let stallBudget: TimeInterval
|
|
32
|
+
private let ceiling: TimeInterval
|
|
33
|
+
// Nothing has landed yet, and an observation of "still nothing" must not read as progress.
|
|
34
|
+
private var bestPrefixLength = 0
|
|
35
|
+
private var lastProgressAt: Date
|
|
36
|
+
|
|
37
|
+
init(startedAt: Date, stallBudget: TimeInterval, ceiling: TimeInterval) {
|
|
38
|
+
self.startedAt = startedAt
|
|
39
|
+
self.stallBudget = stallBudget
|
|
40
|
+
self.ceiling = ceiling
|
|
41
|
+
self.lastProgressAt = startedAt
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Records one observation's expected-prefix length. Only forward movement counts: a shorter
|
|
45
|
+
/// read — the app clearing the field mid-flight, or a value that could not be read at all,
|
|
46
|
+
/// which measures as 0 — is not evidence the burst is still landing, so it neither buys time
|
|
47
|
+
/// nor takes any back.
|
|
48
|
+
mutating func record(expectedPrefixLength: Int, at now: Date) {
|
|
49
|
+
guard expectedPrefixLength > bestPrefixLength else { return }
|
|
50
|
+
bestPrefixLength = expectedPrefixLength
|
|
51
|
+
lastProgressAt = now
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func isExpired(at now: Date) -> Bool {
|
|
55
|
+
now.timeIntervalSince(startedAt) >= ceiling
|
|
56
|
+
|| now.timeIntervalSince(lastProgressAt) >= stallBudget
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Blocks until the synthesized bare-type text is observable in the target field, so `type`
|
|
61
|
+
/// cannot report ok while trailing characters are still uncommitted on a slow simulator.
|
|
62
|
+
///
|
|
63
|
+
/// Observation only. A stalled prefix cannot be told apart from a suffix still queued in the
|
|
64
|
+
/// event stream, so re-synthesizing the difference risks committing it twice after the command
|
|
65
|
+
/// already reported success (#1676 rejected exactly that repair). Reporting `.notObserved` is
|
|
66
|
+
/// what the caller does instead: the partial value is the agent's to resolve, and a named
|
|
67
|
+
/// failure beats a success that misdescribes the field. Text carrying a submit key is skipped
|
|
68
|
+
/// outright: the app may clear or rewrite the field on submit, so `textBefore + typedText` is
|
|
69
|
+
/// not the value to wait for.
|
|
70
|
+
func awaitSynthesizedFirstResponderCommit(
|
|
71
|
+
app: XCUIApplication,
|
|
72
|
+
target: TextEntryTarget,
|
|
73
|
+
textBefore: String?,
|
|
74
|
+
typedText: String
|
|
75
|
+
) -> SynthesizedTextCommitOutcome {
|
|
76
|
+
guard let textBefore, !typedText.contains("\n"), !typedText.contains("\r") else {
|
|
77
|
+
return .unobservable
|
|
78
|
+
}
|
|
79
|
+
let expectedText = textBefore + typedText
|
|
80
|
+
let waitStartedAt = Date()
|
|
81
|
+
NSLog("[DEBUG-1874] wait start expectedLen=%ld route=append", expectedText.count)
|
|
82
|
+
let ingredients = synthesizedCommitPollingIngredients(app: app, target: target, expectedText: expectedText)
|
|
83
|
+
let outcome = Self.awaitSynthesizedCommitOutcome(
|
|
84
|
+
expectedText: expectedText,
|
|
85
|
+
placeholder: ingredients.placeholder,
|
|
86
|
+
now: { Date() },
|
|
87
|
+
observe: ingredients.observe,
|
|
88
|
+
waitForNextObservation: ingredients.waitForNextObservation
|
|
89
|
+
)
|
|
90
|
+
NSLog(
|
|
91
|
+
"[DEBUG-1874] wait outcome=%@ elapsedMs=%.0f route=append",
|
|
92
|
+
String(describing: outcome),
|
|
93
|
+
waitStartedAt.timeIntervalSinceNow * -1000
|
|
94
|
+
)
|
|
95
|
+
return outcome
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Blocks until the synthesized replacement text (`fill`) is observable in the target field, so
|
|
99
|
+
/// `fill` cannot report ok while the select-all-and-retype it posted is still uncommitted — or
|
|
100
|
+
/// silently wrong — on a slow or channel-penalized simulator (this route runs only when the
|
|
101
|
+
/// XCTest channel is already penalized, and never resolves an `XCUIElement`, so it previously had
|
|
102
|
+
/// no verification at all).
|
|
103
|
+
///
|
|
104
|
+
/// Unlike the append route, the expected value is the final text itself — replacement mode
|
|
105
|
+
/// clears the field first, so there is no `textBefore` prefix to account for — and unlike the
|
|
106
|
+
/// append route, a settled mismatch is always reported rather than trusted: see
|
|
107
|
+
/// `awaitSynthesizedReplacementCommitOutcome`'s doc comment.
|
|
108
|
+
func awaitSynthesizedReplacementCommit(
|
|
109
|
+
app: XCUIApplication,
|
|
110
|
+
target: TextEntryTarget,
|
|
111
|
+
expectedText: String
|
|
112
|
+
) -> SynthesizedTextCommitOutcome {
|
|
113
|
+
guard !expectedText.contains("\n"), !expectedText.contains("\r") else {
|
|
114
|
+
return .unobservable
|
|
115
|
+
}
|
|
116
|
+
let waitStartedAt = Date()
|
|
117
|
+
NSLog("[DEBUG-1874] wait start expectedLen=%ld route=replacement", expectedText.count)
|
|
118
|
+
let ingredients = synthesizedCommitPollingIngredients(app: app, target: target, expectedText: expectedText)
|
|
119
|
+
let outcome = Self.awaitSynthesizedReplacementCommitOutcome(
|
|
120
|
+
expectedText: expectedText,
|
|
121
|
+
placeholder: ingredients.placeholder,
|
|
122
|
+
now: { Date() },
|
|
123
|
+
observe: ingredients.observe,
|
|
124
|
+
waitForNextObservation: ingredients.waitForNextObservation
|
|
125
|
+
)
|
|
126
|
+
NSLog(
|
|
127
|
+
"[DEBUG-1874] wait outcome=%@ elapsedMs=%.0f route=replacement",
|
|
128
|
+
String(describing: outcome),
|
|
129
|
+
waitStartedAt.timeIntervalSinceNow * -1000
|
|
130
|
+
)
|
|
131
|
+
return outcome
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// The emitted cadence line, as a pure function so its output is assertable. Only lengths and
|
|
135
|
+
/// a timestamp are representable here; there is no String parameter, so observed field
|
|
136
|
+
/// contents cannot reach runner.log through this boundary whatever they contain.
|
|
137
|
+
static func commitCadenceLogLine(
|
|
138
|
+
elapsedMs: Int,
|
|
139
|
+
observedLen: Int,
|
|
140
|
+
expectedPrefixLen: Int
|
|
141
|
+
) -> String {
|
|
142
|
+
"[DEBUG-1874] poll t=\(elapsedMs)ms observedLen=\(observedLen) expectedPrefixLen=\(expectedPrefixLen)"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// The typed boundary for commit-wait cadence evidence. The poll path must log through this
|
|
146
|
+
/// function and never through a raw NSLog: every parameter is an Int, so the polled value's
|
|
147
|
+
/// contents are unrepresentable at the call site.
|
|
148
|
+
static func logCommitCadence(
|
|
149
|
+
elapsedMs: Int,
|
|
150
|
+
observedLen: Int,
|
|
151
|
+
expectedPrefixLen: Int
|
|
152
|
+
) {
|
|
153
|
+
NSLog(
|
|
154
|
+
"%@",
|
|
155
|
+
commitCadenceLogLine(
|
|
156
|
+
elapsedMs: elapsedMs,
|
|
157
|
+
observedLen: observedLen,
|
|
158
|
+
expectedPrefixLen: expectedPrefixLen
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// The placeholder/observe/pacing ingredients shared by the append route
|
|
164
|
+
/// (`awaitSynthesizedFirstResponderCommit`) and the replacement route
|
|
165
|
+
/// (`awaitSynthesizedReplacementCommit`). What must NOT be shared is which outcome function
|
|
166
|
+
/// consumes them: see `awaitSynthesizedReplacementCommitOutcome`'s doc comment for why append
|
|
167
|
+
/// mode's "trust a diverged value" rule is wrong for replacement mode. Each caller therefore
|
|
168
|
+
/// calls its own named outcome function directly, with real argument labels — deliberately not
|
|
169
|
+
/// a stored closure/function-value parameter here, which would erase those labels at the call
|
|
170
|
+
/// site and make the observe closure unrecognizable to the static content-redaction check in
|
|
171
|
+
/// `apple-runner-log-redaction.test.ts` (`extractObserveClosure` locates the labeled closure
|
|
172
|
+
/// literal by its text; a closure passed as a plain function value carries no such label).
|
|
173
|
+
private func synthesizedCommitPollingIngredients(
|
|
174
|
+
app: XCUIApplication,
|
|
175
|
+
target: TextEntryTarget,
|
|
176
|
+
expectedText: String
|
|
177
|
+
) -> (
|
|
178
|
+
placeholder: String?,
|
|
179
|
+
observe: () -> String?,
|
|
180
|
+
waitForNextObservation: () -> Void
|
|
181
|
+
) {
|
|
182
|
+
let placeholder = resolveTextEntryElement(app: app, target: target)?.placeholderValue
|
|
183
|
+
let waitStartedAt = Date()
|
|
184
|
+
return (
|
|
185
|
+
placeholder: placeholder,
|
|
186
|
+
observe: {
|
|
187
|
+
let observedText = self.editableTextValue(
|
|
188
|
+
for: self.resolveTextEntryElement(app: app, target: target),
|
|
189
|
+
treatingPlaceholderAsEmpty: true
|
|
190
|
+
)
|
|
191
|
+
// Cadence evidence stays value-free: the polled value is user content typed through
|
|
192
|
+
// `type`/`fill` and must never reach runner.log. Lengths and the expected-prefix walk
|
|
193
|
+
// are enough to distinguish throttling (prefix grows slowly) from a wedge (it freezes).
|
|
194
|
+
Self.logCommitCadence(
|
|
195
|
+
elapsedMs: Int(waitStartedAt.timeIntervalSinceNow * -1000),
|
|
196
|
+
observedLen: observedText?.count ?? -1,
|
|
197
|
+
expectedPrefixLen: observedText.map { Self.commonPrefixLength($0, expectedText) } ?? -1
|
|
198
|
+
)
|
|
199
|
+
return observedText
|
|
200
|
+
},
|
|
201
|
+
// XCUI resolution shares the automation channel with the in-flight synthesized event.
|
|
202
|
+
// Sparse reads let the target consume that event instead of continuously interrupting it.
|
|
203
|
+
waitForNextObservation: { self.sleepFor(TextEntryTiming.synthesizedCommitPollInterval) }
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -40,9 +40,14 @@ extension RunnerTests {
|
|
|
40
40
|
replacingExistingText: Bool
|
|
41
41
|
) -> SynthesizedTextEntryAction {
|
|
42
42
|
#if os(iOS)
|
|
43
|
+
let postStartedAt = Date()
|
|
43
44
|
let result = replacingExistingText
|
|
44
45
|
? RunnerSynthesizedTextEntry.replaceText(withApplication: app, text: text)
|
|
45
46
|
: RunnerSynthesizedTextEntry.synthesizeText(withApplication: app, text: text)
|
|
47
|
+
NSLog(
|
|
48
|
+
"[DEBUG-1874] synthesize posted %d chars status=%d tookMs=%.0f",
|
|
49
|
+
text.count, result.status.rawValue, postStartedAt.timeIntervalSinceNow * -1000
|
|
50
|
+
)
|
|
46
51
|
return Self.action(status: result.status, message: result.message)
|
|
47
52
|
#else
|
|
48
53
|
return .fallback
|
|
@@ -122,6 +127,17 @@ extension RunnerTests {
|
|
|
122
127
|
sleepFor(request.delaySeconds)
|
|
123
128
|
}
|
|
124
129
|
}
|
|
130
|
+
// The private synthesize call returns at post time, not commit time (same as bare `type`,
|
|
131
|
+
// see awaitSynthesizedFirstResponderCommit) — but this route never resolves an XCUIElement,
|
|
132
|
+
// so without this wait it had no way to notice a dropped or still-in-flight character at all
|
|
133
|
+
// and reported ok purely because the event posted. Wait here, on the same request.target
|
|
134
|
+
// (element nil, refreshPoint set) that gated this route, so each poll re-resolves via the
|
|
135
|
+
// refresh point rather than trusting a stale element handle.
|
|
136
|
+
let commit = awaitSynthesizedReplacementCommit(
|
|
137
|
+
app: request.app,
|
|
138
|
+
target: request.target,
|
|
139
|
+
expectedText: request.text
|
|
140
|
+
)
|
|
125
141
|
logTextEntryPhase(
|
|
126
142
|
commandId: request.commandId,
|
|
127
143
|
phase: "total",
|
|
@@ -135,7 +151,8 @@ extension RunnerTests {
|
|
|
135
151
|
repaired: false,
|
|
136
152
|
expectedText: request.text,
|
|
137
153
|
observedText: nil,
|
|
138
|
-
textEntryRoute: "synthesized-first-responder-replacement"
|
|
154
|
+
textEntryRoute: "synthesized-first-responder-replacement",
|
|
155
|
+
failure: Self.textEntryFailure(forCommitOutcome: commit)
|
|
139
156
|
)
|
|
140
157
|
)
|
|
141
158
|
#else
|
|
@@ -184,38 +201,143 @@ extension RunnerTests {
|
|
|
184
201
|
return expectedText.hasPrefix(observedText) ? .pending : .diverged
|
|
185
202
|
}
|
|
186
203
|
|
|
187
|
-
///
|
|
188
|
-
///
|
|
204
|
+
/// Length of the shared prefix of two strings. Feeds value-free commit-wait logging: the
|
|
205
|
+
/// expected-prefix walk over time distinguishes throttled delivery (grows slowly) from a
|
|
206
|
+
/// wedged pipeline (freezes) without ever logging the field's contents.
|
|
207
|
+
static func commonPrefixLength(_ lhs: String, _ rhs: String) -> Int {
|
|
208
|
+
var length = 0
|
|
209
|
+
for (l, r) in zip(lhs, rhs) {
|
|
210
|
+
if l != r { break }
|
|
211
|
+
length += 1
|
|
212
|
+
}
|
|
213
|
+
return length
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/// How the commit wait ended. Distinct from `SynthesizedTextCommitProgress`, which classifies a
|
|
217
|
+
/// single observation: this is the whole wait's verdict, and it exists so the deadline can be
|
|
218
|
+
/// told apart from success. The wait used to return `Void`, which made an expired deadline
|
|
219
|
+
/// indistinguishable from a committed one — `type` then reported ok with a partial value in the
|
|
220
|
+
/// field (#1874, #1844).
|
|
221
|
+
enum SynthesizedTextCommitOutcome: Equatable {
|
|
222
|
+
/// The wait's success case, but its meaning is route-specific: for append mode (bare `type`),
|
|
223
|
+
/// the expected text committed OR the app transformed the input in a way the runner must not
|
|
224
|
+
/// second-guess; for replacement mode (`fill`), it means only an exact match — see
|
|
225
|
+
/// `awaitSynthesizedReplacementCommitOutcome`'s doc comment for why replacement mode has no
|
|
226
|
+
/// "trust it" case.
|
|
227
|
+
case settled
|
|
228
|
+
/// There was nothing to wait for — no readable baseline, or the text carries a submit key.
|
|
229
|
+
case unobservable
|
|
230
|
+
/// The deadline expired with the expected text still not observed.
|
|
231
|
+
case notObserved
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/// The commit wait's decision, with observation, pacing and the clock injected so both deadline
|
|
235
|
+
/// branches are exercisable without a simulator (the macOS host lane runs this; the member
|
|
236
|
+
/// wrapper below binds the real XCUI reads).
|
|
189
237
|
///
|
|
190
|
-
///
|
|
191
|
-
///
|
|
192
|
-
///
|
|
193
|
-
///
|
|
194
|
-
func
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
238
|
+
/// The deadline is a local `var`, started from this loop's own first `now()` and advanced from
|
|
239
|
+
/// the same observation the progress check reads, so "did the burst move" and "is time up" are
|
|
240
|
+
/// two statements in one loop. The budget defaults to the shipped one, so only a test that is
|
|
241
|
+
/// asking about time has to name it.
|
|
242
|
+
static func awaitSynthesizedCommitOutcome(
|
|
243
|
+
expectedText: String,
|
|
244
|
+
placeholder: String?,
|
|
245
|
+
stallBudget: TimeInterval = TextEntryTiming.synthesizedCommitStallTimeout,
|
|
246
|
+
ceiling: TimeInterval = TextEntryTiming.synthesizedCommitCeiling,
|
|
247
|
+
now: () -> Date = { Date() },
|
|
248
|
+
observe: () -> String?,
|
|
249
|
+
waitForNextObservation: () -> Void
|
|
250
|
+
) -> SynthesizedTextCommitOutcome {
|
|
251
|
+
// A placeholder-equal AX value cannot prove a commit: an input handler may clear even a
|
|
252
|
+
// previously non-empty field after dispatch, making the empty field render the same value.
|
|
253
|
+
// Refuse before polling because no later read can distinguish those states.
|
|
254
|
+
if Self.textMatchesPlaceholder(expectedText, placeholder: placeholder) {
|
|
255
|
+
return .notObserved
|
|
202
256
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
)
|
|
210
|
-
switch Self.synthesizedTextCommitProgress(observedText: observedText, expectedText: expectedText) {
|
|
257
|
+
var deadline = SynthesizedCommitDeadline(startedAt: now(), stallBudget: stallBudget, ceiling: ceiling)
|
|
258
|
+
// The deadline is checked AFTER an observation, never before one, so the last thing that
|
|
259
|
+
// happens before condemning a commit is a read. Checking first would condemn a commit that
|
|
260
|
+
// landed during the final poll sleep — the exact loaded-host timing this wait exists for.
|
|
261
|
+
while true {
|
|
262
|
+
let observedText = observe()
|
|
263
|
+
switch synthesizedTextCommitProgress(observedText: observedText, expectedText: expectedText) {
|
|
211
264
|
case .committed, .diverged:
|
|
212
|
-
return
|
|
265
|
+
return .settled
|
|
213
266
|
case .pending:
|
|
214
|
-
|
|
267
|
+
// One clock sample, so the instant an observation is recorded at is the instant it is
|
|
268
|
+
// judged against.
|
|
269
|
+
let sampledAt = now()
|
|
270
|
+
deadline.record(
|
|
271
|
+
expectedPrefixLength: Self.commonPrefixLength(observedText ?? "", expectedText),
|
|
272
|
+
at: sampledAt
|
|
273
|
+
)
|
|
274
|
+
if deadline.isExpired(at: sampledAt) { return .notObserved }
|
|
275
|
+
waitForNextObservation()
|
|
215
276
|
}
|
|
216
277
|
}
|
|
217
278
|
}
|
|
218
279
|
|
|
280
|
+
/// The command-level consequence of a commit wait. `.unobservable` is not a failure: there was
|
|
281
|
+
/// no baseline to compare against, which is the pre-existing contract for submit-key text and
|
|
282
|
+
/// unreadable fields, not evidence that anything went wrong.
|
|
283
|
+
static func textEntryFailure(
|
|
284
|
+
forCommitOutcome outcome: SynthesizedTextCommitOutcome
|
|
285
|
+
) -> TextEntryFailure? {
|
|
286
|
+
switch outcome {
|
|
287
|
+
case .settled, .unobservable:
|
|
288
|
+
return nil
|
|
289
|
+
case .notObserved:
|
|
290
|
+
return .commitNotObserved
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/// The replacement-mode counterpart of `awaitSynthesizedCommitOutcome`. It must NOT reuse that
|
|
295
|
+
/// function's `synthesizedTextCommitProgress`: prefix-walk's `.diverged` case exists to trust an
|
|
296
|
+
/// app that transforms bare-`type` input (formatter, autocomplete) rather than second-guess it —
|
|
297
|
+
/// but that same rule silently accepts a dropped-character corruption too, because a value with a
|
|
298
|
+
/// hole in the middle ("ada@example" -> "aexample") is neither a matching prefix NOR the full
|
|
299
|
+
/// string, yet still gets classified `.diverged` -> `.settled` -> reported `ok: true`. This is not
|
|
300
|
+
/// a hypothetical: it is the exact shape of the corruption this wait exists to catch (`fill`
|
|
301
|
+
/// reporting success over "Avelace"/"aexample"-style drops), verified against both live examples
|
|
302
|
+
/// before writing this comment.
|
|
303
|
+
///
|
|
304
|
+
/// `.replacement` mode does not need prefix tolerance for legitimate transforms either:
|
|
305
|
+
/// `isRepairableTextEntryMismatch` (RunnerTests+TextTyping.swift) already treats every mismatch in
|
|
306
|
+
/// `.replacement` mode as repairable unconditionally, with no formatter/autocomplete carve-out —
|
|
307
|
+
/// `fill` fully owns the field via select-all, so there is no legitimate reason for the settled
|
|
308
|
+
/// value to be anything other than exactly what was requested. A settled non-match is therefore
|
|
309
|
+
/// always the wait's failure case, never a `.settled` pass-through.
|
|
310
|
+
static func awaitSynthesizedReplacementCommitOutcome(
|
|
311
|
+
expectedText: String,
|
|
312
|
+
placeholder: String?,
|
|
313
|
+
stallBudget: TimeInterval = TextEntryTiming.synthesizedCommitStallTimeout,
|
|
314
|
+
ceiling: TimeInterval = TextEntryTiming.synthesizedCommitCeiling,
|
|
315
|
+
now: () -> Date = { Date() },
|
|
316
|
+
observe: () -> String?,
|
|
317
|
+
waitForNextObservation: () -> Void
|
|
318
|
+
) -> SynthesizedTextCommitOutcome {
|
|
319
|
+
if Self.textMatchesPlaceholder(expectedText, placeholder: placeholder) {
|
|
320
|
+
return .notObserved
|
|
321
|
+
}
|
|
322
|
+
var deadline = SynthesizedCommitDeadline(startedAt: now(), stallBudget: stallBudget, ceiling: ceiling)
|
|
323
|
+
while true {
|
|
324
|
+
let observedText = observe()
|
|
325
|
+
if observedText == expectedText {
|
|
326
|
+
return .settled
|
|
327
|
+
}
|
|
328
|
+
// Prefix growth cannot settle this wait — a value with a hole in the middle is still a
|
|
329
|
+
// failure, see the doc comment above — but it is the same evidence that the burst is still
|
|
330
|
+
// landing, so it buys the same time here as it does in append mode.
|
|
331
|
+
let sampledAt = now()
|
|
332
|
+
deadline.record(
|
|
333
|
+
expectedPrefixLength: Self.commonPrefixLength(observedText ?? "", expectedText),
|
|
334
|
+
at: sampledAt
|
|
335
|
+
)
|
|
336
|
+
if deadline.isExpired(at: sampledAt) { return .notObserved }
|
|
337
|
+
waitForNextObservation()
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
219
341
|
static func shouldUseResolvedCoordinateTextEntryRoute(
|
|
220
342
|
repairMode: TextTypingRepairMode,
|
|
221
343
|
hasX: Bool,
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import XCTest
|
|
2
|
+
import AgentDeviceSnapshotPresentation
|
|
2
3
|
|
|
3
4
|
extension RunnerTests {
|
|
4
5
|
// MARK: - Blocking System Modal Snapshot
|
|
@@ -25,7 +26,7 @@ extension RunnerTests {
|
|
|
25
26
|
) else {
|
|
26
27
|
return nil
|
|
27
28
|
}
|
|
28
|
-
var nodes: [
|
|
29
|
+
var nodes: [PresentedNode] = [modalNode]
|
|
29
30
|
|
|
30
31
|
for action in actions {
|
|
31
32
|
guard let actionNode = safeMakeSnapshotNode(
|
|
@@ -221,24 +222,26 @@ extension RunnerTests {
|
|
|
221
222
|
depth: Int,
|
|
222
223
|
parentIndex: Int? = nil,
|
|
223
224
|
hittableOverride: Bool? = nil
|
|
224
|
-
) ->
|
|
225
|
+
) -> PresentedNode {
|
|
225
226
|
let label = (labelOverride ?? element.label).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
226
227
|
let identifier = (identifierOverride ?? element.identifier).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
227
|
-
return
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
228
|
+
return SnapshotPresentation.singleElementRead(
|
|
229
|
+
RawAXNode(
|
|
230
|
+
index: index,
|
|
231
|
+
type: type,
|
|
232
|
+
label: label.isEmpty ? nil : label,
|
|
233
|
+
identifier: identifier.isEmpty ? nil : identifier,
|
|
234
|
+
value: nil,
|
|
235
|
+
rect: snapshotRect(from: element.frame),
|
|
236
|
+
enabled: element.isEnabled,
|
|
237
|
+
focused: nil,
|
|
238
|
+
selected: nil,
|
|
239
|
+
hittable: hittableOverride ?? element.isHittable,
|
|
240
|
+
depth: depth,
|
|
241
|
+
parentIndex: parentIndex,
|
|
242
|
+
hiddenContentAbove: nil,
|
|
243
|
+
hiddenContentBelow: nil
|
|
244
|
+
)
|
|
242
245
|
)
|
|
243
246
|
}
|
|
244
247
|
|
|
@@ -251,7 +254,7 @@ extension RunnerTests {
|
|
|
251
254
|
depth: Int,
|
|
252
255
|
parentIndex: Int? = nil,
|
|
253
256
|
hittableOverride: Bool? = nil
|
|
254
|
-
) ->
|
|
257
|
+
) -> PresentedNode? {
|
|
255
258
|
safely("MODAL_NODE") {
|
|
256
259
|
makeSnapshotNode(
|
|
257
260
|
element: element,
|