agent-device 0.21.13 → 0.21.15
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/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.13.apk → agent-device-android-ime-helper-0.21.15.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.15.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.13.manifest.json → agent-device-android-ime-helper-0.21.15.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.13.manifest.json → agent-device-android-snapshot-helper-0.21.15.manifest.json} +6 -6
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +11 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +110 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +4 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerMainOwnedState.swift +27 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.h +8 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.m +26 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +12 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +59 -20
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +2 -3
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +179 -91
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +21 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +9 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +36 -49
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +11 -15
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +136 -29
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +20 -21
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +3 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +6 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +12 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +22 -42
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +15 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +73 -31
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +20 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +9 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +5 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +2 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +51 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +5 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +78 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +32 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +7 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +23 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +17 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +8 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +9 -15
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +12 -11
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotCoordinateSpace.swift +16 -19
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +24 -9
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +66 -10
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +12 -10
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +1 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +27 -5
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -0
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +1 -1
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/adb-transport.js +1 -1
- package/dist/src/agent-browser-provider.js +1 -1
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.js +1 -1
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/android-adb.d.ts +1 -8
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/android-snapshot-quality.js +1 -0
- package/dist/src/android-system-chrome.js +1 -1
- package/dist/src/android.js +1 -1
- package/dist/src/app-catalog.js +1 -1
- package/dist/src/app-deployment-resolution.js +1 -1
- package/dist/src/app-inventory.js +1 -1
- package/dist/src/app-launch.js +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-lifecycle2.js +1 -1
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-runtime2.js +1 -1
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/apple-runner-platform.js +1 -1
- package/dist/src/application-lifecycle-interaction.js +1 -1
- package/dist/src/archive.js +1 -1
- package/dist/src/artifact-download.js +1 -1
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/boot-diagnostics.js +1 -1
- package/dist/src/capture-disclosure.js +1 -1
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +2 -2
- package/dist/src/cli.js +4 -4
- package/dist/src/click-button.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +102 -95
- package/dist/src/clipboard-shell-response.js +1 -1
- package/dist/src/command-schema.js +1 -1
- package/dist/src/command-tools.js +3 -3
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +1 -1
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/debug-symbols-facade.js +1 -1
- package/dist/src/device-claim-rule.js +2 -2
- package/dist/src/device-input-state.d.ts +15 -2
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/device-rotation.js +1 -1
- package/dist/src/device-selection-resolver.js +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/device-shell.js +1 -1
- package/dist/src/device2.js +1 -1
- package/dist/src/devicectl.js +1 -1
- package/dist/src/diagnostics.js +1 -1
- package/dist/src/dispatch-resolve.js +1 -1
- package/dist/src/doctor2.js +1 -1
- package/dist/src/engine-eval-script.js +1 -1
- package/dist/src/error.js +1 -1
- package/dist/src/exec.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/format.js +1 -1
- package/dist/src/gesture-plan-types.d.ts +1 -1
- package/dist/src/gesture-plan.js +1 -1
- package/dist/src/gesture-runtime.js +1 -1
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions2.js +1 -1
- package/dist/src/install-artifact-facade.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-positionals.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-binding.js +1 -1
- package/dist/src/interactor.js +4 -4
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +2 -2
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.js +1 -1
- package/dist/src/inventory.js +1 -1
- package/dist/src/inventory2.js +1 -1
- package/dist/src/inventory3.js +1 -1
- package/dist/src/inventory5.js +1 -1
- package/dist/src/ios-snapshot-acquisition.js +1 -1
- package/dist/src/ios-snapshot-engine.js +1 -0
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-download-file.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +16 -3
- package/dist/src/linux.js +1 -1
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/mechanics.js +17 -17
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/multitouch-support.js +1 -1
- package/dist/src/native-build-cache.js +1 -0
- package/dist/src/observation.js +1 -1
- package/dist/src/overlay.js +3 -0
- package/dist/src/parameterized-recorded-fill.js +1 -1
- package/dist/src/perf-facade.js +1 -1
- package/dist/src/perf-runtime-operation-builder.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +2 -2
- package/dist/src/perf.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-managed-owner.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 +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/png-crop-bytes.js +1 -1
- package/dist/src/png-size.js +1 -1
- package/dist/src/png-worker-client.js +1 -1
- package/dist/src/png.js +1 -1
- package/dist/src/prepare-kind.js +1 -1
- package/dist/src/provider-session-ownership.js +1 -1
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/quality-warnings.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/recording.js +1 -1
- package/dist/src/rect-center.js +1 -1
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +36 -36
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +1 -1
- package/dist/src/replay.js +1 -1
- package/dist/src/reporting.js +1 -1
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-cancel.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/runner-cache-metadata.js +1 -1
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-dev-tools-security.js +1 -1
- package/dist/src/runner-device-readiness.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-error-classification.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-transport-hints.js +1 -1
- package/dist/src/runtime.js +1 -3
- package/dist/src/runtime10.js +2 -2
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +5 -5
- 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/screen-recording-admission-ledger.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -1
- package/dist/src/screen-recording-options.js +1 -1
- package/dist/src/screen-recording-resource-recovery.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-image.js +1 -1
- package/dist/src/screenshot-overlay-draw.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot3.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-command.d.ts +13 -6
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/scroll-gesture.js +1 -1
- package/dist/src/sdk-batch-runner.js +2 -2
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +59 -12
- 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-io.js +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +1 -1
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-allocation.js +1 -1
- package/dist/src/session-routing.js +1 -1
- package/dist/src/session-runtime-admission.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session-store.js +1 -1
- package/dist/src/session.js +1 -1
- package/dist/src/session2.js +4 -4
- package/dist/src/settings.js +1 -1
- package/dist/src/settings2.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-state.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-capture-annotations.js +1 -1
- package/dist/src/snapshot-desktop-projection.js +1 -1
- package/dist/src/snapshot-runtime-binding.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-state.js +1 -1
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src.js +1 -1
- package/dist/src/src4.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/src8.js +1 -1
- package/dist/src/string-enum.js +1 -1
- package/dist/src/surface-snapshot.js +1 -1
- package/dist/src/takeover.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider-facade.js +1 -1
- package/dist/src/tool-provider.js +2 -2
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/transport.js +1 -1
- package/dist/src/tree.js +1 -1
- package/dist/src/tv-remote.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/video.js +1 -1
- package/dist/src/viewport.js +1 -1
- package/dist/src/web.js +1 -1
- package/dist/src/web2.js +1 -1
- package/dist/src/webdriver-source.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk.sha256 +0 -1
- package/dist/src/absence-observation-errors.js +0 -1
- package/dist/src/runner-presentation.js +0 -1
- package/dist/src/semantic-index.js +0 -1
- package/dist/src/snapshot-process.js +0 -1
- package/dist/src/snapshot-scope.js +0 -1
|
@@ -54,11 +54,7 @@ final class RunnerTests: XCTestCase {
|
|
|
54
54
|
let commandExecutionQueue = DispatchQueue(label: "agent-device.runner.commands")
|
|
55
55
|
let app = XCUIApplication()
|
|
56
56
|
lazy var springboard = XCUIApplication(bundleIdentifier: Self.springboardBundleId)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
var currentApp: XCUIApplication?
|
|
60
|
-
var currentBundleId: String?
|
|
61
|
-
var currentAppProcessIdentifier: Int?
|
|
57
|
+
let mainOwned = RunnerMainOwnedState()
|
|
62
58
|
|
|
63
59
|
|
|
64
60
|
var pendingTargetActivation: TargetActivationFactPayload?
|
|
@@ -68,7 +64,7 @@ final class RunnerTests: XCTestCase {
|
|
|
68
64
|
|
|
69
65
|
var textEntryTapWitness: TextEntryTapWitness?
|
|
70
66
|
let maxRequestBytes = 2 * 1024 * 1024
|
|
71
|
-
let mainThreadExecutionTimeout: TimeInterval = 30
|
|
67
|
+
static let mainThreadExecutionTimeout: TimeInterval = 30
|
|
72
68
|
let appExistenceTimeout: TimeInterval = 30
|
|
73
69
|
let retryCooldown: TimeInterval = 0.2
|
|
74
70
|
let postSnapshotInteractionDelay: TimeInterval = 0.2
|
|
@@ -83,27 +79,25 @@ final class RunnerTests: XCTestCase {
|
|
|
83
79
|
|
|
84
80
|
|
|
85
81
|
let recordingFrameCaptureTimeout: TimeInterval = 1
|
|
86
|
-
var needsPostSnapshotInteractionDelay = false
|
|
87
82
|
|
|
88
83
|
|
|
89
84
|
|
|
90
85
|
|
|
91
86
|
var lastLoggedFastAppGuardLine: String?
|
|
92
87
|
var lastLoggedGesturePolicyLines: [SynthesizedGesturePolicyKind: String] = [:]
|
|
93
|
-
var runnerMarkerWriter: (String) -> Void = { NSLog("%@", $0) }
|
|
88
|
+
var runnerMarkerWriter: @MainActor (String) -> Void = { NSLog("%@", $0) }
|
|
94
89
|
|
|
95
90
|
|
|
96
91
|
|
|
97
92
|
|
|
98
93
|
var firstInteractionReadyUptime: TimeInterval?
|
|
99
|
-
var runnerAccessibilityHealth: RunnerAccessibilityHealth = .unknown
|
|
100
94
|
var activeRecording: ScreenRecorder?
|
|
101
95
|
let commandJournal = RunnerCommandJournal()
|
|
102
96
|
|
|
103
97
|
|
|
104
98
|
let inFlightCommandLock = NSLock()
|
|
105
99
|
var inFlightCommandIds: Set<String> = []
|
|
106
|
-
var inFlightCommandWaiters: [String: [((data: Data, shouldFinish: Bool)) -> Void]] = [:]
|
|
100
|
+
var inFlightCommandWaiters: [String: [@Sendable ((data: Data, shouldFinish: Bool)) -> Void]] = [:]
|
|
107
101
|
|
|
108
102
|
|
|
109
103
|
|
|
@@ -206,6 +200,13 @@ final class RunnerTests: XCTestCase {
|
|
|
206
200
|
|
|
207
201
|
|
|
208
202
|
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
209
210
|
|
|
210
211
|
|
|
211
212
|
|
|
@@ -316,7 +317,7 @@ final class RunnerTests: XCTestCase {
|
|
|
316
317
|
deadline: .now() + xctestIdleKeepaliveInterval,
|
|
317
318
|
repeating: xctestIdleKeepaliveInterval
|
|
318
319
|
)
|
|
319
|
-
idleKeepaliveTimer.setEventHandler {
|
|
320
|
+
idleKeepaliveTimer.setEventHandler { @Sendable in
|
|
320
321
|
NSLog("AGENT_DEVICE_RUNNER_IDLE_KEEPALIVE")
|
|
321
322
|
}
|
|
322
323
|
idleKeepaliveTimer.resume()
|
|
@@ -105,7 +105,7 @@ public enum CoordinateSpaceRotation {
|
|
|
105
105
|
|
|
106
106
|
public enum SnapshotGeometrySpace: Equatable {
|
|
107
107
|
case appOrientation
|
|
108
|
-
case deviceNative(appFrame:
|
|
108
|
+
case deviceNative(appFrame: SnapshotViewport.Box, interfaceOrientation: Int)
|
|
109
109
|
|
|
110
110
|
public static let quarterTurnTolerance: Double = 1
|
|
111
111
|
|
|
@@ -116,22 +116,26 @@ public enum SnapshotGeometrySpace: Equatable {
|
|
|
116
116
|
case .deviceNative(let appFrame, let interfaceOrientation):
|
|
117
117
|
return CoordinateSpaceRotation.oriented(
|
|
118
118
|
rect: reportedFrame,
|
|
119
|
-
in: appFrame,
|
|
119
|
+
in: appFrame.rect,
|
|
120
120
|
interfaceOrientation: interfaceOrientation
|
|
121
121
|
)
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/// Only a `.reported` viewport carries an orientation, so only it can anchor a rotation.
|
|
125
126
|
public static func space(
|
|
126
127
|
reportedBySurfaceHost isSurfaceHost: Bool,
|
|
127
128
|
reportedFrame: CGRect,
|
|
128
129
|
inheritedFrom inherited: SnapshotGeometrySpace,
|
|
129
|
-
|
|
130
|
-
interfaceOrientation: Int
|
|
130
|
+
viewport: SnapshotViewport
|
|
131
131
|
) -> SnapshotGeometrySpace {
|
|
132
132
|
guard isSurfaceHost else { return inherited }
|
|
133
|
-
guard
|
|
134
|
-
|
|
133
|
+
guard case .reported(let appFrame, let interfaceOrientation) = viewport,
|
|
134
|
+
namesQuarterTurn(interfaceOrientation),
|
|
135
|
+
isQuarterTurned(reportedFrame, relativeTo: appFrame.rect)
|
|
136
|
+
else {
|
|
137
|
+
return .appOrientation
|
|
138
|
+
}
|
|
135
139
|
return .deviceNative(appFrame: appFrame, interfaceOrientation: interfaceOrientation)
|
|
136
140
|
}
|
|
137
141
|
|
|
@@ -145,7 +149,7 @@ public enum SnapshotGeometrySpace: Equatable {
|
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
private static func isQuarterTurned(_ frame: CGRect, relativeTo appFrame: CGRect) -> Bool {
|
|
148
|
-
guard
|
|
152
|
+
guard SnapshotGeometry.isPositiveFinite(frame),
|
|
149
153
|
abs(appFrame.width - appFrame.height) > quarterTurnTolerance
|
|
150
154
|
else {
|
|
151
155
|
return false
|
|
@@ -153,19 +157,12 @@ public enum SnapshotGeometrySpace: Equatable {
|
|
|
153
157
|
return abs(frame.width - appFrame.height) <= quarterTurnTolerance
|
|
154
158
|
&& abs(frame.height - appFrame.width) <= quarterTurnTolerance
|
|
155
159
|
}
|
|
156
|
-
|
|
157
|
-
private static func isPlottable(_ frame: CGRect) -> Bool {
|
|
158
|
-
frame.origin.x.isFinite && frame.origin.y.isFinite
|
|
159
|
-
&& frame.width.isFinite && frame.height.isFinite
|
|
160
|
-
&& frame.width > 0 && frame.height > 0
|
|
161
|
-
}
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
extension SnapshotGeometrySpace {
|
|
165
163
|
public static func normalized(
|
|
166
164
|
nodes: [RawAXNode],
|
|
167
|
-
viewport:
|
|
168
|
-
interfaceOrientation: Int
|
|
165
|
+
viewport: SnapshotViewport
|
|
169
166
|
) -> [RawAXNode] {
|
|
170
167
|
let carriers = SnapshotVisibilityFold.visibilityExemptCarrierTypes
|
|
171
168
|
var spaces = [SnapshotGeometrySpace](repeating: .appOrientation, count: nodes.count)
|
|
@@ -180,16 +177,16 @@ extension SnapshotGeometrySpace {
|
|
|
180
177
|
),
|
|
181
178
|
reportedFrame: node.rect.cgRect,
|
|
182
179
|
inheritedFrom: parentIndex.map { spaces[$0] } ?? .appOrientation,
|
|
183
|
-
|
|
184
|
-
interfaceOrientation: interfaceOrientation
|
|
180
|
+
viewport: viewport
|
|
185
181
|
)
|
|
186
182
|
spaces[position] = nodeSpace
|
|
187
183
|
let frame = nodeSpace.orientedFrame(of: node.rect.cgRect)
|
|
188
184
|
result.append(
|
|
189
185
|
node.replacing(
|
|
190
186
|
rect: SnapshotRect(frame),
|
|
191
|
-
hittable: node.parentIndex
|
|
192
|
-
|
|
187
|
+
hittable: node.parentIndex == nil
|
|
188
|
+
? false
|
|
189
|
+
: SnapshotGeometry.isGeometricallyActionable(
|
|
193
190
|
enabled: node.enabled,
|
|
194
191
|
frame: frame,
|
|
195
192
|
viewport: viewport
|
|
@@ -2,14 +2,26 @@ import Foundation
|
|
|
2
2
|
import CoreGraphics
|
|
3
3
|
|
|
4
4
|
public enum SnapshotGeometry {
|
|
5
|
+
/// Twin of `isPositiveFiniteRect` in `packages/kernel/src/rect.ts`, and the one place the
|
|
6
|
+
/// `hittable` rule asks whether a box may be plotted or measured (#2891). Three refusals, each
|
|
7
|
+
/// reachable by a different input: a non-finite component, a finite box wide enough to overflow
|
|
8
|
+
/// its own right or bottom edge, and `CGRect.infinite`, which is built of finite components and
|
|
9
|
+
/// finite extents and so is refused by identity alone.
|
|
10
|
+
public static func isPositiveFinite(_ rect: CGRect) -> Bool {
|
|
11
|
+
!rect.isInfinite
|
|
12
|
+
&& rect.minX.isFinite && rect.minY.isFinite
|
|
13
|
+
&& rect.maxX.isFinite && rect.maxY.isFinite
|
|
14
|
+
&& rect.size.width > 0 && rect.size.height > 0
|
|
15
|
+
}
|
|
16
|
+
|
|
5
17
|
public static func effectiveFrame(
|
|
6
18
|
reportedFrame: CGRect,
|
|
7
|
-
viewport:
|
|
19
|
+
viewport: SnapshotViewport,
|
|
8
20
|
ancestorClip: CGRect?
|
|
9
21
|
) -> CGRect {
|
|
10
22
|
var frame = reportedFrame
|
|
11
|
-
if
|
|
12
|
-
frame = clipped(frame, to:
|
|
23
|
+
if let box = viewport.rect {
|
|
24
|
+
frame = clipped(frame, to: box)
|
|
13
25
|
}
|
|
14
26
|
if let ancestorClip {
|
|
15
27
|
frame = clipped(frame, to: ancestorClip)
|
|
@@ -34,15 +46,18 @@ public enum SnapshotGeometry {
|
|
|
34
46
|
)
|
|
35
47
|
}
|
|
36
48
|
|
|
49
|
+
/// The shared `hittable` predicate (#1933), twin of `isGeometricallyActionable` in
|
|
50
|
+
/// `packages/kernel/src/rect.ts`, with `CGRect.contains`'s half-open right and bottom edges.
|
|
51
|
+
/// `nil` when only containment is left to decide and the capture has no viewport box: the node's
|
|
52
|
+
/// `hittable` is then absent on the wire, as it is on the host bridge (#2891).
|
|
37
53
|
public static func isGeometricallyActionable(
|
|
38
54
|
enabled: Bool,
|
|
39
55
|
frame: CGRect,
|
|
40
|
-
viewport:
|
|
41
|
-
) -> Bool {
|
|
42
|
-
guard enabled,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return viewport.contains(center)
|
|
56
|
+
viewport: SnapshotViewport
|
|
57
|
+
) -> Bool? {
|
|
58
|
+
guard enabled, isPositiveFinite(frame) else { return false }
|
|
59
|
+
guard let box = viewport.rect else { return nil }
|
|
60
|
+
return box.contains(CGPoint(x: frame.midX, y: frame.midY))
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
private static func clipped(_ frame: CGRect, to clip: CGRect) -> CGRect {
|
|
@@ -34,11 +34,14 @@ public struct RawAXNode: Equatable {
|
|
|
34
34
|
public let label: String?
|
|
35
35
|
public let identifier: String?
|
|
36
36
|
public let value: String?
|
|
37
|
+
/// The text a text field shows while empty (`placeholderValue`); `nil` for every other node.
|
|
38
|
+
public let placeholder: String?
|
|
37
39
|
public var rect: SnapshotRect
|
|
38
40
|
public let enabled: Bool
|
|
39
41
|
public let focused: Bool?
|
|
40
42
|
public let selected: Bool?
|
|
41
|
-
|
|
43
|
+
/// Geometric actionability; `nil` when the capture has no viewport box to decide it against.
|
|
44
|
+
public var hittable: Bool?
|
|
42
45
|
public let depth: Int
|
|
43
46
|
public let parentIndex: Int?
|
|
44
47
|
public let hiddenContentAbove: Bool?
|
|
@@ -51,11 +54,12 @@ public struct RawAXNode: Equatable {
|
|
|
51
54
|
label: String?,
|
|
52
55
|
identifier: String?,
|
|
53
56
|
value: String?,
|
|
57
|
+
placeholder: String? = nil,
|
|
54
58
|
rect: SnapshotRect,
|
|
55
59
|
enabled: Bool,
|
|
56
60
|
focused: Bool?,
|
|
57
61
|
selected: Bool?,
|
|
58
|
-
hittable: Bool
|
|
62
|
+
hittable: Bool?,
|
|
59
63
|
depth: Int,
|
|
60
64
|
parentIndex: Int?,
|
|
61
65
|
hiddenContentAbove: Bool?,
|
|
@@ -67,6 +71,7 @@ public struct RawAXNode: Equatable {
|
|
|
67
71
|
self.label = label
|
|
68
72
|
self.identifier = identifier
|
|
69
73
|
self.value = value
|
|
74
|
+
self.placeholder = placeholder
|
|
70
75
|
self.rect = rect
|
|
71
76
|
self.enabled = enabled
|
|
72
77
|
self.focused = focused
|
|
@@ -79,7 +84,7 @@ public struct RawAXNode: Equatable {
|
|
|
79
84
|
self.actions = actions
|
|
80
85
|
}
|
|
81
86
|
|
|
82
|
-
func replacing(rect: SnapshotRect, hittable: Bool) -> RawAXNode {
|
|
87
|
+
func replacing(rect: SnapshotRect, hittable: Bool?) -> RawAXNode {
|
|
83
88
|
var updated = self
|
|
84
89
|
updated.rect = rect
|
|
85
90
|
updated.hittable = hittable
|
|
@@ -153,15 +158,66 @@ public struct PresentationOptions: Equatable {
|
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
160
|
|
|
161
|
+
/// What a capture knows about the viewport hosting its tree: the three cases of the host's
|
|
162
|
+
/// `IosViewportEvidence` (#2891). No rectangle stands for "unknown".
|
|
163
|
+
public enum SnapshotViewport: Equatable {
|
|
164
|
+
/// A box that was checked on the way in. The initializer is the only gate: no caller, inside this
|
|
165
|
+
/// package or outside it, holds a `Box` whose rectangle `SnapshotGeometry.isPositiveFinite`
|
|
166
|
+
/// refuses, so a `.reported` case never needs re-checking what it was handed.
|
|
167
|
+
public struct Box: Equatable {
|
|
168
|
+
public let rect: CGRect
|
|
169
|
+
|
|
170
|
+
init?(checked rect: CGRect) {
|
|
171
|
+
guard SnapshotGeometry.isPositiveFinite(rect) else { return nil }
|
|
172
|
+
self.rect = rect
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/// The platform's box for the app's surface, with the interface orientation read in the same hop.
|
|
177
|
+
/// Only this case can anchor a rotation (#2612).
|
|
178
|
+
case reported(Box, interfaceOrientation: Int)
|
|
179
|
+
/// A box the capture inferred from its own root element. It clips and contains, and carries no
|
|
180
|
+
/// orientation, so it cannot anchor a rotation.
|
|
181
|
+
case derived(Box)
|
|
182
|
+
case missing(reason: MissingReason)
|
|
183
|
+
|
|
184
|
+
public enum MissingReason: Equatable {
|
|
185
|
+
/// The read was skipped or raised.
|
|
186
|
+
case notProvided
|
|
187
|
+
/// The box read is one `SnapshotGeometry.isPositiveFinite` refuses.
|
|
188
|
+
case invalid
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public var rect: CGRect? {
|
|
192
|
+
switch self {
|
|
193
|
+
case .reported(let box, _), .derived(let box):
|
|
194
|
+
return box.rect
|
|
195
|
+
case .missing:
|
|
196
|
+
return nil
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public static func reported(
|
|
201
|
+
box: CGRect,
|
|
202
|
+
interfaceOrientation: Int = RunnerInterfaceOrientation.unknown
|
|
203
|
+
) -> SnapshotViewport {
|
|
204
|
+
guard let checked = Box(checked: box) else { return .missing(reason: .invalid) }
|
|
205
|
+
return .reported(checked, interfaceOrientation: interfaceOrientation)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public static func derived(box: CGRect) -> SnapshotViewport {
|
|
209
|
+
guard let checked = Box(checked: box) else { return .missing(reason: .invalid) }
|
|
210
|
+
return .derived(checked)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
156
214
|
public struct SnapshotAcquisition {
|
|
157
215
|
public let hint: CaptureHint
|
|
158
216
|
public var nodes: [RawAXNode]
|
|
159
217
|
public let truncated: Bool
|
|
160
218
|
public let effectiveDepth: Int?
|
|
161
219
|
public var customActions: SnapshotCustomActionCoverage?
|
|
162
|
-
public let viewport:
|
|
163
|
-
/// The app's interface orientation, consumed by the one `normalized` pass; `unknown` turns nothing.
|
|
164
|
-
public let interfaceOrientation: Int
|
|
220
|
+
public let viewport: SnapshotViewport
|
|
165
221
|
|
|
166
222
|
public init(
|
|
167
223
|
hint: CaptureHint,
|
|
@@ -169,8 +225,7 @@ public struct SnapshotAcquisition {
|
|
|
169
225
|
truncated: Bool,
|
|
170
226
|
effectiveDepth: Int?,
|
|
171
227
|
customActions: SnapshotCustomActionCoverage? = nil,
|
|
172
|
-
viewport:
|
|
173
|
-
interfaceOrientation: Int = 0
|
|
228
|
+
viewport: SnapshotViewport
|
|
174
229
|
) {
|
|
175
230
|
self.hint = hint
|
|
176
231
|
self.nodes = nodes
|
|
@@ -178,7 +233,6 @@ public struct SnapshotAcquisition {
|
|
|
178
233
|
self.effectiveDepth = effectiveDepth
|
|
179
234
|
self.customActions = customActions
|
|
180
235
|
self.viewport = viewport
|
|
181
|
-
self.interfaceOrientation = interfaceOrientation
|
|
182
236
|
}
|
|
183
237
|
|
|
184
238
|
public func replacingNodes(_ nodes: [RawAXNode]) -> SnapshotAcquisition {
|
|
@@ -222,11 +276,12 @@ public struct PresentedNode: Codable, Equatable {
|
|
|
222
276
|
public let label: String?
|
|
223
277
|
public let identifier: String?
|
|
224
278
|
public let value: String?
|
|
279
|
+
public let placeholder: String?
|
|
225
280
|
public let rect: SnapshotRect
|
|
226
281
|
public let enabled: Bool
|
|
227
282
|
public let focused: Bool?
|
|
228
283
|
public let selected: Bool?
|
|
229
|
-
public let hittable: Bool
|
|
284
|
+
public let hittable: Bool?
|
|
230
285
|
public let depth: Int
|
|
231
286
|
public let parentIndex: Int?
|
|
232
287
|
public let hiddenContentAbove: Bool?
|
|
@@ -245,6 +300,7 @@ public struct PresentedNode: Codable, Equatable {
|
|
|
245
300
|
self.label = raw.label
|
|
246
301
|
self.identifier = raw.identifier
|
|
247
302
|
self.value = raw.value
|
|
303
|
+
self.placeholder = raw.placeholder
|
|
248
304
|
self.rect = rect ?? raw.rect
|
|
249
305
|
self.enabled = raw.enabled
|
|
250
306
|
self.focused = raw.focused
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import CoreGraphics
|
|
3
3
|
|
|
4
|
+
/// With no viewport box the cumulative clip has no root, so containment has nothing to violate.
|
|
4
5
|
public enum SnapshotPresentationInvariant {
|
|
5
6
|
struct ValidationStats: Equatable {
|
|
6
7
|
let parentClipLookups: Int
|
|
@@ -12,7 +13,7 @@ public enum SnapshotPresentationInvariant {
|
|
|
12
13
|
|
|
13
14
|
public static func validateRegular(
|
|
14
15
|
_ nodes: [SnapshotPresentationNode],
|
|
15
|
-
viewport:
|
|
16
|
+
viewport: SnapshotViewport,
|
|
16
17
|
policy: SnapshotVisibilityFold.Policy
|
|
17
18
|
) throws {
|
|
18
19
|
_ = try validateRegularWithStats(nodes, viewport: viewport, policy: policy)
|
|
@@ -20,24 +21,25 @@ public enum SnapshotPresentationInvariant {
|
|
|
20
21
|
|
|
21
22
|
static func validateRegularWithStats(
|
|
22
23
|
_ nodes: [SnapshotPresentationNode],
|
|
23
|
-
viewport:
|
|
24
|
+
viewport: SnapshotViewport,
|
|
24
25
|
policy: SnapshotVisibilityFold.Policy
|
|
25
26
|
) throws -> ValidationStats {
|
|
26
27
|
var parentClipLookups = 0
|
|
27
|
-
var clipIncludingNodeByIndex: [Int: CGRect] = [:]
|
|
28
|
+
var clipIncludingNodeByIndex: [Int: CGRect?] = [:]
|
|
28
29
|
clipIncludingNodeByIndex.reserveCapacity(nodes.count)
|
|
30
|
+
let rootClip = viewport.rect
|
|
29
31
|
|
|
30
32
|
for node in nodes {
|
|
31
|
-
let ancestorClip: CGRect
|
|
33
|
+
let ancestorClip: CGRect?
|
|
32
34
|
if let parentIndex = node.raw.parentIndex {
|
|
33
35
|
parentClipLookups += 1
|
|
34
|
-
ancestorClip = clipIncludingNodeByIndex[parentIndex] ??
|
|
36
|
+
ancestorClip = clipIncludingNodeByIndex[parentIndex] ?? rootClip
|
|
35
37
|
} else {
|
|
36
|
-
ancestorClip =
|
|
38
|
+
ancestorClip = rootClip
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
let frame = node.effectiveRect.cgRect
|
|
40
|
-
let clipIncludingNode: CGRect
|
|
42
|
+
let clipIncludingNode: CGRect?
|
|
41
43
|
if policy == .cursorProjected,
|
|
42
44
|
SnapshotVisibilityFold.scrollContainerTypeNames.contains(node.raw.type),
|
|
43
45
|
!frame.isNull,
|
|
@@ -50,7 +52,7 @@ public enum SnapshotPresentationInvariant {
|
|
|
50
52
|
clipIncludingNodeByIndex[node.raw.index] = clipIncludingNode
|
|
51
53
|
|
|
52
54
|
guard !frame.isNull, !frame.isEmpty else {
|
|
53
|
-
if node.raw.hittable {
|
|
55
|
+
if node.raw.hittable == true {
|
|
54
56
|
throw SnapshotPresentationFailure.regularDegenerateNodeIsActionable(
|
|
55
57
|
index: node.raw.index,
|
|
56
58
|
frame: node.effectiveRect
|
|
@@ -59,11 +61,11 @@ public enum SnapshotPresentationInvariant {
|
|
|
59
61
|
continue
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
if let clip = ancestorClip, !contains(frame, in: clip) {
|
|
63
65
|
throw SnapshotPresentationFailure.regularNodeOutsideCumulativeClip(
|
|
64
66
|
index: node.raw.index,
|
|
65
67
|
frame: node.effectiveRect,
|
|
66
|
-
clip: SnapshotRect(
|
|
68
|
+
clip: SnapshotRect(clip)
|
|
67
69
|
)
|
|
68
70
|
}
|
|
69
71
|
}
|
|
@@ -100,7 +100,7 @@ public enum SnapshotVisibilityFold {
|
|
|
100
100
|
public static func traversalDecision(
|
|
101
101
|
for node: RawAXNode,
|
|
102
102
|
parent: TraversalState,
|
|
103
|
-
viewport:
|
|
103
|
+
viewport: SnapshotViewport,
|
|
104
104
|
interactiveOnly: Bool,
|
|
105
105
|
hasChildren: Bool,
|
|
106
106
|
policy: Policy
|
|
@@ -153,7 +153,7 @@ public enum SnapshotVisibilityFold {
|
|
|
153
153
|
|
|
154
154
|
public static func fold(
|
|
155
155
|
_ nodes: [RawAXNode],
|
|
156
|
-
viewport:
|
|
156
|
+
viewport: SnapshotViewport,
|
|
157
157
|
interactiveOnly: Bool,
|
|
158
158
|
policy: Policy
|
|
159
159
|
) -> [SnapshotPresentationNode] {
|
|
@@ -199,14 +199,17 @@ public enum SnapshotVisibilityFold {
|
|
|
199
199
|
label: node.label,
|
|
200
200
|
identifier: node.identifier,
|
|
201
201
|
value: node.value,
|
|
202
|
+
placeholder: node.placeholder,
|
|
202
203
|
rect: node.rect,
|
|
203
204
|
enabled: node.enabled,
|
|
204
205
|
focused: node.focused,
|
|
205
206
|
selected: node.selected,
|
|
206
|
-
hittable: node.parentIndex
|
|
207
|
-
|
|
207
|
+
hittable: node.parentIndex == nil
|
|
208
|
+
? false
|
|
209
|
+
: clippedHittability(
|
|
210
|
+
source: node.hittable,
|
|
208
211
|
enabled: node.enabled,
|
|
209
|
-
|
|
212
|
+
clippedFrame: decision.effectiveFrame,
|
|
210
213
|
viewport: viewport
|
|
211
214
|
),
|
|
212
215
|
depth: outDepth,
|
|
@@ -239,4 +242,23 @@ public enum SnapshotVisibilityFold {
|
|
|
239
242
|
return applyHiddenContentHints(hints, to: kept)
|
|
240
243
|
}
|
|
241
244
|
|
|
245
|
+
/// The fold's share of the `hittable` policy (#2891). A declared `false` is kept; anything the
|
|
246
|
+
/// source left undecided is re-decided on the clipped frame: a disabled or degenerate frame —
|
|
247
|
+
/// including a `visibilityExempt` carrier a scroll anchor clipped to nothing — answers `false`,
|
|
248
|
+
/// and `nil` stays reserved for the one question the clipped frame cannot answer, containment
|
|
249
|
+
/// while the capture has no viewport box.
|
|
250
|
+
private static func clippedHittability(
|
|
251
|
+
source: Bool?,
|
|
252
|
+
enabled: Bool,
|
|
253
|
+
clippedFrame: CGRect,
|
|
254
|
+
viewport: SnapshotViewport
|
|
255
|
+
) -> Bool? {
|
|
256
|
+
if source == false { return false }
|
|
257
|
+
return SnapshotGeometry.isGeometricallyActionable(
|
|
258
|
+
enabled: enabled,
|
|
259
|
+
frame: clippedFrame,
|
|
260
|
+
viewport: viewport
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
|
|
242
264
|
}
|
package/dist/src/adapter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{D as e,F as t}from"./sdk-contracts.js";import{Gr as n,Ur as r,Wr as i}from"./sdk-batch.js";import{c as a,r as o}from"./diagnostics.js";import{f as s,x as c}from"./owner-identity.js";import{c as l,l as u,m as d,r as f}from"./exec.js";import{n as p,t as m}from"./file.js";import"./diagnostics2.js";import"./command.js";import{n as ee}from"./retry.js";import{r as te}from"./version.js";import"./process.js";import{C as ne,D as re,c as ie,f as ae,h as oe,n as se,o as ce,w as le,y as ue}from"./host-file.js";import{t as h}from"./apple-runner-platform.js";import{t as de}from"./simctl.js";import{n as fe,r as g,t as pe}from"./snapshot-process.js";import _ from"node:path";import{createHash as v,randomUUID as y}from"node:crypto";import me from"node:net";import{Buffer as b}from"node:buffer";const he={unsupported:`UNSUPPORTED_OPERATION`,"malformed-tree":`COMMAND_FAILED`,"stale-target":`COMMAND_FAILED`,timeout:`COMMAND_FAILED`,cancelled:`COMMAND_FAILED`,"process-crash":`COMMAND_FAILED`,"transport-failure":`COMMAND_FAILED`,preparing:`COMMAND_FAILED`};var x=class extends e{failureKind;failureCode;constructor(e,t,n=`iOS Simulator snapshot source ${e}: ${t}`,r={},i){super(he[e],n,{...r,bridgeFailure:e,bridgeFailureCode:t,...e===`cancelled`?{reason:`request_canceled`}:{}},i),this.name=`SnapshotSourceError`,this.failureKind=e,this.failureCode=t}};function S(e,t,n={},r){return new x(e,t,void 0,n,r)}function C(n){return n instanceof x?n:t(n)?S(`cancelled`,`abort-signal`,{},n):n instanceof e&&typeof n.details?.timeoutMs==`number`?S(`timeout`,`host-operation-timeout`,{timeoutMs:n.details.timeoutMs},n):S(`transport-failure`,`unexpected-host-error`,{error:n instanceof Error?n.message:String(n)},n)}function w(e,t,n=Date.now){if(t?.aborted)throw S(`cancelled`,`abort-signal`);return{clock:ee.fromTimeoutMs(e,n()),now:n,signal:t}}function T(e,t){if(e.signal?.aborted)throw S(`cancelled`,`abort-signal`);let n=e.clock.remainingMs(e.now());if(n<=0)throw S(`timeout`,t);return Math.max(1,Math.floor(n))}async function E(e,t,n,r){let i=Math.min(t,T(e,n));await g({waitMs:i,signal:e.signal,stop:r,cancelled:()=>S(`cancelled`,`abort-signal`)})}var ge=class{entries=new Map;probeBackAfterUses;constructor(e=8){this.probeBackAfterUses=e}consume(e,t,n){if(n)return{nativeLevels:void 0,reason:`explicit-depth`};let r=this.currentEntry(e);return r===`unidentified`?{nativeLevels:void 0,reason:`unidentified-target`}:!r||r.nativeLevels>=t?{nativeLevels:void 0,reason:`no-hint`}:r.remainingUses<=0?{nativeLevels:void 0,reason:`probe-back`}:(--r.remainingUses,{nativeLevels:r.nativeLevels,reason:`hinted`})}learn(e,t,n,r){return n||!e.targetId?`ignored`:r.rejected>0&&r.acceptedLevels<t?(this.remember(e.targetId,{generation:e.generation,nativeLevels:r.acceptedLevels,remainingUses:this.probeBackAfterUses}),`learned`):r.rejected===0&&r.acceptedLevels>=t?this.entries.delete(e.targetId)?`forgotten`:`ignored`:this.currentEntry(e)?`kept`:`ignored`}currentEntry(e){if(!e.targetId)return`unidentified`;let t=this.entries.get(e.targetId);if(t){if(t.generation!==e.generation){this.entries.delete(e.targetId);return}return t}}remember(e,t){if(this.entries.delete(e),this.entries.size>=32){let e=this.entries.keys().next().value;e!==void 0&&this.entries.delete(e)}this.entries.set(e,t)}};const D=65536;function _e(){return{projectRoot:te,homeDirectory:ae,run:async(e,t,n)=>await l(e,t,n),start:ve,connect:ye,readText:ue,readBinary:oe,writeText:re,ensureDirectory:ce,chmod:se,exists:ie,rename:le,remove:ne,acquireLock:be,emitDiagnostic:o,withDiagnosticTimer:a,processId:s,readTargetProcessStartTime:pe}}function ve(e,t,n,r={}){if(r.signal?.aborted)throw S(`cancelled`,`abort-signal`);let i=u(`xcrun`,de([`spawn`,e.udid,t,`serve`,n,`--idle-timeout`,`60`,`--exit-on-disconnect`,`false`],{simulatorSetPath:e.simulatorSetPath}),{allowFailure:!0,captureOutput:!1,detached:!0}),a=i.child.pid??0;if(a<=0)throw S(`transport-failure`,`bridge-process-pid-missing`);let o=``;return i.child.stderr?.setEncoding(`utf8`),i.child.stderr?.on(`data`,e=>{o=xe(o,String(e))}),{pid:a,wait:i.wait,isAlive:()=>i.child.exitCode===null&&i.child.signalCode===null,signal:e=>{d(a,e)||i.child.kill(e)},readLog:()=>o}}async function ye(e,t){if(t.signal?.aborted)throw S(`cancelled`,`abort-signal`);let n=Math.max(1,Math.floor(t.timeoutMs));return await new Promise((r,i)=>{let a=me.createConnection({path:e}),o=!1,s=!1,c=setTimeout(()=>{p(S(`timeout`,`bridge-connect-timeout`)),a.destroy()},n),l=()=>{p(S(`cancelled`,`abort-signal`)),a.destroy()},u=()=>{o=!0,clearTimeout(c),t.signal?.removeEventListener(`abort`,l),a.off(`error`,d),a.off(`close`,f),a.setTimeout(0),r(a)},d=e=>{p(e),a.destroy()},f=()=>{o||p(S(`transport-failure`,`bridge-closed-before-connect`))},p=e=>{s||o||(s=!0,clearTimeout(c),t.signal?.removeEventListener(`abort`,l),a.off(`connect`,u),a.off(`error`,d),a.off(`close`,f),i(e))};a.once(`connect`,u),a.once(`error`,d),a.once(`close`,f),t.signal?.addEventListener(`abort`,l,{once:!0}),t.signal?.aborted&&l()})}async function be(e,t){let n=s(),r=t.deadline,i=m({lockDirPath:e,owner:{pid:n,startTime:c(n),acquiredAtMs:Date.now()},timeoutMs:T(r,`cache-lock-deadline`),pollMs:100,ownerGraceMs:5e3,description:`iOS Simulator snapshot bridge cache`}),a=r.signal;if(!a)return await i;let o=!1,l,u=new Promise((e,t)=>{l=()=>{o=!0,t(S(`cancelled`,`abort-signal`))},a.addEventListener(`abort`,l,{once:!0}),a.aborted&&l()});try{return await Promise.race([i,u])}catch(e){throw o&&i.then(e=>e().catch(()=>void 0),()=>void 0),r.clock.isExpired()&&!(e instanceof x&&e.failureKind===`cancelled`)?S(`timeout`,`cache-lock-deadline`):e}finally{a.removeEventListener(`abort`,l)}}function xe(e,t){let n=e+t;return n.length<=D?n:n.slice(n.length-D)}function Se(e,t,n){let r=v(`sha256`).update(t).digest(`hex`).slice(0,12),i=v(`sha256`).update(n).digest(`hex`).slice(0,12);return _.join(`/tmp`,`agent-device-ax-${r}-${e.processId()}-${i}`,`snapshot.sock`)}const O=new WeakSet;async function k(e,t){let n;try{n=(await t.wait).exitCode}catch{n=void 0}return O.has(t)||(O.add(t),e.emitDiagnostic({level:`error`,phase:`ios.snapshot-source.bridge-process-exit`,data:{pid:t.pid,...n===void 0?{}:{exitCode:n},stderr:A(t.readLog())}})),S(`process-crash`,`bridge-exited`,{pid:t.pid,...n===void 0?{}:{exitCode:n}})}function A(e){let t=b.from(e);return t.length<=65536?e:t.subarray(-65536).toString(`utf8`)}const j=`agent-device-simulator-ax-v1.7.0`;Object.freeze([`verb`,`requestId`,`pid`,`generation`,`snapshotTree`,`automationMode`,`maxDepth`,`maxNodes`,`maxDurationMs`,`maxResponseBytes`,`nativeLevelsHint`]),Object.freeze([`protocolVersion`,`sourceVersion`,`requestId`,`generation`,`ok`,`pid`,`tree`,`truncated`,`automationEnabled`,`recovery`,`error_kind`,`error_code`,`error`]),Object.freeze([`XC_kAXXCAttributeElementType`,`XC_kAXXCAttributeElementBaseType`,`XC_kAXXCAttributeLabel`,`XC_kAXXCAttributeValue`,`XC_kAXXCAttributeIdentifier`,`XC_kAXXCAttributeFrame`,`XC_kAXXCAttributeAutomationType`,`XC_kAXXCAttributeTraits`,`XC_kAXXCAttributeIsUserInteractionEnabled`,`XC_kAXXCAttributeChildren`]);const Ce=[`requests`,`rejected`,`continuations`,`acceptedLevels`];function we(e){let t=e.recovery;if(!M(t))throw S(`malformed-tree`,`recovery-invalid`);let n=Ce.map(e=>[e,t[e]]);if(n.some(([,e])=>!Number.isSafeInteger(e)||e<0))throw S(`malformed-tree`,`recovery-invalid`);return Object.freeze(Object.fromEntries(n))}function Te(e,t){let n;try{n=b.from(JSON.stringify(e),`utf8`)}catch(e){throw S(`malformed-tree`,`request-not-json`,{},e)}let r=n.length+4;if(r>t.maxRequestBytes)throw S(`transport-failure`,`request-limit-exceeded`,{frameBytes:r,maxRequestBytes:t.maxRequestBytes});let i=b.alloc(4);return i.writeUInt32BE(n.length,0),b.concat([i,n])}var Ee=class{header=b.alloc(4);headerBytes=0;chunks=[];payloadBytes=0;expectedBodyBytes;frame;maxFrameBytes;constructor(e){if(!Number.isSafeInteger(e)||e<=0)throw S(`malformed-tree`,`frame-limit-invalid`,{maxFrameBytes:e});this.maxFrameBytes=e}push(e){if(this.frame)return this.acceptTrailingChunk(e);let t=this.readHeader(e);if(t&&(this.appendPayload(e,t.offset,t.bodyBytes),this.payloadBytes===t.bodyBytes))return this.frame=b.concat(this.chunks,t.bodyBytes),this.frame}acceptTrailingChunk(e){if(e.length>0)throw S(`malformed-tree`,`multiple-frames`,{trailingBytes:e.length});return this.frame}readHeader(e){if(this.headerBytes===4)return{offset:0,bodyBytes:this.expectedBodyBytes};let t=Math.min(4-this.headerBytes,e.length);if(e.copy(this.header,this.headerBytes,0,t),this.headerBytes+=t,this.headerBytes<4)return;let n=this.header.readUInt32BE(0);if(n===0||n>this.maxFrameBytes)throw S(`malformed-tree`,`frame-limit-exceeded`,{bodyBytes:n,maxFrameBytes:this.maxFrameBytes});return this.expectedBodyBytes=n,{offset:t,bodyBytes:n}}appendPayload(e,t,n){let r=n-this.payloadBytes,i=e.length-t;if(i>r)throw S(`malformed-tree`,`multiple-frames`,{trailingBytes:i-r});i!==0&&(this.chunks.push(e.subarray(t)),this.payloadBytes+=i)}finish(){if(this.frame)return this.frame;throw S(`transport-failure`,`bridge-frame-incomplete`,{headerBytes:this.headerBytes,payloadBytes:this.payloadBytes,expectedBodyBytes:this.expectedBodyBytes})}};function De(e){let t;try{t=JSON.parse(e.toString(`utf8`))}catch(e){throw S(`malformed-tree`,`response-not-json`,{},e)}if(!M(t))throw S(`malformed-tree`,`response-not-object`);return t}function Oe(e){return Object.freeze({verb:`describe`,requestId:e.requestId,pid:e.pid,generation:e.generation,snapshotTree:!0,automationMode:!0,maxDepth:e.maxDepth,maxNodes:e.maxNodes,maxDurationMs:e.maxDurationMs,maxResponseBytes:e.maxResponseBytes,...e.nativeLevelsHint===void 0?{}:{nativeLevelsHint:e.nativeLevelsHint}})}function ke(e,t){if(e.protocolVersion!==1)throw S(`transport-failure`,`protocol-version-mismatch`,{expected:1,observed:e.protocolVersion});if(e.sourceVersion!==`agent-device-simulator-ax-v1.7.0`)throw S(`transport-failure`,`source-version-mismatch`,{expected:j,observed:e.sourceVersion});if(e.requestId!==t)throw S(`transport-failure`,`request-id-mismatch`,{expected:t,observed:e.requestId})}function Ae(e,t){if(typeof e.pid!=`number`||e.pid!==t.pid)throw S(`stale-target`,`bridge-pid-mismatch`,{expectedPid:t.pid,observedPid:e.pid});if(e.generation!==t.generation)throw S(`stale-target`,`bridge-generation-mismatch`,{expectedGeneration:t.generation,observedGeneration:e.generation})}function je(e){let t=e.error_kind,n=typeof e.error_code==`string`?e.error_code:`guest-error`,r=typeof e.error==`string`?e.error:void 0,i=r?{guestMessage:r.slice(0,1024)}:{};throw S(t===`unsupported`?`unsupported`:t===`malformed_tree`?`malformed-tree`:t===`application_not_responding`?`timeout`:t===`application_unavailable`?`transport-failure`:t===`bad_request`?`malformed-tree`:`transport-failure`,n,i)}function M(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function Me(e){let t=new Ee(e.limits.maxResponseBytes-4),n=T(e.deadline,`bridge-request-deadline`);return await new Promise((r,i)=>{let a=!1,o=!1,s=setTimeout(()=>{p(S(`timeout`,`bridge-request-deadline`,{dispatched:o})),e.socket.destroy()},n),c=()=>{p(S(`cancelled`,`abort-signal`,{dispatched:o})),e.socket.destroy()},l=n=>{try{if(!Buffer.isBuffer(n))throw S(`transport-failure`,`bridge-data-invalid`);let r=t.push(n);if(r){let t=De(r);if(ke(t,e.requestId),Ae(t,{pid:e.expectedPid,generation:e.expectedGeneration}),t.ok!==!0&&je(t),typeof t.truncated!=`boolean`)throw S(`malformed-tree`,`truncated-invalid`);f(t);return}}catch(t){p(t),e.socket.destroy()}},u=e=>p(C(e)),d=()=>{a||(e.process.isAlive()?p(S(`transport-failure`,`bridge-connection-closed`)):k(e.host,e.process).then(p))};e.process.wait.then(()=>{a||k(e.host,e.process).then(p)},e=>{a||p(C(e))});let f=e=>m(()=>r(e)),p=e=>m(()=>i(e)),m=t=>{a||(a=!0,clearTimeout(s),e.deadline.signal?.removeEventListener(`abort`,c),e.socket.off(`data`,l),e.socket.off(`error`,u),e.socket.off(`close`,d),t())};e.socket.on(`data`,l),e.socket.on(`error`,u),e.socket.on(`close`,d),e.deadline.signal?.addEventListener(`abort`,c,{once:!0});try{if(e.deadline.signal?.aborted)throw S(`cancelled`,`abort-signal`);o=!0,e.socket.write(e.frame)}catch(t){p(C(t)),e.socket.destroy()}})}var Ne=class{sessions=new Map;requestQueues=new Map;ownerId=y();closed=!1;host;constructor(e){this.host=e}async request(e){if(this.closed)throw S(`unsupported`,`source-closed`);return await this.withSimulatorLock(e.target.udid,e.deadline,()=>this.requestInSimulator(e))}async requestInSimulator(e){if(this.closed)throw S(`unsupported`,`source-closed`);let t=e.deadline;T(t,`bridge-request-deadline`);let n=this.sessions.get(e.target.udid),r=await this.ensureSession(e,t);try{let n=await this.readTargetStartTime(e.target,t),i=await this.exchange(r,e,t);return await this.assertTargetStillCurrent(e.target,n,t),i}catch(e){throw await this.handleRequestFailure(e,r,n)}}async handleRequestFailure(e,t,n){let r=C(e);return Fe(r,t,n)?await this.removeSession(t,!0):r.failureKind===`process-crash`?await this.removeSession(t,!1):r.failureKind===`transport-failure`&&(t.socket?.destroy(),t.socket=void 0),r}async withSimulatorLock(e,t,n){let r=this.requestQueues.get(e)??Promise.resolve(),i,a=new Promise(e=>{i=e}),o=r.then(()=>a);this.requestQueues.set(e,o);try{return await Pe(r,t),await n()}finally{i(),this.requestQueues.get(e)===o&&this.requestQueues.delete(e)}}async close(){if(this.closed)return;this.closed=!0;let e=[...this.sessions.values()];this.sessions.clear(),await Promise.all(e.map(async e=>await this.dispose(e,!0)))}async ensureSession(e,t){let n=e.target.udid,r=this.sessions.get(n);if(r&&r.bridgePath===e.bridge.path&&r.process.isAlive())return(!r.socket||r.socket.destroyed)&&(r.socket=await this.connectUntilReady(r,t)),r;r&&await this.removeSession(r,!0);let i=Se(this.host,e.target.udid,this.ownerId);await this.host.ensureDirectory(_.dirname(i)),await this.host.remove(i);let a=this.host.start(e.target,e.bridge.path,i,{signal:t.signal}),o={udid:e.target.udid,bridgePath:e.bridge.path,socketPath:i,process:a};this.sessions.set(n,o);try{return o.socket=await this.connectUntilReady(o,t),o}catch(e){throw await this.removeSession(o,!0),C(e)}}async connectUntilReady(e,t){let n;for(;;){let r=T(t,`bridge-connect-deadline`);if(!e.process.isAlive())throw await k(this.host,e.process);try{return await this.host.connect(e.socketPath,{signal:t.signal,timeoutMs:Math.min(250,r)})}catch(e){if(n=e,e instanceof x&&e.failureKind===`cancelled`)throw e;let r=Math.min(20,T(t,`bridge-connect-deadline`));try{await E(t,r,`bridge-connect-deadline`)}catch(e){throw C(e)}}if(n instanceof x&&n.failureKind===`timeout`)throw n}}async exchange(e,t,n){(!e.socket||e.socket.destroyed)&&(e.socket=await this.connectUntilReady(e,n));let r=y(),i=Te(Oe({requestId:r,pid:t.target.pid,generation:t.target.generation,maxDepth:Math.min(t.limits.maxTraversalDepth,t.maxDepth),maxNodes:t.limits.maxNodes,maxDurationMs:T(n,`bridge-request-deadline`),maxResponseBytes:t.limits.maxResponseBytes,...t.nativeLevelsHint===void 0?{}:{nativeLevelsHint:t.nativeLevelsHint}}),t.limits);return await Me({process:e.process,socket:e.socket,frame:i,requestId:r,deadline:n,limits:t.limits,expectedPid:t.target.pid,expectedGeneration:t.target.generation,host:this.host})}async readTargetStartTime(e,t){let n=await this.host.readTargetProcessStartTime(e.pid,{signal:t.signal,timeoutMs:T(t,`target-identity-deadline`)});if(!n)throw S(`stale-target`,`target-process-unavailable`,{pid:e.pid,generation:e.generation});if(e.processStartTime!==void 0&&e.processStartTime!==n)throw S(`stale-target`,`target-process-changed`,{pid:e.pid,generation:e.generation,expectedStartTime:e.processStartTime,observedStartTime:n});return n}async assertTargetStillCurrent(e,t,n){let r=await this.host.readTargetProcessStartTime(e.pid,{signal:n.signal,timeoutMs:T(n,`target-identity-deadline`)});if(r!==t)throw S(`stale-target`,`target-process-changed`,{pid:e.pid,generation:e.generation,expectedStartTime:t,observedStartTime:r})}async removeSession(e,t){this.sessions.get(e.udid)===e&&this.sessions.delete(e.udid),await this.dispose(e,t)}async dispose(e,t){e.socket?.destroy(),e.socket=void 0,t&&e.process.isAlive()&&(e.process.signal(`SIGTERM`),await N(e.process,500),e.process.isAlive()&&(e.process.signal(`SIGKILL`),await N(e.process,500))),await this.host.remove(e.socketPath)}};async function Pe(e,t){let n=T(t,`bridge-request-deadline`);await Promise.race([e,E(t,n,`bridge-request-deadline`).then(()=>{throw S(`timeout`,`bridge-request-deadline`)})])}function Fe(e,t,n){return(e.failureKind===`cancelled`||e.failureKind===`timeout`)&&(e.details?.dispatched===!0||n!==t)}async function N(e,t){await Promise.race([e.wait.catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}const P=16777216,F=12e4,I=1e4,Ie=Object.freeze({maxRequestBytes:65536,maxResponseBytes:4194304,maxNodes:5e3,maxTraversalDepth:64,maxDurationMs:5e3});function L(t){let n={...Ie,...t??{}};for(let[t,r]of Object.entries(n))if(!Number.isSafeInteger(r)||r<=0)throw new e(`INVALID_ARGS`,`Snapshot source limit ${t} must be a positive integer`,{name:t,value:r});if(n.maxRequestBytes>n.maxResponseBytes)throw new e(`INVALID_ARGS`,`Snapshot source request bytes cannot exceed response bytes`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes});if(n.maxRequestBytes>P||n.maxResponseBytes>P)throw new e(`INVALID_ARGS`,`Snapshot source frame limits exceed the bridge bound`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes,maximumFrameBytes:P});if(n.maxNodes>I||n.maxTraversalDepth>128)throw new e(`INVALID_ARGS`,`Snapshot source tree limits exceed the bridge bound`,{maxNodes:n.maxNodes,maxTraversalDepth:n.maxTraversalDepth,maximumNodes:I,maximumDepth:128});if(n.maxDurationMs>F)throw new e(`INVALID_ARGS`,`Snapshot source duration exceeds the bridge bound`,{maxDurationMs:n.maxDurationMs,maximumDurationMs:F});if(n.maxRequestBytes<=4||n.maxResponseBytes<=4)throw new e(`INVALID_ARGS`,`Snapshot source frame limits must leave room for a body`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes});return Object.freeze(n)}const R=[`SnapshotBridge.m`,`SnapshotBridgeRuntime.m`,`SnapshotBridgeRuntime.h`,`SnapshotBridgeCapture.h`,`SnapshotBridgeCapture.m`],Le=[`SnapshotBridge.m`,`SnapshotBridgeRuntime.m`,`SnapshotBridgeCapture.m`];async function Re(e,t,n){let r=v(`sha256`);for(let i of R){let a=_.join(t,i);if(T(n,`native-source-fingerprint-deadline`),!e.exists(a))throw S(`unsupported`,`native-source-missing`,{filePath:a});r.update(i),r.update(`\0`),r.update(await e.readBinary(a)),r.update(`\0`)}return r.digest(`hex`)}async function ze(e,t,n){let r=await z(e,`xcodebuild`,[`-version`],n),i=await z(e,`sw_vers`,[`-productVersion`],n),a=await z(e,`sw_vers`,[`-buildVersion`],n),o=await z(e,`uname`,[`-m`],n),s=t.trim();if(!s)throw S(`unsupported`,`simulator-runtime-missing`);if(o!==`arm64`&&o!==`x86_64`)throw S(`unsupported`,`simulator-architecture-unsupported`,{architecture:o});return{xcode:r,macosProductVersion:i,macosBuild:a,architecture:o,simulatorRuntime:s}}async function z(e,t,n,r){let i=await Be(e,t,n,r);if(i.exitCode!==0)throw S(`unsupported`,`toolchain-probe-failed`,{command:t,exitCode:i.exitCode,stderr:i.stderr.slice(0,1024)});let a=(i.stdout||i.stderr).trim();if(!a)throw S(`unsupported`,`toolchain-probe-empty`,{command:t});return a}async function Be(e,t,n,r){let i=[],a;for(let o=1;;o+=1){let s;try{s=Math.min(h,T(r,`toolchain-probe-deadline`))}catch(e){throw a??e}i.push(s);try{return await He(e,t,n,r,s)}catch(e){if(!f(e))throw e;if(r.signal?.aborted)throw S(`cancelled`,`abort-signal`);if(a=Ve(t,i,e),o>=2)throw a}}}function Ve(e,t,n){let r=t.length;return S(`timeout`,`toolchain-probe-stalled`,{command:e,attemptTimeoutsMs:[...t],hint:`${e} did not answer within ${t[r-1]}ms on ${r} attempt(s). A toolchain probe that cannot answer is a host condition rather than a toolchain defect: run \`${e}\` by hand until it answers, then retry.`},n)}function He(e,t,n,r,i){return e.run(t,n,{allowFailure:!0,signal:r.signal,timeoutMs:i})}const B=`snapshot-bridge`,V=`manifest.json`,H=12e4;async function Ue(e){let t=e.deadline,n=e.sourceRoot??Ge(e.host),r=await Re(e.host,n,t),i=await ze(e.host,e.runtime,t),a=qe({schemaVersion:1,protocolVersion:1,sourceVersion:j,sourceHash:r,toolchain:i}),o=e.cacheRoot??_.join(e.host.homeDirectory(),`.agent-device`,`snapshot-source`),s=_.join(o,a);return await p({acquire:()=>e.host.acquireLock(_.join(o,`${a}.lock`),{deadline:t}),task:async()=>{let c=await Ke(e.host,s,{sourceHash:r,cacheKey:a,toolchain:i},t);if(c)return c;T(t,`native-build-deadline`),e.host.exists(s)&&await e.host.remove(s),T(t,`native-build-deadline`),await e.host.ensureDirectory(o);let l=_.join(o,`.${a}.${e.host.processId()}.tmp`);T(t,`native-build-deadline`),await e.host.remove(l);try{T(t,`native-build-deadline`),await e.host.ensureDirectory(l);let o=_.join(l,B),c=await We(e.host,t,i.architecture,n,o);if(c.exitCode!==0||!e.host.exists(o))throw S(`unsupported`,`native-build-failed`,{exitCode:c.exitCode,stderr:c.stderr.slice(0,4096)});T(t,`native-build-deadline`),await e.host.chmod(o,493);let u=await U(e.host,o,t),d={schemaVersion:1,protocolVersion:1,sourceVersion:j,sourceHash:r,cacheKey:a,toolchain:i,binarySha256:u};return await e.host.writeText(_.join(l,V),`${JSON.stringify(d,null,2)}\n`),T(t,`native-build-deadline`),await e.host.rename(l,s),{path:_.join(s,B),sourceHash:r,cacheKey:a,protocolVersion:1,sourceVersion:j}}catch(t){throw await e.host.remove(l),t}}})}async function We(e,t,n,r,i){let a=Math.min(H,T(t,`native-build-deadline`));try{return await e.run(`xcrun`,[`--sdk`,`iphonesimulator`,`clang`,`-arch`,n,`-mios-simulator-version-min=15.0`,`-fobjc-arc`,`-Werror`,`-Wall`,`-Wextra`,`-framework`,`Foundation`,`-framework`,`CoreGraphics`,...Le.map(e=>_.join(r,e)),`-o`,i],{signal:t.signal,timeoutMs:a,allowFailure:!0})}catch(e){throw f(e)?S(`timeout`,`native-build-stalled`,{timeoutMs:a,hint:`The Simulator SDK toolchain did not answer within ${a}ms, which stopped the bridge build before clang reported anything. Run \`xcrun --sdk iphonesimulator clang --version\` by hand until it answers, then retry.`},e):e}}function Ge(e){let t=e.projectRoot(),n=_.join(t,`apple`,`snapshot-bridge`);if(R.every(t=>e.exists(_.join(n,t))))return n;let r=_.join(t,`dist`,`apple`,`snapshot-bridge`);if(R.every(t=>e.exists(_.join(r,t))))return r;throw S(`unsupported`,`native-source-missing`,{projectRoot:t})}async function Ke(e,t,n,r){let i=_.join(t,B);if(!(!e.exists(i)||!e.exists(_.join(t,V))))try{let a=JSON.parse(await e.readText(_.join(t,V)));return a.schemaVersion!==1||a.protocolVersion!==1||a.sourceVersion!==`agent-device-simulator-ax-v1.7.0`||a.sourceHash!==n.sourceHash||a.cacheKey!==n.cacheKey||JSON.stringify(a.toolchain)!==JSON.stringify(n.toolchain)||typeof a.binarySha256!=`string`||await U(e,i,r)!==a.binarySha256?void 0:{path:i,sourceHash:n.sourceHash,cacheKey:n.cacheKey,protocolVersion:1,sourceVersion:j}}catch(e){if(e instanceof x&&(e.failureKind===`cancelled`||e.failureKind===`timeout`))throw e;return}}async function U(e,t,n){return T(n,`native-cache-hash-deadline`),v(`sha256`).update(await e.readBinary(t)).digest(`hex`)}function qe(e){return v(`sha256`).update(JSON.stringify(e)).digest(`hex`).slice(0,32)}const Je=h+H;function Ye(e){let t=e.now??Date.now,n=new Map,r=fe({waitMs:2e3,waitGrant:`first-caller`,retryAfterMs:6e4,now:t}),i=async(r,i)=>{let a=w(Je,i,t);try{let t=await e.host.withDiagnosticTimer(`ios.snapshot-source.prepare`,async()=>await Ue({host:e.host,runtime:r,limits:e.limits,deadline:a,sourceRoot:e.sourceRoot,cacheRoot:e.cacheRoot}),{producer:e.producer});return n.set(r,t),t}catch(e){throw C(e)}};return{readyBinary:async(e,t,a)=>n.get(e)||await r.value(e,{start:t=>i(e,t),wait:(e,n)=>E(t,e,a,n),pending:()=>S(`preparing`,`bridge-preparation-pending`)}),close:()=>{n.clear(),r.close()}}}function Xe(e,t){return!i(e)||!i(t)||Math.abs(t.width-t.height)<=1?!1:Math.abs(e.width-t.height)<=1&&Math.abs(e.height-t.width)<=1}const W=Object.freeze({elementType:`XC_kAXXCAttributeElementType`,elementBaseType:`XC_kAXXCAttributeElementBaseType`,label:`XC_kAXXCAttributeLabel`,value:`XC_kAXXCAttributeValue`,identifier:`XC_kAXXCAttributeIdentifier`,frame:`XC_kAXXCAttributeFrame`,automationType:`XC_kAXXCAttributeAutomationType`,traits:`XC_kAXXCAttributeTraits`,userInteractionEnabled:`XC_kAXXCAttributeIsUserInteractionEnabled`,children:`XC_kAXXCAttributeChildren`}),G=`Other.Other.Application.Group.Window.Sheet.Drawer.Alert.Dialog.Button.RadioButton.RadioGroup.CheckBox.DisclosureTriangle.PopUpButton.ComboBox.MenuButton.ToolbarButton.Popover.Keyboard.Key.NavigationBar.TabBar.TabGroup.Toolbar.StatusBar.Table.TableRow.TableColumn.Outline.OutlineRow.Browser.CollectionView.Slider.PageIndicator.ProgressIndicator.ActivityIndicator.SegmentedControl.Picker.PickerWheel.Switch.Toggle.Link.Image.Icon.SearchField.ScrollView.ScrollBar.StaticText.TextField.SecureTextField.DatePicker.TextView.Menu.MenuItem.MenuBar.MenuBarItem.Map.WebView.IncrementArrow.DecrementArrow.Timeline.RatingIndicator.ValueIndicator.SplitGroup.Splitter.RelevanceIndicator.ColorWell.HelpTag.Matte.DockItem.Ruler.RulerMarker.Grid.LevelIndicator.Cell.LayoutArea.LayoutItem.Handle.Stepper.Tab.TouchBar.StatusItem`.split(`.`),K={UIApplication:`Application`,UIWindow:`Window`},Ze=new Set(Object.values(W)),Qe=1n<<8n,$e=1n<<3n,et={x:0,y:0,width:0,height:0};function tt(e,t,n){let r=Array.isArray(e)?e:[e];if(r.length===0||r.some(e=>!M(e)))throw S(`malformed-tree`,`guest-tree-root-invalid`);let i=[],a=[],o=0;for(let e of r)c(e,void 0,0,!1);if(i.length>n.maxNodes)throw S(`malformed-tree`,`node-limit-exceeded`,{nodeCount:i.length,maxNodes:n.maxNodes});if(o>n.maxTraversalDepth)throw S(`malformed-tree`,`traversal-depth-exceeded`,{maxTraversalDepth:o,maxAllowedDepth:n.maxTraversalDepth});if(typeof t.truncated!=`boolean`)throw S(`malformed-tree`,`truncated-invalid`);let s=ot(i.filter(J)[0]);return s.kind===`reported`&&st(i,s.rect),{nodes:i,maxTraversalDepth:o,viewport:s,opaqueRemoteElements:a.filter(e=>it(e,s)).length,unresolvedCoordinateSpaceWindows:ct(i,s)};function c(e,t,r,s){if(i.length>=n.maxNodes)throw S(`malformed-tree`,`node-limit-exceeded`,{maxNodes:n.maxNodes});for(let t of Object.keys(e))if(!Ze.has(t))throw S(`malformed-tree`,`node-contains-unknown-field`,{key:t});let l=e[W.children];if(!Array.isArray(l))throw S(`malformed-tree`,`children-invalid`);let u=i.length,d=nt(e,u,t,r);i.push(d),o=Math.max(o,r),rt(d,l.length,s)&&a.push(d.rect);let f=s||d.type===`WebView`;for(let e of l){if(!M(e))throw S(`malformed-tree`,`child-invalid`);c(e,u,r+1,f)}}}function nt(e,t,n,r){let i=X(e[W.elementType]),a=X(e[W.elementBaseType]),o=dt(e[W.automationType]),s=at(e[W.frame]),c=lt(e[W.traits]),l=c===void 0?void 0:(c&Qe)===0n,u=c===void 0||(c&$e)===0n?void 0:!0,d=ut(e[W.userInteractionEnabled]);return{index:t,...n===void 0?{}:{parentIndex:n},...q(i,o)?{type:q(i,o)}:{},...i?{role:i}:{},...a&&a!==i?{subrole:a}:{},...X(e[W.label])?{label:X(e[W.label])}:{},...Z(e[W.value])?{value:Z(e[W.value])}:{},...X(e[W.identifier])?{identifier:X(e[W.identifier])}:{},...s?{rect:s}:{},...l===void 0?{}:{enabled:l},...u===void 0?{}:{selected:u},...d===void 0?{}:{userInteractionEnabled:d},depth:r}}function q(e,t){if(e!==void 0&&K[e])return K[e];if(e!==void 0&&G.includes(e))return e;if(t!==void 0)return G[t]??`Other`}function rt(e,t,n){return n&&e.role===`AXRemoteElement`&&t===0}function it(e,t){return e===void 0?!0:i(e)?t.kind!==`reported`||n(e,t.rect):!1}function at(e){if(e===void 0)return;if(!M(e))throw S(`malformed-tree`,`frame-invalid`);let t=[`X`,`Y`,`Width`,`Height`].map(t=>e[t]);if(!t.every(e=>typeof e==`number`&&Number.isFinite(e)))throw S(`malformed-tree`,`frame-invalid`);let[n,r,i,a]=t;if(i<0||a<0)throw S(`malformed-tree`,`frame-invalid`);return{x:n,y:r,width:i,height:a}}function ot(e){return!e||!J(e)?{kind:`missing`,reason:`not-provided`}:i(e.rect)?{kind:`reported`,rect:e.rect}:{kind:`missing`,reason:e.rect?`invalid`:`not-provided`}}function J(e){return e.type===`Application`||e.type===`Window`}function st(e,t){for(let n of e)n.hittable=n.parentIndex!==void 0&&r(n.enabled!==!1,n.rect,t)}function ct(e,t){return t.kind===`reported`?e.filter(n=>Y(n,e)&&Xe(n.rect??et,t.rect)).length:0}function Y(e,t){return J(e)?!0:e.parentIndex!==void 0&&J(t[e.parentIndex]??e)}function X(e){return typeof e==`string`&&e.length>0?e:void 0}function Z(e){if(typeof e==`string`)return e.length>0?e:void 0;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(e!=null)throw S(`malformed-tree`,`scalar-invalid`)}function lt(e){if(e!=null){if(typeof e!=`string`||!/^\d{1,20}$/.test(e))throw S(`malformed-tree`,`traits-invalid`);return BigInt(e)}}function ut(e){if(e!=null){if(typeof e!=`boolean`)throw S(`malformed-tree`,`user-interaction-invalid`);return e}}function dt(e){if(e!=null){if(!Number.isSafeInteger(e))throw S(`malformed-tree`,`automation-type-invalid`);return e}}const Q=`simulator-ax-bridge`;function ft(e={}){let t=e.host??_e(),n=new Ne(t),r=new ge,i=Ye({host:t,limits:L(e.limits),producer:Q,sourceRoot:e.sourceRoot,cacheRoot:e.cacheRoot}),a=!1;return{acquire:async o=>{try{if(a)throw S(`unsupported`,`source-closed`);pt(o);let s=L({...e.limits,...o.limits}),c=w(s.maxDurationMs,o.signal),l=ht(o.hint,s.maxTraversalDepth),u=l+1,d=o.hint.rawTraversalDepth!==null;return await t.withDiagnosticTimer(`ios.snapshot-source.acquire`,async()=>{let e=await i.readyBinary(o.target.runtime,c,`bridge-preparation-deadline`),a=r.consume(o.target,u,d),f=await n.request({target:o.target,bridge:e,limits:s,maxDepth:l,nativeLevelsHint:a.nativeLevels,deadline:c});T(c,`snapshot-decode-deadline`);let p=gt(o.hint,o.target,f,s);return mt(t,r,o.target,u,d,a,f),{stage:`acquired`,acquisition:p}},{producer:Q})}catch(e){let t=C(e);return{stage:`failed`,failure:{kind:t.failureKind,code:t.failureCode,...t.details?{details:t.details}:{}}}}},close:async()=>{a||(a=!0,i.close(),await n.close())}}}function pt(t){if(!t.target.udid.trim()||!t.target.runtime.trim()||!t.target.generation.trim()||!Number.isSafeInteger(t.target.pid)||t.target.pid<=0)throw new e(`INVALID_ARGS`,`Simulator snapshot source target identity is incomplete`);let n=t.hint;if(n.projection!==`raw`&&n.projection!==`regular`||![`full`,`surface-observation`].includes(n.acquisitionIntent)||typeof n.interactiveOnly!=`boolean`||typeof n.customActions!=`boolean`||!$(n.rawTraversalDepth)||!$(n.regularPresentedDepth))throw new e(`INVALID_ARGS`,`Simulator snapshot source capture hint is invalid`)}function mt(e,t,n,r,i,a,o){let s=we(o),c=o.truncated===!0,l=t.learn(n,r,i,s);e.emitDiagnostic({level:`debug`,phase:`ios_snapshot_source_recovery`,data:{producer:Q,...n.targetId?{targetId:n.targetId}:{},generation:n.generation,requestedLevels:r,hint:a.reason,...a.nativeLevels===void 0?{}:{hintedLevels:a.nativeLevels},...s,truncated:c,learning:l}})}function ht(t,n){let r=t.rawTraversalDepth??n;if(r>n)throw new e(`INVALID_ARGS`,`Simulator snapshot source depth exceeds its bound`,{requested:r,maximum:n});return r}function $(e){return e===null||Number.isSafeInteger(e)&&e>=0}function gt(e,t,n,r){if(n.automationEnabled!==!0)throw S(`unsupported`,`automation-mode-unavailable`);let i=n.tree,a=n.truncated;if(typeof a!=`boolean`)throw S(`malformed-tree`,`truncated-invalid`);let o=tt(i,{truncated:a},r),s=n.generation;if(typeof s!=`string`||!s)throw S(`malformed-tree`,`generation-invalid`);if(o.opaqueRemoteElements>0)throw S(`unsupported`,`remote-content-boundary`,{remoteElements:o.opaqueRemoteElements});if(o.unresolvedCoordinateSpaceWindows>0)throw S(`unsupported`,`window-coordinate-space-unresolved`,{windows:o.unresolvedCoordinateSpaceWindows});let c=Object.freeze(o.nodes.map(e=>Object.freeze({...e,pid:t.pid}))),l=_t(e,a,o.viewport),u=Object.freeze({...t.targetId?{targetId:t.targetId}:{},generation:s}),d={producer:Q,nodes:c,truncated:a,viewport:o.viewport,lineage:u,residue:l};return e.acquisitionIntent===`full`?{...d,intent:`full`,hint:{...e,acquisitionIntent:`full`}}:{...d,intent:`surface-observation`,hint:{...e,acquisitionIntent:`surface-observation`}}}function _t(e,t,n){let r=n.kind===`reported`?[]:[{kind:`unavailable-fact`,fact:`hittability`}];return Object.freeze([...r,...e.interactiveOnly?[{kind:`unavailable-fact`,fact:`interactive-query`}]:[],...t?[{kind:`truncated`}]:[],...n.kind===`missing`?[{kind:`missing-viewport`,reason:n.reason}]:[]])}export{ft as createSimulatorSnapshotSource};
|
|
1
|
+
import{A as e}from"./sdk-contracts.js";import{Jr as t,Yr as n,qr as r}from"./sdk-batch.js";import{t as i}from"./apple-runner-platform.js";import{_ as a,a as o,d as s,f as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,t as ee,u as v}from"./native-build-cache.js";import y from"node:path";import{randomUUID as b}from"node:crypto";import{Buffer as x}from"node:buffer";var te=class{entries=new Map;probeBackAfterUses;constructor(e=8){this.probeBackAfterUses=e}consume(e,t,n){if(n)return{nativeLevels:void 0,reason:`explicit-depth`};let r=this.currentEntry(e);return r===`unidentified`?{nativeLevels:void 0,reason:`unidentified-target`}:!r||r.nativeLevels>=t?{nativeLevels:void 0,reason:`no-hint`}:r.remainingUses<=0?{nativeLevels:void 0,reason:`probe-back`}:(--r.remainingUses,{nativeLevels:r.nativeLevels,reason:`hinted`})}learn(e,t,n,r){return n||!e.targetId?`ignored`:r.rejected>0&&r.acceptedLevels<t?(this.remember(e.targetId,{generation:e.generation,nativeLevels:r.acceptedLevels,remainingUses:this.probeBackAfterUses}),`learned`):r.rejected===0&&r.acceptedLevels>=t?this.entries.delete(e.targetId)?`forgotten`:`ignored`:this.currentEntry(e)?`kept`:`ignored`}currentEntry(e){if(!e.targetId)return`unidentified`;let t=this.entries.get(e.targetId);if(t){if(t.generation!==e.generation){this.entries.delete(e.targetId);return}return t}}remember(e,t){if(this.entries.delete(e),this.entries.size>=32){let e=this.entries.keys().next().value;e!==void 0&&this.entries.delete(e)}this.entries.set(e,t)}};const S=new WeakSet;async function C(e,t){let n;try{n=(await t.wait).exitCode}catch{n=void 0}return S.has(t)||(S.add(t),e.emitDiagnostic({level:`error`,phase:`ios.snapshot-source.bridge-process-exit`,data:{pid:t.pid,...n===void 0?{}:{exitCode:n},stderr:ne(t.readLog())}})),l(`process-crash`,`bridge-exited`,{pid:t.pid,...n===void 0?{}:{exitCode:n}})}function ne(e){let t=x.from(e);return t.length<=65536?e:t.subarray(-65536).toString(`utf8`)}const w=`agent-device-simulator-ax-v1.8.0`;Object.freeze([`verb`,`requestId`,`pid`,`generation`,`snapshotTree`,`automationMode`,`maxDepth`,`maxNodes`,`maxDurationMs`,`maxResponseBytes`,`nativeLevelsHint`]),Object.freeze([`protocolVersion`,`sourceVersion`,`requestId`,`generation`,`ok`,`pid`,`tree`,`truncated`,`automationEnabled`,`recovery`,`error_kind`,`error_code`,`error`]),Object.freeze([`XC_kAXXCAttributeElementType`,`XC_kAXXCAttributeElementBaseType`,`XC_kAXXCAttributeLabel`,`XC_kAXXCAttributeValue`,`XC_kAXXCAttributePlaceholderValue`,`XC_kAXXCAttributeIdentifier`,`XC_kAXXCAttributeFrame`,`XC_kAXXCAttributeAutomationType`,`XC_kAXXCAttributeTraits`,`XC_kAXXCAttributeIsUserInteractionEnabled`,`XC_kAXXCAttributeChildren`]);const T=[`requests`,`rejected`,`continuations`,`acceptedLevels`];function re(e){let t=e.recovery;if(!j(t))throw l(`malformed-tree`,`recovery-invalid`);let n=T.map(e=>[e,t[e]]);if(n.some(([,e])=>!Number.isSafeInteger(e)||e<0))throw l(`malformed-tree`,`recovery-invalid`);return Object.freeze(Object.fromEntries(n))}function ie(e,t){let n;try{n=x.from(JSON.stringify(e),`utf8`)}catch(e){throw l(`malformed-tree`,`request-not-json`,{},e)}let r=n.length+4;if(r>t.maxRequestBytes)throw l(`transport-failure`,`request-limit-exceeded`,{frameBytes:r,maxRequestBytes:t.maxRequestBytes});let i=x.alloc(4);return i.writeUInt32BE(n.length,0),x.concat([i,n])}var E=class{header=x.alloc(4);headerBytes=0;chunks=[];payloadBytes=0;expectedBodyBytes;frame;maxFrameBytes;constructor(e){if(!Number.isSafeInteger(e)||e<=0)throw l(`malformed-tree`,`frame-limit-invalid`,{maxFrameBytes:e});this.maxFrameBytes=e}push(e){if(this.frame)return this.acceptTrailingChunk(e);let t=this.readHeader(e);if(t&&(this.appendPayload(e,t.offset,t.bodyBytes),this.payloadBytes===t.bodyBytes))return this.frame=x.concat(this.chunks,t.bodyBytes),this.frame}acceptTrailingChunk(e){if(e.length>0)throw l(`malformed-tree`,`multiple-frames`,{trailingBytes:e.length});return this.frame}readHeader(e){if(this.headerBytes===4)return{offset:0,bodyBytes:this.expectedBodyBytes};let t=Math.min(4-this.headerBytes,e.length);if(e.copy(this.header,this.headerBytes,0,t),this.headerBytes+=t,this.headerBytes<4)return;let n=this.header.readUInt32BE(0);if(n===0||n>this.maxFrameBytes)throw l(`malformed-tree`,`frame-limit-exceeded`,{bodyBytes:n,maxFrameBytes:this.maxFrameBytes});return this.expectedBodyBytes=n,{offset:t,bodyBytes:n}}appendPayload(e,t,n){let r=n-this.payloadBytes,i=e.length-t;if(i>r)throw l(`malformed-tree`,`multiple-frames`,{trailingBytes:i-r});i!==0&&(this.chunks.push(e.subarray(t)),this.payloadBytes+=i)}finish(){if(this.frame)return this.frame;throw l(`transport-failure`,`bridge-frame-incomplete`,{headerBytes:this.headerBytes,payloadBytes:this.payloadBytes,expectedBodyBytes:this.expectedBodyBytes})}};function ae(e){let t;try{t=JSON.parse(e.toString(`utf8`))}catch(e){throw l(`malformed-tree`,`response-not-json`,{},e)}if(!j(t))throw l(`malformed-tree`,`response-not-object`);return t}function D(e){return Object.freeze({verb:`describe`,requestId:e.requestId,pid:e.pid,generation:e.generation,snapshotTree:!0,automationMode:!0,maxDepth:e.maxDepth,maxNodes:e.maxNodes,maxDurationMs:e.maxDurationMs,maxResponseBytes:e.maxResponseBytes,...e.nativeLevelsHint===void 0?{}:{nativeLevelsHint:e.nativeLevelsHint}})}function O(e,t){if(e.protocolVersion!==1)throw l(`transport-failure`,`protocol-version-mismatch`,{expected:1,observed:e.protocolVersion});if(e.sourceVersion!==`agent-device-simulator-ax-v1.8.0`)throw l(`transport-failure`,`source-version-mismatch`,{expected:w,observed:e.sourceVersion});if(e.requestId!==t)throw l(`transport-failure`,`request-id-mismatch`,{expected:t,observed:e.requestId})}function k(e,t){if(typeof e.pid!=`number`||e.pid!==t.pid)throw l(`stale-target`,`bridge-pid-mismatch`,{expectedPid:t.pid,observedPid:e.pid});if(e.generation!==t.generation)throw l(`stale-target`,`bridge-generation-mismatch`,{expectedGeneration:t.generation,observedGeneration:e.generation})}function A(e){let t=e.error_kind,n=typeof e.error_code==`string`?e.error_code:`guest-error`,r=typeof e.error==`string`?e.error:void 0,i=r?{guestMessage:r.slice(0,1024)}:{};throw l(t===`unsupported`?`unsupported`:t===`malformed_tree`?`malformed-tree`:t===`application_not_responding`?`timeout`:t===`application_unavailable`?`transport-failure`:t===`bad_request`?`malformed-tree`:`transport-failure`,n,i)}function j(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function oe(e){let t=new E(e.limits.maxResponseBytes-4),n=s(e.deadline,`bridge-request-deadline`);return await new Promise((r,i)=>{let a=!1,o=!1,s=setTimeout(()=>{h(l(`timeout`,`bridge-request-deadline`,{dispatched:o})),e.socket.destroy()},n),c=()=>{h(l(`cancelled`,`abort-signal`,{dispatched:o})),e.socket.destroy()},u=n=>{try{if(!Buffer.isBuffer(n))throw l(`transport-failure`,`bridge-data-invalid`);let r=t.push(n);if(r){let t=ae(r);if(O(t,e.requestId),k(t,{pid:e.expectedPid,generation:e.expectedGeneration}),t.ok!==!0&&A(t),typeof t.truncated!=`boolean`)throw l(`malformed-tree`,`truncated-invalid`);m(t);return}}catch(t){h(t),e.socket.destroy()}},d=e=>h(f(e)),p=()=>{a||(e.process.isAlive()?h(l(`transport-failure`,`bridge-connection-closed`)):C(e.host,e.process).then(h))};e.process.wait.then(()=>{a||C(e.host,e.process).then(h)},e=>{a||h(f(e))});let m=e=>g(()=>r(e)),h=e=>g(()=>i(e)),g=t=>{a||(a=!0,clearTimeout(s),e.deadline.signal?.removeEventListener(`abort`,c),e.socket.off(`data`,u),e.socket.off(`error`,d),e.socket.off(`close`,p),t())};e.socket.on(`data`,u),e.socket.on(`error`,d),e.socket.on(`close`,p),e.deadline.signal?.addEventListener(`abort`,c,{once:!0});try{if(e.deadline.signal?.aborted)throw l(`cancelled`,`abort-signal`);o=!0,e.socket.write(e.frame)}catch(t){h(f(t)),e.socket.destroy()}})}var se=class{sessions=new Map;requestQueues=new Map;ownerId=b();closed=!1;host;constructor(e){this.host=e}async request(e){if(this.closed)throw l(`unsupported`,`source-closed`);return await this.withSimulatorLock(e.target.simulator.udid,e.deadline,()=>this.requestInSimulator(e))}async requestInSimulator(e){if(this.closed)throw l(`unsupported`,`source-closed`);let t=e.deadline;s(t,`bridge-request-deadline`);let n=this.sessions.get(e.target.simulator.udid),r=await this.ensureSession(e,t);try{let n=await this.readTargetStartTime(e.target,t),i=await this.exchange(r,e,t);return await this.assertTargetStillCurrent(e.target,n,t),i}catch(e){throw await this.handleRequestFailure(e,r,n)}}async handleRequestFailure(e,t,n){let r=f(e);return le(r,t,n)?await this.removeSession(t,!0):r.failureKind===`process-crash`?await this.removeSession(t,!1):r.failureKind===`transport-failure`&&(t.socket?.destroy(),t.socket=void 0),r}async withSimulatorLock(e,t,n){let r=this.requestQueues.get(e)??Promise.resolve(),i,a=new Promise(e=>{i=e}),o=r.then(()=>a);this.requestQueues.set(e,o);try{return await ce(r,t),await n()}finally{i(),this.requestQueues.get(e)===o&&this.requestQueues.delete(e)}}async close(){if(this.closed)return;this.closed=!0;let e=[...this.sessions.values()];this.sessions.clear(),await Promise.all(e.map(async e=>await this.dispose(e,!0)))}async ensureSession(e,t){let n=e.target.simulator.udid,r=this.sessions.get(n);if(r&&r.bridgePath===e.bridge.path&&r.process.isAlive())return(!r.socket||r.socket.destroyed)&&(r.socket=await this.connectUntilReady(r,t)),r;r&&await this.removeSession(r,!0);let i=o(this.host,e.target.simulator.udid,this.ownerId);await this.host.ensureDirectory(y.dirname(i)),await this.host.remove(i);let a=this.host.start(e.target.simulator,e.bridge.path,i,{signal:t.signal}),s={udid:e.target.simulator.udid,bridgePath:e.bridge.path,socketPath:i,process:a};this.sessions.set(n,s);try{return s.socket=await this.connectUntilReady(s,t),s}catch(e){throw await this.removeSession(s,!0),f(e)}}async connectUntilReady(e,t){let n;for(;;){let r=s(t,`bridge-connect-deadline`);if(!e.process.isAlive())throw await C(this.host,e.process);try{return await this.host.connect(e.socketPath,{signal:t.signal,timeoutMs:Math.min(250,r)})}catch(e){if(n=e,e instanceof h&&e.failureKind===`cancelled`)throw e;let r=Math.min(20,s(t,`bridge-connect-deadline`));try{await c(t,r,`bridge-connect-deadline`)}catch(e){throw f(e)}}if(n instanceof h&&n.failureKind===`timeout`)throw n}}async exchange(e,t,n){(!e.socket||e.socket.destroyed)&&(e.socket=await this.connectUntilReady(e,n));let r=b(),i=ie(D({requestId:r,pid:t.target.pid,generation:t.target.generation,maxDepth:Math.min(t.limits.maxTraversalDepth,t.maxDepth),maxNodes:t.limits.maxNodes,maxDurationMs:s(n,`bridge-request-deadline`),maxResponseBytes:t.limits.maxResponseBytes,...t.nativeLevelsHint===void 0?{}:{nativeLevelsHint:t.nativeLevelsHint}}),t.limits);return await oe({process:e.process,socket:e.socket,frame:i,requestId:r,deadline:n,limits:t.limits,expectedPid:t.target.pid,expectedGeneration:t.target.generation,host:this.host})}async readTargetStartTime(e,t){let n=await this.host.readTargetProcessStartTime(e.pid,{signal:t.signal,timeoutMs:s(t,`target-identity-deadline`)});if(!n)throw l(`stale-target`,`target-process-unavailable`,{pid:e.pid,generation:e.generation});if(e.processStartTime!==void 0&&e.processStartTime!==n)throw l(`stale-target`,`target-process-changed`,{pid:e.pid,generation:e.generation,expectedStartTime:e.processStartTime,observedStartTime:n});return n}async assertTargetStillCurrent(e,t,n){let r=await this.host.readTargetProcessStartTime(e.pid,{signal:n.signal,timeoutMs:s(n,`target-identity-deadline`)});if(r!==t)throw l(`stale-target`,`target-process-changed`,{pid:e.pid,generation:e.generation,expectedStartTime:t,observedStartTime:r})}async removeSession(e,t){this.sessions.get(e.udid)===e&&this.sessions.delete(e.udid),await this.dispose(e,t)}async dispose(e,t){e.socket?.destroy(),e.socket=void 0,t&&e.process.isAlive()&&(e.process.signal(`SIGTERM`),await M(e.process,500),e.process.isAlive()&&(e.process.signal(`SIGKILL`),await M(e.process,500))),await this.host.remove(e.socketPath)}};async function ce(e,t){let n=s(t,`bridge-request-deadline`);await Promise.race([e,c(t,n,`bridge-request-deadline`).then(()=>{throw l(`timeout`,`bridge-request-deadline`)})])}function le(e,t,n){return(e.failureKind===`cancelled`||e.failureKind===`timeout`)&&(e.details?.dispatched===!0||n!==t)}async function M(e,t){await Promise.race([e.wait.catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}const N=16777216,P=12e4,F=1e4,I=Object.freeze({maxRequestBytes:65536,maxResponseBytes:4194304,maxNodes:5e3,maxTraversalDepth:64,maxDurationMs:5e3});function L(t){let n={...I,...t??{}};for(let[t,r]of Object.entries(n))if(!Number.isSafeInteger(r)||r<=0)throw new e(`INVALID_ARGS`,`Snapshot source limit ${t} must be a positive integer`,{name:t,value:r});if(n.maxRequestBytes>n.maxResponseBytes)throw new e(`INVALID_ARGS`,`Snapshot source request bytes cannot exceed response bytes`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes});if(n.maxRequestBytes>N||n.maxResponseBytes>N)throw new e(`INVALID_ARGS`,`Snapshot source frame limits exceed the bridge bound`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes,maximumFrameBytes:N});if(n.maxNodes>F||n.maxTraversalDepth>128)throw new e(`INVALID_ARGS`,`Snapshot source tree limits exceed the bridge bound`,{maxNodes:n.maxNodes,maxTraversalDepth:n.maxTraversalDepth,maximumNodes:F,maximumDepth:128});if(n.maxDurationMs>P)throw new e(`INVALID_ARGS`,`Snapshot source duration exceeds the bridge bound`,{maxDurationMs:n.maxDurationMs,maximumDurationMs:P});if(n.maxRequestBytes<=4||n.maxResponseBytes<=4)throw new e(`INVALID_ARGS`,`Snapshot source frame limits must leave room for a body`,{maxRequestBytes:n.maxRequestBytes,maxResponseBytes:n.maxResponseBytes});return Object.freeze(n)}const R=12e4;async function z(e){let t=e.deadline,n=e.sourceRoot??V(e.host),r=await g(e.host,n,_,t),i=await d(e.host,e.runtime,t),a=e.cacheRoot??y.join(e.host.homeDirectory(),`.agent-device`,`snapshot-source`),o=await ee({host:e.host,deadline:t,cacheRoot:a,binaryFilename:`snapshot-bridge`,lockDescription:`iOS Simulator snapshot bridge cache`,keyInputs:{schemaVersion:1,protocolVersion:1,sourceVersion:w,sourceHash:r,toolchain:i,compileArgv:B({architecture:i.architecture,sourceRoot:``,outputPath:``})},build:async r=>{let a=await p({host:e.host,deadline:t,argv:B({architecture:i.architecture,sourceRoot:n,outputPath:r}),budgetMs:R,label:`bridge`});if(a.exitCode!==0||!e.host.exists(r))throw l(`unsupported`,`native-build-failed`,{exitCode:a.exitCode,stderr:a.stderr.slice(0,4096)})}});return{path:o.path,sourceHash:r,cacheKey:o.cacheKey,protocolVersion:1,sourceVersion:w}}function B(e){return[`--sdk`,`iphonesimulator`,`clang`,`-arch`,e.architecture,`-mios-simulator-version-min=15.0`,`-fobjc-arc`,`-Wall`,`-Wextra`,`-framework`,`Foundation`,`-framework`,`CoreGraphics`,...m.map(t=>y.join(e.sourceRoot,t)),`-o`,e.outputPath]}function V(e){let t=e.projectRoot(),n=y.join(t,`apple`,`snapshot-bridge`);if(_.every(t=>e.exists(y.join(n,t))))return n;let r=y.join(t,`dist`,`apple`,`snapshot-bridge`);if(_.every(t=>e.exists(y.join(r,t))))return r;throw l(`unsupported`,`native-source-missing`,{projectRoot:t})}const H=i+R;function U(e){let t=e.now??Date.now,n=new Map,r=a({waitMs:2e3,waitGrant:`first-caller`,retryAfterMs:6e4,now:t}),i=async(r,i)=>{let a=v(H,i,t);try{let t=await e.host.withDiagnosticTimer(`ios.snapshot-source.prepare`,async()=>await z({host:e.host,runtime:r,limits:e.limits,deadline:a,sourceRoot:e.sourceRoot,cacheRoot:e.cacheRoot}),{producer:e.producer});return n.set(r,t),t}catch(e){throw f(e)}};return{readyBinary:async(e,t,a)=>n.get(e)||await r.value(e,{start:t=>i(e,t),wait:(e,n)=>c(t,e,a,n),pending:()=>l(`preparing`,`bridge-preparation-pending`)}),close:()=>{n.clear(),r.close()}}}function W(e,n){return!t(e)||!t(n)||Math.abs(n.width-n.height)<=1?!1:Math.abs(e.width-n.height)<=1&&Math.abs(e.height-n.width)<=1}const G=Object.freeze({elementType:`XC_kAXXCAttributeElementType`,elementBaseType:`XC_kAXXCAttributeElementBaseType`,label:`XC_kAXXCAttributeLabel`,value:`XC_kAXXCAttributeValue`,placeholder:`XC_kAXXCAttributePlaceholderValue`,identifier:`XC_kAXXCAttributeIdentifier`,frame:`XC_kAXXCAttributeFrame`,automationType:`XC_kAXXCAttributeAutomationType`,traits:`XC_kAXXCAttributeTraits`,userInteractionEnabled:`XC_kAXXCAttributeIsUserInteractionEnabled`,children:`XC_kAXXCAttributeChildren`}),K=`Other.Other.Application.Group.Window.Sheet.Drawer.Alert.Dialog.Button.RadioButton.RadioGroup.CheckBox.DisclosureTriangle.PopUpButton.ComboBox.MenuButton.ToolbarButton.Popover.Keyboard.Key.NavigationBar.TabBar.TabGroup.Toolbar.StatusBar.Table.TableRow.TableColumn.Outline.OutlineRow.Browser.CollectionView.Slider.PageIndicator.ProgressIndicator.ActivityIndicator.SegmentedControl.Picker.PickerWheel.Switch.Toggle.Link.Image.Icon.SearchField.ScrollView.ScrollBar.StaticText.TextField.SecureTextField.DatePicker.TextView.Menu.MenuItem.MenuBar.MenuBarItem.Map.WebView.IncrementArrow.DecrementArrow.Timeline.RatingIndicator.ValueIndicator.SplitGroup.Splitter.RelevanceIndicator.ColorWell.HelpTag.Matte.DockItem.Ruler.RulerMarker.Grid.LevelIndicator.Cell.LayoutArea.LayoutItem.Handle.Stepper.Tab.TouchBar.StatusItem`.split(`.`),q={UIApplication:`Application`,UIWindow:`Window`},ue=new Set(Object.values(G)),de=1n<<8n,fe=1n<<3n,pe={x:0,y:0,width:0,height:0};function me(e,t,n){let r=Array.isArray(e)?e:[e];if(r.length===0||r.some(e=>!j(e)))throw l(`malformed-tree`,`guest-tree-root-invalid`);let i=[],a=[],o=0;for(let e of r)c(e,void 0,0,!1);if(i.length>n.maxNodes)throw l(`malformed-tree`,`node-limit-exceeded`,{nodeCount:i.length,maxNodes:n.maxNodes});if(o>n.maxTraversalDepth)throw l(`malformed-tree`,`traversal-depth-exceeded`,{maxTraversalDepth:o,maxAllowedDepth:n.maxTraversalDepth});if(typeof t.truncated!=`boolean`)throw l(`malformed-tree`,`truncated-invalid`);let s=ye(i.filter(Y)[0]);return s.kind===`reported`&&be(i,s.rect),{nodes:i,maxTraversalDepth:o,viewport:s,opaqueRemoteElements:a.filter(e=>_e(e,s)).length,unresolvedCoordinateSpaceWindows:xe(i,s)};function c(e,t,r,s){if(i.length>=n.maxNodes)throw l(`malformed-tree`,`node-limit-exceeded`,{maxNodes:n.maxNodes});for(let t of Object.keys(e))if(!ue.has(t))throw l(`malformed-tree`,`node-contains-unknown-field`,{key:t});let u=e[G.children];if(!Array.isArray(u))throw l(`malformed-tree`,`children-invalid`);let d=i.length,f=he(e,d,t,r);i.push(f),o=Math.max(o,r),ge(f,u.length,s)&&a.push(f.rect);let p=s||f.type===`WebView`;for(let e of u){if(!j(e))throw l(`malformed-tree`,`child-invalid`);c(e,d,r+1,p)}}}function he(e,t,n,r){let i=X(e[G.elementType]),a=X(e[G.elementBaseType]),o=Te(e[G.automationType]),s=ve(e[G.frame]),c=Ce(e[G.traits]),l=c===void 0?void 0:(c&de)===0n,u=c===void 0||(c&fe)===0n?void 0:!0,d=we(e[G.userInteractionEnabled]),f=X(e[G.placeholder])?.trim();return{index:t,...n===void 0?{}:{parentIndex:n},...J(i,o)?{type:J(i,o)}:{},...i?{role:i}:{},...a&&a!==i?{subrole:a}:{},...X(e[G.label])?{label:X(e[G.label])}:{},...Z(e[G.value])?{value:Z(e[G.value])}:{},...f?{placeholder:f}:{},...X(e[G.identifier])?{identifier:X(e[G.identifier])}:{},...s?{rect:s}:{},...l===void 0?{}:{enabled:l},...u===void 0?{}:{selected:u},...d===void 0?{}:{userInteractionEnabled:d},depth:r}}function J(e,t){if(e!==void 0&&q[e])return q[e];if(e!==void 0&&K.includes(e))return e;if(t!==void 0)return K[t]??`Other`}function ge(e,t,n){return n&&e.role===`AXRemoteElement`&&t===0}function _e(e,r){return e===void 0?!0:t(e)?r.kind!==`reported`||n(e,r.rect):!1}function ve(e){if(e===void 0)return;if(!j(e))throw l(`malformed-tree`,`frame-invalid`);let t=[`X`,`Y`,`Width`,`Height`].map(t=>e[t]);if(!t.every(e=>typeof e==`number`&&Number.isFinite(e)))throw l(`malformed-tree`,`frame-invalid`);let[n,r,i,a]=t;if(i<0||a<0)throw l(`malformed-tree`,`frame-invalid`);return{x:n,y:r,width:i,height:a}}function ye(e){return!e||!Y(e)?{kind:`missing`,reason:`not-provided`}:t(e.rect)?{kind:`reported`,rect:e.rect}:{kind:`missing`,reason:e.rect?`invalid`:`not-provided`}}function Y(e){return e.type===`Application`||e.type===`Window`}function be(e,t){for(let n of e)n.hittable=n.parentIndex!==void 0&&r(n.enabled!==!1,n.rect,t)}function xe(e,t){return t.kind===`reported`?e.filter(n=>Se(n,e)&&W(n.rect??pe,t.rect)).length:0}function Se(e,t){return Y(e)?!0:e.parentIndex!==void 0&&Y(t[e.parentIndex]??e)}function X(e){return typeof e==`string`&&e.length>0?e:void 0}function Z(e){if(typeof e==`string`)return e.length>0?e:void 0;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(e!=null)throw l(`malformed-tree`,`scalar-invalid`)}function Ce(e){if(e!=null){if(typeof e!=`string`||!/^\d{1,20}$/.test(e))throw l(`malformed-tree`,`traits-invalid`);return BigInt(e)}}function we(e){if(e!=null){if(typeof e!=`boolean`)throw l(`malformed-tree`,`user-interaction-invalid`);return e}}function Te(e){if(e!=null){if(!Number.isSafeInteger(e))throw l(`malformed-tree`,`automation-type-invalid`);return e}}const Q=`simulator-ax-bridge`;function Ee(e={}){let t=e.host??u(),n=new se(t),r=new te,i=U({host:t,limits:L(e.limits),producer:Q,sourceRoot:e.sourceRoot,cacheRoot:e.cacheRoot}),a=!1;return{acquire:async o=>{try{if(a)throw l(`unsupported`,`source-closed`);De(o);let c=L({...e.limits,...o.limits}),u=v(c.maxDurationMs,o.signal),d=ke(o.hint,c.maxTraversalDepth),f=d+1,p=o.hint.rawTraversalDepth!==null;return await t.withDiagnosticTimer(`ios.snapshot-source.acquire`,async()=>{let e=await i.readyBinary(o.target.runtime,u,`bridge-preparation-deadline`),a=r.consume(o.target,f,p),l=await n.request({target:o.target,bridge:e,limits:c,maxDepth:d,nativeLevelsHint:a.nativeLevels,deadline:u});s(u,`snapshot-decode-deadline`);let m=Ae(o.hint,o.target,l,c);return Oe(t,r,o.target,f,p,a,l),{stage:`acquired`,acquisition:m}},{producer:Q})}catch(e){let t=f(e);return{stage:`failed`,failure:{kind:t.failureKind,code:t.failureCode,...t.details?{details:t.details}:{}}}}},close:async()=>{a||(a=!0,i.close(),await n.close())}}}function De(t){if(!t.target.simulator.udid.trim()||!t.target.runtime.trim()||!t.target.generation.trim()||!Number.isSafeInteger(t.target.pid)||t.target.pid<=0)throw new e(`INVALID_ARGS`,`Simulator snapshot source target identity is incomplete`);let n=t.hint;if(n.projection!==`raw`&&n.projection!==`regular`||![`full`,`surface-observation`].includes(n.acquisitionIntent)||typeof n.interactiveOnly!=`boolean`||typeof n.customActions!=`boolean`||!$(n.rawTraversalDepth)||!$(n.regularPresentedDepth))throw new e(`INVALID_ARGS`,`Simulator snapshot source capture hint is invalid`)}function Oe(e,t,n,r,i,a,o){let s=re(o),c=o.truncated===!0,l=t.learn(n,r,i,s);e.emitDiagnostic({level:`debug`,phase:`ios_snapshot_source_recovery`,data:{producer:Q,...n.targetId?{targetId:n.targetId}:{},generation:n.generation,requestedLevels:r,hint:a.reason,...a.nativeLevels===void 0?{}:{hintedLevels:a.nativeLevels},...s,truncated:c,learning:l}})}function ke(t,n){let r=t.rawTraversalDepth??n;if(r>n)throw new e(`INVALID_ARGS`,`Simulator snapshot source depth exceeds its bound`,{requested:r,maximum:n});return r}function $(e){return e===null||Number.isSafeInteger(e)&&e>=0}function Ae(e,t,n,r){if(n.automationEnabled!==!0)throw l(`unsupported`,`automation-mode-unavailable`);let i=n.tree,a=n.truncated;if(typeof a!=`boolean`)throw l(`malformed-tree`,`truncated-invalid`);let o=me(i,{truncated:a},r),s=n.generation;if(typeof s!=`string`||!s)throw l(`malformed-tree`,`generation-invalid`);if(o.opaqueRemoteElements>0)throw l(`unsupported`,`remote-content-boundary`,{remoteElements:o.opaqueRemoteElements});if(o.unresolvedCoordinateSpaceWindows>0)throw l(`unsupported`,`window-coordinate-space-unresolved`,{windows:o.unresolvedCoordinateSpaceWindows});let c=Object.freeze(o.nodes.map(e=>Object.freeze({...e,pid:t.pid}))),u=je(e,a,o.viewport),d=Object.freeze({...t.targetId?{targetId:t.targetId}:{},generation:s}),f={producer:Q,nodes:c,truncated:a,viewport:o.viewport,lineage:d,residue:u};return e.acquisitionIntent===`full`?{...f,intent:`full`,hint:{...e,acquisitionIntent:`full`}}:{...f,intent:`surface-observation`,hint:{...e,acquisitionIntent:`surface-observation`}}}function je(e,t,n){let r=n.kind===`reported`?[]:[{kind:`unavailable-fact`,fact:`hittability`}];return Object.freeze([...r,...e.interactiveOnly?[{kind:`unavailable-fact`,fact:`interactive-query`}]:[],...t?[{kind:`truncated`}]:[],...n.kind===`missing`?[{kind:`missing-viewport`,reason:n.reason}]:[]])}export{Ee as createSimulatorSnapshotSource};
|