agent-device 0.21.16 → 0.21.18
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.16.apk → agent-device-android-ime-helper-0.21.18.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.18.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.16.manifest.json → agent-device-android-ime-helper-0.21.18.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.16.apk → agent-device-android-snapshot-helper-0.21.18.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.18.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.16.manifest.json → agent-device-android-snapshot-helper-0.21.18.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +31 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +9 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +40 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +4 -0
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +2 -2
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/adb-transport.js +1 -1
- package/dist/src/agent-browser-process-record.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/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/back-mode.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/boot-diagnostics.js +1 -1
- package/dist/src/cache.js +1 -0
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +6 -5
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +4 -4
- package/dist/src/click-button.js +1 -1
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +5 -5
- package/dist/src/clipboard-shell-response.js +1 -1
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/command-schema.js +3 -3
- 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.js +1 -1
- package/dist/src/daemon-client-lease-beat.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-client-transport.js +1 -1
- package/dist/src/daemon-policy-file.js +1 -0
- package/dist/src/daemon-process.js +1 -1
- package/dist/src/daemon-registration.js +1 -1
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/debug-symbols-facade.js +1 -1
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -2
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/{stop-sequence.js → device-readiness-runtime.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/device.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/doctor-facade.js +1 -1
- package/dist/src/doctor2.js +1 -1
- package/dist/src/durable-resource.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 -2
- package/dist/src/gesture-admission.js +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/host.js +1 -1
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.d.ts +1 -1
- 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 +5 -5
- 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-runtime.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/legacy-xctest-device-set.js +1 -0
- package/dist/src/limrun-download-file.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +1 -1
- 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 +10 -10
- package/dist/src/multitouch-support.js +1 -1
- package/dist/src/observation.js +1 -1
- package/dist/src/overlay.js +3 -3
- package/dist/src/owner-identity.js +3 -3
- 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 +1 -1
- package/dist/src/perf.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-app-log-process.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 +2 -2
- 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-unavailable.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/process.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 +2 -2
- 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/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/result-serialization.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/runner-cache-metadata.js +3 -3
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-command-traits.js +1 -0
- 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 +2 -2
- package/dist/src/runner-exchange.js +1 -0
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-owner-facade.js +1 -1
- package/dist/src/runner-session-types.js +1 -0
- package/dist/src/runner-start-budget.js +1 -0
- package/dist/src/runner-startup-transport.js +1 -0
- package/dist/src/runner-xctestrun.js +1 -0
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-transport-hints.js +1 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/runtime10.js +2 -2
- package/dist/src/runtime2.js +3 -3
- 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/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-image.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 +4 -1
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/scroll-gesture.js +1 -1
- package/dist/src/sdk-batch-runner.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +10 -0
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.js +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/session2.js +5 -4
- package/dist/src/settings.js +1 -1
- package/dist/src/settings2.js +1 -1
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-boot.js +1 -1
- package/dist/src/simulator.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/src7.js +1 -1
- package/dist/src/src8.js +2 -2
- package/dist/src/string-enum.js +1 -1
- package/dist/src/takeover.js +1 -1
- package/dist/src/target-evidence.js +1 -0
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider.js +1 -1
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/transport.js +2 -2
- package/dist/src/tv-remote.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/vars.js +2 -0
- 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.16.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.16.apk.sha256 +0 -1
- package/dist/src/capture-disclosure.js +0 -1
- package/dist/src/fold-runtime.js +0 -1
- package/dist/src/native-build-cache.js +0 -1
package/dist/src/runtime10.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{B as e,I as t,M as n,P as r}from"./sdk-contracts.js";import{i}from"./recording-export-quality.js";import{_ as a,a as o,d as s,f as c,g as l,i as u,o as d,p as f,r as p,t as ee,v as te,x as m,y as ne}from"./runtime.js";import{r as h}from"./success-text.js";import{n as re,t as ie}from"./app-inventory.js";import"./app-inventory-contract.js";import{D as ae}from"./owner-identity.js";import{c as oe}from"./exec.js";import"./file.js";import{r as se}from"./tv-remote.js";import"./command.js";import{r as g}from"./version.js";import{t as ce}from"./keyboard-actions.js";import{i as le}from"./quality-warnings.js";import{i as ue}from"./png-worker-client.js";import{r as _}from"./png.js";import{t as de}from"./png-size.js";import{i as v,n as fe,r as pe}from"./screenshot-overlay-draw.js";import{t as me}from"./png-encode.js";import{r as y}from"./artifact-paths.js";import{t as he}from"./mp4-duration.js";import{c as b,o as ge,r as _e,s as ve}from"./video.js";import x from"node:path";import S from"node:fs";import ye from"node:os";function C(e,t){if(e!==void 0)return w(e,t)}function w(e,t){let r=e?.trim();if(!r)throw new n(`INVALID_ARGS`,`${t} must be a non-empty string`);return r}const be=async(e,t={})=>{if(!e.backend.listDevices)throw new n(`UNSUPPORTED_OPERATION`,`admin.devices is not supported by this backend`);return{kind:`adminDevices`,devices:await e.backend.listDevices(f(e,t),t.filter)}},xe=async(e,t={})=>{if(!e.backend.bootDevice)throw new n(`UNSUPPORTED_OPERATION`,`admin.boot is not supported by this backend`);let r=D(t.target),i=await e.backend.bootDevice(f(e,t),r),a=c(i);return{kind:`deviceBooted`,...r?{target:r}:{},...a?{backendResult:a}:{},...h(`Booted device`)}},Se=async(e,t={})=>{if(!e.backend.shutdownDevice)throw new n(`UNSUPPORTED_OPERATION`,`admin.shutdown is not supported by this backend`);let r=D(t.target),i=await e.backend.shutdownDevice(f(e,t),r),a=c(i);return{kind:`deviceShutdown`,...r?{target:r}:{},...a?{backendResult:a}:{},...h(`Shutdown device`)}},Ce=async(e,t)=>await T(e,t,`install`),we=async(e,t)=>await T(e,t,`reinstall`),Te=async(e,t)=>await T(e,t,`installFromSource`);async function T(e,t,r){let i=r===`reinstall`?`reinstallApp`:`installApp`,a=e.backend[i];if(!a)throw new n(`UNSUPPORTED_OPERATION`,`admin.${r} is not supported by this backend`);let o=`app`in t&&t.app!==void 0?w(t.app,`app`):void 0;if(r!==`installFromSource`&&!o)throw new n(`INVALID_ARGS`,`admin.${r} requires app`);let s=f(e,t),c=await Ee(e,s,t.source);try{let t=await a.call(e.backend,s,{...o?{app:o}:{},source:c.source});return ke(r,o,c.source,t)}finally{await c.cleanup?.()}}async function Ee(e,t,n){let r=await De(e,E(n));try{return{source:E(e.backend.resolveInstallSource?await e.backend.resolveInstallSource(t,r.source):r.source),...r.cleanup?{cleanup:r.cleanup}:{}}}catch(e){if(r.cleanup)try{await r.cleanup()}catch{}throw e}}async function De(e,t){if(t.kind===`url`)return{source:t};let n=await u(e,t,{usage:`admin.install`,field:`source`});return{source:{kind:`path`,path:n.path},...n.cleanup?{cleanup:n.cleanup}:{}}}function E(e){if(!e||typeof e!=`object`)throw new n(`INVALID_ARGS`,`install source is required`);if(e.kind===`path`)return{kind:`path`,path:w(e.path,`source.path`)};if(e.kind===`uploadedArtifact`)return{kind:`uploadedArtifact`,id:w(e.id,`source.id`)};if(e.kind===`url`){let t=w(e.url,`source.url`);return Oe(t),{kind:`url`,url:t}}throw new n(`INVALID_ARGS`,`install source kind must be path, uploadedArtifact, or url`)}function Oe(e){let t;try{t=new URL(e)}catch{throw new n(`INVALID_ARGS`,`Invalid install source URL: ${e}`)}if(t.protocol!==`http:`&&t.protocol!==`https:`)throw new n(`INVALID_ARGS`,`Install source URL must use http or https`)}function D(e){if(!e)return;let t=C(e.id,`target.id`),n=C(e.name,`target.name`),r={...t?{id:t}:{},...n?{name:n}:{},...e.platform?{platform:e.platform}:{},...e.target?{target:e.target}:{},...e.headless===void 0?{}:{headless:e.headless}};return Object.keys(r).length>0?r:void 0}function ke(e,t,n,r){let i=c(r),a=e===`reinstall`?`appReinstalled`:e===`installFromSource`?`appInstalledFromSource`:`appInstalled`,o=O(r,`appName`),s=O(r,`appId`),l=O(r,`bundleId`),u=O(r,`packageName`),d=O(r,`launchTarget`),f=O(r,`installablePath`),p=O(r,`archivePath`);return{kind:a,...t?{app:t}:{},source:n,...s?{appId:s}:{},...o?{appName:o}:{},...l?{bundleId:l}:{},...u?{packageName:u}:{},...d?{launchTarget:d}:{},...f?{installablePath:f}:{},...p?{archivePath:p}:{},...i?{backendResult:i}:{},...h(`${e===`reinstall`?`Reinstalled`:`Installed`}: ${o??d??t??Ae(n)}`)}}function O(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Ae(e){return e.kind===`path`?e.path:e.kind===`uploadedArtifact`?e.id:e.url}const je=/^[A-Za-z0-9_.:-]{1,64}$/,Me=async(e,t)=>{if(!e.backend.openApp)throw new n(`UNSUPPORTED_OPERATION`,`apps.open is not supported by this backend`);let r=Re(t),i=await e.backend.openApp(A(e,t),r,{launchArgs:t.launchArgs,relaunch:t.relaunch}),a=c(i);return{kind:`appOpened`,target:r,relaunch:t.relaunch===!0,...a?{backendResult:a}:{},...h(`Opened: ${Be(r)}`)}},Ne=async(e,t={})=>{if(!e.backend.closeApp)throw new n(`UNSUPPORTED_OPERATION`,`apps.close is not supported by this backend`);let r=C(t.app,`app`),i=await e.backend.closeApp(A(e,t),r),a=c(i);return{kind:`appClosed`,...r?{app:r}:{},...a?{backendResult:a}:{},...h(r?`Closed: ${r}`:`Closed app`)}},Pe=async(e,t={})=>{if(!e.backend.listApps)throw new n(`UNSUPPORTED_OPERATION`,`apps.list is not supported by this backend`);return{kind:`appsList`,apps:await e.backend.listApps(A(e,t),ie(t.filter))}},Fe=async(e,t)=>{if(!e.backend.getAppState)throw new n(`UNSUPPORTED_OPERATION`,`apps.state is not supported by this backend`);let r=w(t.app,`app`);return{kind:`appState`,app:r,state:await e.backend.getAppState(A(e,t),r)}},Ie=async(e,t)=>{if(!e.backend.pushFile)throw new n(`UNSUPPORTED_OPERATION`,`apps.push is not supported by this backend`);let r=w(t.app,`app`),i=await Ve(e,t.input);try{let n=await e.backend.pushFile(A(e,t),i.backendInput,r),a=c(n);return{kind:`appPushed`,app:r,inputKind:i.inputKind,...a?{backendResult:a}:{},...h(`Pushed to ${r}`)}}finally{await i.cleanup?.()}},Le=async(e,t)=>{if(!e.backend.triggerAppEvent)throw new n(`UNSUPPORTED_OPERATION`,`apps.triggerEvent is not supported by this backend`);let r=He(t.name);Ue(t.payload,`apps.triggerEvent payload for "${r}"`);let i=await e.backend.triggerAppEvent(A(e,t),{name:r,...t.payload?{payload:t.payload}:{}}),a=c(i);return{kind:`appEventTriggered`,name:r,...t.payload?{payload:t.payload}:{},...a?{backendResult:a}:{},...h(`Triggered app event: ${r}`)}};function Re(e){let t=C(e.app,`app`),r=C(e.appId,`appId`),i=C(e.bundleId,`bundleId`),a=C(e.packageName,`packageName`),o=C(e.url,`url`),s=C(e.activity,`activity`),c={...t?{app:t}:{},...r?{appId:r}:{},...i?{bundleId:i}:{},...a?{packageName:a}:{},...o?{url:o}:{},...s?{activity:s}:{}};if(!ze(c))throw new n(`INVALID_ARGS`,`apps.open requires app, appId, bundleId, packageName, url, or activity`);return c}function ze(e){return!!(e.app??e.appId??e.bundleId??e.packageName??e.url??e.activity)}function Be(e){return e.app??e.appId??e.bundleId??e.packageName??e.url??e.activity??`app`}async function Ve(e,t){if(!t||typeof t!=`object`)throw new n(`INVALID_ARGS`,`apps.push requires an input`);if(t.kind===`json`)return k(t.payload,`apps.push JSON payload`,8192),{backendInput:{kind:`json`,payload:t.payload},inputKind:`json`};let r=await u(e,t,{usage:`apps.push`,field:`input`});return{backendInput:{kind:`file`,path:r.path},inputKind:`file`,...r.cleanup?{cleanup:r.cleanup}:{}}}function He(e){let t=w(e,`name`);if(!je.test(t))throw new n(`INVALID_ARGS`,`Invalid apps.triggerEvent name: ${t}`,{hint:`Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash.`});return t}function Ue(e,t){e!==void 0&&k(e,t,8192)}function k(e,t,r){if(We(e,t),Buffer.byteLength(Ge(e,t),`utf8`)>r)throw new n(`INVALID_ARGS`,`${t} exceeds ${r} bytes`)}function We(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw new n(`INVALID_ARGS`,`${t} must be a JSON object`)}function Ge(e,t){try{let r=JSON.stringify(e);if(typeof r!=`string`)throw new n(`INVALID_ARGS`,`${t} must be JSON-serializable`);return r}catch{throw new n(`INVALID_ARGS`,`${t} must be JSON-serializable`)}}function A(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}const j={open:Me,close:Ne,list:Pe,state:Fe,push:Ie,triggerEvent:Le},Ke={devices:be,boot:xe,shutdown:Se,install:Ce,reinstall:we,installFromSource:Te};function qe(e){return{...s(j,e),list:(t={})=>j.list(e,{...t,filter:re(t.filter)})}}const Je=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i,Ye=/\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g;function Xe(e){let t=!1,n=e;return n=n.replaceAll(/(authorization|token|secret|password|passwd|api[-_]?key)=([^&\s]+)/gi,(e,n)=>(t=!0,`${String(n)}=[REDACTED]`)),n=n.replaceAll(/("(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)"\s*:\s*")([^"]*)(")/gi,(e,n,r,i)=>(t=!0,`${String(n)}[REDACTED]${String(i)}`)),n=n.replaceAll(/\b(Bearer\s+)([^\s",;]+)/gi,(e,n)=>(t=!0,`${String(n)}[REDACTED]`)),n=n.replaceAll(/((?:authorization|cookie|token|secret|password|passwd|api[-_]?key)\s*[:=]\s*)([^\s,;&]+)/gi,(e,n)=>(t=!0,`${String(n)}[REDACTED]`)),n=n.replaceAll(Ye,()=>(t=!0,`[REDACTED]`)),n=Qe(n,()=>{t=!0}),{value:n,redacted:t}}function Ze(e){try{let t=new URL(e),n=$e(t);return(t.username||t.password)&&(t.username=`REDACTED`,t.password=`REDACTED`,n=!0),{value:t.toString(),redacted:n}}catch{return}}function Qe(e,t){return/(https?:\/\/|token|secret|password|authorization|cookie|api[-_]?key)/i.test(e)?e.replaceAll(/https?:\/\/[^\s"'<>)]+/gi,e=>{let n=Ze(e);return n?(n.redacted&&t(),n.value):e}):e}function $e(e){let t=!1;for(let n of Array.from(e.searchParams.keys()))Je.test(n)&&(e.searchParams.set(n,`[REDACTED]`),t=!0);return t}const M=2048,N=4096,P=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i;function et(e){let t=e.redacted===!0;return{kind:`diagnosticsLogs`,entries:e.entries.map(e=>{let n=z(e.message,N),r=L(e.metadata);return t||=n.redacted||r.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.level?{level:e.level}:{},message:n.value??``,...e.source?{source:e.source}:{},...r.value?{metadata:r.value}:{}}}),...e.nextCursor?{nextCursor:e.nextCursor}:{},...e.timeWindow?{timeWindow:e.timeWindow}:{},...e.backend?{backend:e.backend}:{},redacted:t,...e.notes?{notes:e.notes}:{}}}function tt(e,t){let n=e.redacted===!0;return{kind:`diagnosticsNetwork`,entries:e.entries.map(e=>{let r=e.url?rt(e.url):void 0,i=t===`headers`||t===`all`?F(e.requestHeaders):void 0,a=t===`headers`||t===`all`?F(e.responseHeaders):void 0,o=t===`body`||t===`all`?I(e.requestBody):void 0,s=t===`body`||t===`all`?I(e.responseBody):void 0,c=L(e.metadata);return n||=(r?.redacted??!1)||(i?.redacted??!1)||(a?.redacted??!1)||(o?.redacted??!1)||(s?.redacted??!1)||c.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.method?{method:e.method}:{},...r?{url:r.value}:{},...e.status===void 0?{}:{status:e.status},...e.durationMs===void 0?{}:{durationMs:e.durationMs},...i?.value?{requestHeaders:i.value}:{},...a?.value?{responseHeaders:a.value}:{},...o?.value===void 0?{}:{requestBody:o.value},...s?.value===void 0?{}:{responseBody:s.value},...c.value?{metadata:c.value}:{}}}),...e.nextCursor?{nextCursor:e.nextCursor}:{},...e.timeWindow?{timeWindow:e.timeWindow}:{},...e.backend?{backend:e.backend}:{},redacted:n,...e.notes?{notes:e.notes}:{}}}function nt(e){let t=e.redacted===!0;return{kind:`diagnosticsPerf`,metrics:e.metrics.map(e=>{let n=z(e.message,N),r=L(e.metadata);return t||=n.redacted||r.redacted,{name:e.name,...e.value===void 0?{}:{value:e.value},...e.unit?{unit:e.unit}:{},...e.status?{status:e.status}:{},...n.value===void 0?{}:{message:n.value},...r.value?{metadata:r.value}:{}}}),...e.startedAt?{startedAt:e.startedAt}:{},...e.endedAt?{endedAt:e.endedAt}:{},...e.backend?{backend:e.backend}:{},redacted:t,...e.notes?{notes:e.notes}:{}}}function F(e){if(!e)return{redacted:!1};let t=!1,n={};for(let[r,i]of Object.entries(e))if(P.test(r))n[r]=`[REDACTED]`,t=!0;else{let e=z(i,M);n[r]=e.value??``,t||=e.redacted}return{value:n,redacted:t}}function rt(e){return Ze(e)??z(e,M)}function I(e){return e===void 0?{redacted:!1}:it(e)??z(e,M)}function it(e){try{let t=R(JSON.parse(e),Xe);return B(JSON.stringify(t.value),M,t.redacted)}catch{return}}function L(e){return R(e,e=>z(e,M))}function R(e,t){if(e===void 0)return{redacted:!1};if(typeof e==`string`)return t(e);if(!e||typeof e!=`object`)return{value:e,redacted:!1};if(Array.isArray(e)){let n=!1;return{value:e.map(e=>{let r=R(e,t);return n||=r.redacted,r.value}),redacted:n}}let n=!1,r={};for(let[i,a]of Object.entries(e)){if(P.test(i)){r[i]=`[REDACTED]`,n=!0;continue}let e=R(a,t);r[i]=e.value,n||=e.redacted}return{value:r,redacted:n}}function z(e,t){if(e===void 0)return{redacted:!1};let n=Xe(e);return B(n.value,t,n.redacted)}function B(e,t,n){if(e===void 0)return{redacted:n};let r=e;return r.length>t&&(r=`${r.slice(0,t)}...[truncated]`,n=!0),{value:r,redacted:n}}const at=async(e,t={})=>{if(!e.backend.readLogs)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.logs is not supported by this backend`);return et(await e.backend.readLogs(await V(e,t),ct(t)))},ot=async(e,t={})=>{if(!e.backend.dumpNetwork)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.network is not supported by this backend`);let r=lt(t);return tt(await e.backend.dumpNetwork(await V(e,t),r),r.include??`summary`)},st=async(e,t={})=>{if(!e.backend.measurePerf)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.perf is not supported by this backend`);return nt(await e.backend.measurePerf(await V(e,t),ut(t)))};async function V(e,t){let n=f(e,t),r=t.session?await e.sessions.get(t.session):void 0;return{...n,...t.appId??r?.appId?{appId:t.appId??r?.appId}:{},...t.appBundleId??r?.appBundleId?{appBundleId:t.appBundleId??r?.appBundleId}:{}}}function ct(e){return{...H(e,100,500,`logs limit`),...e.levels===void 0?{}:{levels:W(e.levels,`levels`)},...e.search===void 0?{}:{search:w(e.search,`search`)},...e.source===void 0?{}:{source:w(e.source,`source`)}}}function lt(e){return{...H(e,25,200,`network limit`),include:dt(e.include)}}function ut(e){return{...U(e),...e.sampleMs===void 0?{}:{sampleMs:m(e.sampleMs,`sampleMs`,100,6e4)},...e.metrics===void 0?{}:{metrics:W(e.metrics,`metrics`,20)}}}function H(e,t,n,r){return{...U(e),...e.cursor===void 0?{}:{cursor:w(e.cursor,`cursor`)},limit:e.limit===void 0?t:m(e.limit,r,1,n)}}function U(e){return{...e.since===void 0?{}:{since:w(e.since,`since`)},...e.until===void 0?{}:{until:w(e.until,`until`)}}}function dt(e){if(e===void 0)return`summary`;if(e===`summary`||e===`headers`||e===`body`||e===`all`)return e;throw new n(`INVALID_ARGS`,`network include must be summary, headers, body, or all`)}function W(e,t,r=50){if(!Array.isArray(e))throw new n(`INVALID_ARGS`,`${t} must be an array of strings`);if(e.length>r)throw new n(`INVALID_ARGS`,`${t} must contain at most ${r} entries`);return e.map((e,n)=>w(e,`${t}[${n}]`))}const ft={logs:at,network:ot,perf:st},G=`contact_sheet_frame_extraction_failed`,K=`contact_sheet_no_frames`;function q(e=process.platform){if(e!==`darwin`)throw new n(`UNSUPPORTED_OPERATION`,`Contact sheets can only be built on macOS hosts, which is where the frame decoder runs`,{reason:`contact_sheet_unsupported_host`,hostPlatform:e,hint:`Run this command on the macOS host that recorded the clip, or read the video artifact itself.`})}async function pt(e){if(q(e.hostPlatform??process.platform),e.timesMs.length===0)throw new n(`COMMAND_FAILED`,`Contact sheet sampling requested no frames`,{reason:K,videoPath:e.videoPath});vt(e.signal);let t=await _t(e);vt(e.signal);let r;try{r=await oe(t,[`--input`,e.videoPath,`--output-dir`,e.scratchDir,`--times`,e.timesMs.join(`,`),`--max-width`,String(e.maxWidth)],{timeoutMs:9e4,env:ge(),allowFailure:!0,...e.signal===void 0?{}:{signal:e.signal}})}catch(t){X(t,e.videoPath,`Failed to run the frame decoder`)}if(r.exitCode!==0)throw new n(`COMMAND_FAILED`,`Failed to extract frames from the recording: ${gt(r.stderr)||`exit ${r.exitCode}`}`,{reason:G,videoPath:e.videoPath,exitCode:r.exitCode});let i=mt(r.stdout,e.videoPath,e.scratchDir,e.timesMs.length);if(i.frames.length===0)throw new n(`COMMAND_FAILED`,`The recording returned no decodable frames for a contact sheet`,{reason:K,videoPath:e.videoPath,skippedSampleCount:i.skippedSampleCount});return i}function mt(e,t,n,r){let i;try{i=JSON.parse(e)}catch(e){throw Y(t,`invalid manifest: ${String(e)}`)}let a=Z(i).frames;if(!Array.isArray(a))throw Y(t,`manifest has no frames array`);let o=Z(i).skipped;if(a.length>r)throw Y(t,`returned ${a.length} frames for ${r} requested samples`);let s=a.flatMap(e=>{let r=Z(e),i=ht(r.path),a=Q(r.actualTimeMs);if(i===void 0||a===void 0||a<0)throw Y(t,`frame entry is missing a path or presentation time`);let o=x.resolve(n,x.basename(i));return S.existsSync(o)?[{requestedTimeMs:Q(r.requestedTimeMs)??a,actualTimeMs:a,path:o}]:[]});return{frames:s.sort((e,t)=>e.actualTimeMs-t.actualTimeMs),skippedSampleCount:Math.max(Array.isArray(o)?o.length:0,r-s.length)}}function J(e,t,r){return new n(`COMMAND_FAILED`,e,{reason:G,videoPath:t},r)}function Y(e,t){return J(`Frame extraction returned an unreadable manifest: ${t}`,e)}function X(r,i,a){throw e(r)||r instanceof n&&r.code===`COMMAND_FAILED`&&r.details?.reason?r:J(`${a} for ${i}: ${t(r)}`,i,r)}function Z(e){return typeof e==`object`&&e?e:{}}function ht(e){return typeof e==`string`&&e!==``?e:void 0}function Q(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function gt(e){return(e.trim().split(`
|
|
2
|
-
`).pop()??``).trim()}async function _t(e){try{return await ve({sourcePath:b(`recording-frames.swift`,g()),extraSourcePaths:[b(`RecordingExportSupport.swift`,g())],cacheName:`recording-frames`,timeoutMs:12e4})}catch(t){X(t,e.videoPath,`Could not build the frame decoder`)}}function vt(e){if(e?.aborted)throw r()}function yt(e,t){if(e===void 0||!Number.isFinite(e)||e<0)throw new n(`COMMAND_FAILED`,`Cannot plan a contact sheet: the video timeline of ${t} could not be read`,{reason:`contact_sheet_duration_unknown`,videoPath:t,hint:`Retry once the recording finished finalizing; a clip whose container is still being written has no readable duration.`});if(e<=250)return{durationMs:e,timesMs:e>0?[0,Math.round(e)]:[0]};let r=Math.min(48,Math.floor(e/250)+1),i=e/(r-1);return{durationMs:e,timesMs:Array.from({length:r},(e,t)=>Math.round(t*i))}}const bt=[360,320,280,240,200,160],xt=[255,255,255,255],St=[17,24,39,255],$=pe(2)+8;function Ct(e){let{cells:t}=e;if(t.length===0)throw new n(`COMMAND_FAILED`,`Contact sheet has no cells to render`);let r=Tt(t[0].image.height/Math.max(1,t[0].image.width),t.length,e),i=Ot(r.width,r.height,St);return t.forEach((e,t)=>{let n=t%r.columns,a=Math.floor(t/r.columns);wt(i,8+n*(r.cellWidth+8),8+a*($+r.cellHeight+8),e,r.cellWidth,r.cellHeight)}),{bytes:me(i.data,r.width,r.height,4),width:r.width,height:r.height,cellWidth:r.cellWidth}}function wt(e,t,n,r,i,a){fe(e,{x:t+4,y:n+4,text:jt(r.timeMs),color:xt,scale:2}),kt(e,le(At(r.image),i,a),t,n+$)}function Tt(e,t,r){let i=Et(e,t,r.maxPixels);if(i)return i;let a=Dt(e,t,160);throw new n(`COMMAND_FAILED`,`Contact sheet would be ${a.width*a.height} pixels, above the configured maxImagePixels limit of ${r.maxPixels}`,{reason:`contact_sheet_pixel_budget_exceeded`,cellCount:r.cells.length,maxPixels:r.maxPixels,hint:`Shorten the recording or raise the command policy maxImagePixels limit.`})}function Et(e,t,n){for(let r of bt){let i=Dt(e,t,r);if(i.width*i.height<=n)return i}}function Dt(e,t,n){let r=Math.min(4,t),i=Math.ceil(t/r),a=Math.max(1,Math.round(n*e));return{columns:r,cellWidth:n,cellHeight:a,width:16+r*n+(r-1)*8,height:16+i*($+a)+(i-1)*8}}function Ot(e,t,n){let r=new _.PNG({width:e,height:t});for(let i=0;i<t;i+=1)for(let t=0;t<e;t+=1)v(r,t,i,n);return r}function kt(e,t,n,r){for(let i=0;i<t.height;i+=1)for(let a=0;a<t.width;a+=1){let o=(i*t.width+a)*4;v(e,n+a,r+i,[t.data[o],t.data[o+1],t.data[o+2],t.data[o+3]])}}function At(e){let t=new _.PNG({width:e.width,height:e.height});return Buffer.from(e.data.buffer,e.data.byteOffset,e.data.byteLength).copy(t.data),t}function jt(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=Math.floor(e%1e3);return`${[n,r,i].map(e=>String(e).padStart(2,`0`)).join(`:`)}.${String(a).padStart(3,`0`)}`}function Mt(e,t){if(e.width!==t.width||e.height!==t.height)return{status:`dimension_mismatch`};let n=e.width*e.height;if(n===0)return{status:`compared`,changedPixelRatio:0};if(e.data.length!==t.data.length)return{status:`dimension_mismatch`};let r=0;for(let n=0;n+3<e.data.length;n+=4)(e.data[n]!==t.data[n]||e.data[n+1]!==t.data[n+1]||e.data[n+2]!==t.data[n+2])&&(r+=1);return{status:`compared`,changedPixelRatio:r/n}}function Nt(e,t=.02,n=24){let r=[],i;for(let n of e){let e=i?Ft(i,n.image):1;e<t||(r.push({timeMs:n.timeMs,changedPixelRatio:e,image:n.image}),i=n.image)}Pt(r,e);let a=r.length>n?It(r,n):r;return{cells:a,keptCellCount:r.length,thinned:a.length<r.length}}function Pt(e,t){let n=t.at(-1);if(!n)return;let r=e.at(-1);!r||r.timeMs===n.timeMs||e.push({timeMs:n.timeMs,changedPixelRatio:Ft(r.image,n.image),image:n.image})}function Ft(e,t){let n=Mt(e,t);return n.status===`compared`?n.changedPixelRatio:1}function It(e,t){if(t<=1)return[e.at(-1)];let n=(e.length-1)/(t-1);return Array.from({length:t},(t,r)=>e[Math.round(r*n)])}async function Lt(e){q(e.hostPlatform??process.platform);let t=x.resolve(e.videoPath),r=x.resolve(e.outputPath??y(t));Bt(t,r);let i=await _e(t);if(i!==`mp4`)throw new n(`INVALID_ARGS`,i===`webm`?`Contact sheets need an MP4 recording; ${t} is WebM, whose frames this decoder does not read`:`Contact sheets need an MP4 recording; ${t} is not a readable MP4`,{reason:`contact_sheet_container_unsupported`,videoPath:t,container:i??`unknown`,hint:`Re-record on a backend that exports MP4, or pass the MP4 artifact the recording produced.`});let a=yt(he(t),t),o=S.mkdtempSync(x.join(ye.tmpdir(),`agent-device-contact-sheet-`));try{let n=await pt({videoPath:t,scratchDir:o,timesMs:a.timesMs,maxWidth:360,hostPlatform:e.hostPlatform??process.platform,...e.signal===void 0?{}:{signal:e.signal}}),i=await Rt(n.frames,e.maxPixels);zt(e.signal);let s=Nt(i,e.changedPixelThreshold??.02),c=Ct({cells:s.cells,maxPixels:e.maxPixels});return Gt(r,c.bytes),{path:r,videoPath:t,durationMs:a.durationMs,width:c.width,height:c.height,sampledFrameCount:a.timesMs.length,decodedFrameCount:n.frames.length,skippedSampleCount:n.skippedSampleCount,changedPixelThreshold:e.changedPixelThreshold??.02,cells:s.cells.map(Ut),...Wt(s,n)}}finally{S.rmSync(o,{recursive:!0,force:!0})}}async function Rt(e,t){let r=[];for(let i of e){let e=await de(i.path);if(e.width>360)throw new n(`COMMAND_FAILED`,`Frame extraction returned a ${e.width}px-wide frame when the sheet asked for 360px cells`,{reason:G,framePath:i.path,frameWidth:e.width,frameWidthLimit:360});if(e.width*e.height>t)throw new n(`COMMAND_FAILED`,`Frame extraction returned a ${e.width}x${e.height} frame, above the ${t}-pixel budget for the whole sheet`,{reason:G,framePath:i.path,framePixels:e.width*e.height,maxPixels:t});let a=await ue(S.readFileSync(i.path),`recording frame`);r.push({timeMs:i.actualTimeMs,image:a})}return r}function zt(e){if(e?.aborted)throw r()}function Bt(e,t){if(Vt(e,t)??t===e)throw new n(`INVALID_ARGS`,`A contact sheet cannot be written over the recording it describes: ${t}`,{reason:`contact_sheet_output_collides_with_input`,videoPath:e,outputPath:t,hint:`Choose a different --out path, or omit it to write beside the recording.`})}function Vt(e,t){let n=Ht(e),r=Ht(t);if(n!==void 0&&r!==void 0)return n.dev===r.dev&&n.ino===r.ino}function Ht(e){try{return S.statSync(e)}catch{return}}function Ut(e){return{timeMs:e.timeMs,changedPixelRatio:e.changedPixelRatio}}function Wt(e,t){let n=[];return t.skippedSampleCount>0&&n.push(`${t.skippedSampleCount} sample times returned no frame, so the sheet covers less of the recording than it asked for`),e.thinned&&n.push(`${e.keptCellCount} changes were found and 24 cells are printed, so the sheet thins evenly across the recording instead of showing every change`),n.length===0?{}:{warning:n.join(`; `)}}function Gt(e,t){try{S.mkdirSync(x.dirname(e),{recursive:!0}),ae({destination:e,contents:t})}catch(t){throw new n(`COMMAND_FAILED`,`Failed to write the contact sheet to ${e}: ${t instanceof Error?t.message:String(t)}`,{reason:`contact_sheet_output_write_failed`,outputPath:e})}}const Kt=async(e,t)=>{if(!t.video)throw new n(`INVALID_ARGS`,`record contact-sheet requires a recording to read`);Jt(t.changedPixelThreshold);let r=await u(e,t.video,{usage:`record contact-sheet`,field:`video`}),i;try{let n=qt(t,t.video,r.path);i=await p(e,n,{field:`path`,ext:`.png`,artifactType:`screen-recording-contact-sheet`});let a=await Lt({videoPath:r.path,outputPath:i.path,maxPixels:e.policy.maxImagePixels,...t.changedPixelThreshold===void 0?{}:{changedPixelThreshold:t.changedPixelThreshold},signal:t.signal??e.signal}),o=await i.publish();return{...a,path:Yt(a.path,o),...o?{artifact:o}:{}}}catch(e){throw await i?.cleanup?.(),e}finally{await r.cleanup?.()}};function qt(e,t,r){if(e.out)return e.out;if(t.kind===`path`)return{kind:`path`,path:x.resolve(y(t.path||r))};throw new n(`INVALID_ARGS`,`record contact-sheet needs an output path when the recording is an uploaded artifact`,{hint:"Pass --out <sheet.png> (CLI) or `out` (Node) to name where the sheet is written."})}function Jt(e){if(e!==void 0&&(!Number.isFinite(e)||e<0||e>1))throw new n(`INVALID_ARGS`,`record contact-sheet needs a changedPixelThreshold between 0 and 1, got ${e}`,{reason:`contact_sheet_threshold_invalid`,changedPixelThreshold:e,hint:`Omit it to use the calibrated default, or pass a share of the frame between 0 and 1.`})}function Yt(e,t){return t?t.kind===`localPath`?t.path:t.clientPath??e:e}const Xt=async(e,t)=>{let r=tn(t.action,`record`),i=r===`start`?e.backend.startRecording:e.backend.stopRecording;if(!i)throw new n(`UNSUPPORTED_OPERATION`,`record ${r} is not supported by this backend`);let a=t.out?await p(e,t.out,{field:`path`,ext:`.mp4`,artifactType:`screen-recording`}):void 0;try{let n=Qt(t,a?.path);return nn(r,await i.call(e.backend,f(e,t),n),await a?.publish())}catch(e){throw await a?.cleanup?.(),e}},Zt=async(e,t)=>{let r=tn(t.action,`trace`),i=r===`start`?e.backend.startTrace:e.backend.stopTrace;if(!i)throw new n(`UNSUPPORTED_OPERATION`,`trace ${r} is not supported by this backend`);let a=t.out?await p(e,t.out,{field:`outPath`,ext:`.trace`,artifactType:`trace-log`}):void 0;try{let n=a?.path?{outPath:a.path}:{};return rn(r,await i.call(e.backend,f(e,t),n),await a?.publish())}catch(e){throw await a?.cleanup?.(),e}};function Qt(e,t){let n={};t&&(n.outPath=t);let r=$t(e.fps);r!==void 0&&(n.fps=r);let i=en(e.quality);return i!==void 0&&(n.quality=i),e.hideTouches!==void 0&&(n.showTouches=e.hideTouches!==!0),n}function $t(e){return e===void 0?void 0:m(e,`fps`,1,60)}function en(e){if(e===void 0)return;let t=i(e);if(t===void 0)throw new n(`INVALID_ARGS`,`quality must be one of: medium, high (legacy numeric values 5-10 are accepted)`);return t}function tn(e,t){if(e===`start`||e===`stop`)return e;throw new n(`INVALID_ARGS`,`${t} action must be start or stop`)}function nn(e,t,n){return{...typeof t.path==`string`?{path:t.path}:{},...typeof t.telemetryPath==`string`?{telemetryPath:t.telemetryPath}:{},...typeof t.warning==`string`?{warning:t.warning}:{},...an(e,t,n,{startKind:`recordingStarted`,stopKind:`recordingStopped`,startMessage:`Recording started`,stopMessage:`Recording stopped`})}}function rn(e,t,n){return{...typeof t.outPath==`string`?{outPath:t.outPath}:{},...an(e,t,n,{startKind:`traceStarted`,stopKind:`traceStopped`,startMessage:`Trace started`,stopMessage:`Trace stopped`})}}function an(e,t,n,r){return{kind:e===`start`?r.startKind:r.stopKind,action:e,...n?{artifact:n}:{},backendResult:t,...h(e===`start`?r.startMessage:r.stopMessage)}}const on={record:Xt,trace:Zt,contactSheet:Kt},sn=async(e,t={})=>{if(!e.backend.pressBack)throw new n(`UNSUPPORTED_OPERATION`,`system.back is not supported by this backend`);let r=t.mode??`in-app`;if(r!==`in-app`&&r!==`system`)throw new n(`INVALID_ARGS`,`system.back mode must be in-app or system`);let i=await e.backend.pressBack(f(e,t),{mode:r}),a=c(i);return{kind:`systemBack`,mode:r,...a?{backendResult:a}:{},...h(`Back`)}},cn=async(e,t={})=>{if(!e.backend.pressHome)throw new n(`UNSUPPORTED_OPERATION`,`system.home is not supported by this backend`);let r=await e.backend.pressHome(f(e,t)),i=c(r);return{kind:`systemHome`,...i?{backendResult:i}:{},...h(`Home`)}},ln=async(e,t)=>{if(!e.backend.pressTvRemote)throw new n(`UNSUPPORTED_OPERATION`,`system.tvRemote is not supported by this backend`);let r=se(t.button),i=t.durationMs===void 0?void 0:m(t.durationMs,`durationMs`,0,1e4),a=await e.backend.pressTvRemote(f(e,t),{button:r,...i===void 0?{}:{durationMs:i}}),o=c(a);return{kind:`tvRemotePressed`,button:r,...i===void 0?{}:{durationMs:i},...o?{backendResult:o}:{},...h(`Pressed TV remote ${r}`)}},un=async(e,t)=>{if(!e.backend.setOrientation)throw new n(`UNSUPPORTED_OPERATION`,`system.orientation is not supported by this backend`);let r=gn(t.orientation),i=await e.backend.setOrientation(f(e,t),r),a=c(i);return{kind:`systemOrientationSet`,orientation:r,...a?{backendResult:a}:{},...h(`Rotated to ${r}`)}},dn=async(e,t={})=>{if(!e.backend.setKeyboard)throw new n(`UNSUPPORTED_OPERATION`,`system.keyboard is not supported by this backend`);let r=t.action??`status`;if(!ce(r))throw new n(`INVALID_ARGS`,`system.keyboard action must be status, get, dismiss, enter, or return`);let i=await e.backend.setKeyboard(f(e,t),{action:r}),a=c(i),o=Tn(i)?i:{};return r===`enter`||r===`return`?vn(o,a):r===`dismiss`?yn(r,o,a):xn(r,o,a)},fn=async(e,t)=>{if(t.action===`read`){if(!e.backend.getClipboard)throw new n(`UNSUPPORTED_OPERATION`,`system.clipboard read is not supported by this backend`);let r=await e.backend.getClipboard(f(e,t));return{kind:`clipboardText`,action:`read`,text:typeof r==`string`?r:r.text}}if(t.action!==`write`)throw new n(`INVALID_ARGS`,`system.clipboard action must be read or write`);if(!e.backend.setClipboard)throw new n(`UNSUPPORTED_OPERATION`,`system.clipboard write is not supported by this backend`);if(typeof t.text!=`string`)throw new n(`INVALID_ARGS`,`system.clipboard write requires text`);let r=await e.backend.setClipboard(f(e,t),t.text),i=c(r);return{kind:`clipboardUpdated`,action:`write`,textLength:Array.from(t.text).length,...i?{backendResult:i}:{},...h(`Clipboard updated`)}},pn=async(e,t={})=>{if(!e.backend.openSettings)throw new n(`UNSUPPORTED_OPERATION`,`system.settings is not supported by this backend`);let r=C(t.target,`target`),i=await e.backend.openSettings(f(e,t),r),a=c(i);return{kind:`settingsOpened`,...r?{target:r}:{},...a?{backendResult:a}:{},...h(r?`Opened settings: ${r}`:`Opened settings`)}},mn=async(e,t={})=>{if(!e.backend.handleAlert)throw new n(`UNSUPPORTED_OPERATION`,`system.alert is not supported by this backend`);let r=t.action??`get`;if(r!==`get`&&r!==`accept`&&r!==`dismiss`&&r!==`wait`)throw new n(`INVALID_ARGS`,`system.alert action must be get, accept, dismiss, or wait`);let i=t.timeoutMs===void 0?void 0:m(t.timeoutMs,`timeoutMs`,0,12e4);return _n(r,await e.backend.handleAlert(f(e,t),r,{timeoutMs:i}))},hn=async(e,t={})=>{if(!e.backend.openAppSwitcher)throw new n(`UNSUPPORTED_OPERATION`,`system.appSwitcher is not supported by this backend`);let r=await e.backend.openAppSwitcher(f(e,t)),i=c(r);return{kind:`appSwitcherOpened`,...i?{backendResult:i}:{},...h(`Opened app switcher`)}};function gn(e){switch(e){case`portrait`:case`portrait-upside-down`:case`landscape-left`:case`landscape-right`:return e;default:throw new n(`INVALID_ARGS`,`system.orientation must be portrait, portrait-upside-down, landscape-left, or landscape-right`)}}function _n(e,t){return e===`get`?Sn(t):e===`wait`?Cn(t):wn(e,t)}function vn(e,t){return{kind:`keyboardEnterPressed`,action:`enter`,state:e,...t?{backendResult:t}:{},...h(`Keyboard enter pressed`)}}function yn(e,t,n){return{kind:`keyboardDismissed`,action:e,state:t,...n?{backendResult:n}:{},...h(bn(t))}}function bn(e){return e.dismissed===!1?`Keyboard already hidden`:e.mechanism===`dismissKey`?`Keyboard dismissed via its dismiss key`:`Keyboard dismissed`}function xn(e,t,n){return{kind:`keyboardState`,action:e,state:t,...n?{backendResult:n}:{}}}function Sn(e){if(e.kind!==`alertStatus`)throw new n(`COMMAND_FAILED`,`system.alert get returned an invalid backend result`);return{kind:`alertStatus`,action:`get`,alert:e.alert}}function Cn(e){if(e.kind!==`alertWait`)throw new n(`COMMAND_FAILED`,`system.alert wait returned an invalid backend result`);return{kind:`alertWait`,action:`wait`,alert:e.alert,...e.waitedMs===void 0?{}:{waitedMs:e.waitedMs},...e.timedOut===void 0?{}:{timedOut:e.timedOut},...h(e.alert?`Alert visible`:`Alert wait timed out`)}}function wn(e,t){if(t.kind!==`alertHandled`)throw new n(`COMMAND_FAILED`,`system.alert ${e} returned an invalid backend result`);return{kind:`alertHandled`,action:e,handled:t.handled,...t.alert?{alert:t.alert}:{},...t.button?{button:t.button}:{},...h(t.handled?`Alert ${e}ed`:`No alert handled`)}}function Tn(e){return!!(e&&typeof e==`object`)}const En={back:sn,home:cn,orientation:un,keyboard:dn,clipboard:fn,settings:pn,alert:mn,appSwitcher:hn,tvRemote:ln};function Dn(e){return{capture:ee(e),selectors:d(e),interactions:o(e),system:s(En,e),apps:qe(e),admin:s(Ke,e),recording:s(on,e),observability:s(ft,e)}}function On(e){let t=l(e);return{...t,...Dn(t)}}export{On as createAgentDevice,a as createMemorySessionStore,te as localCommandPolicy,ne as restrictedCommandPolicy};
|
|
1
|
+
import{F as e,L as t,N as n,V as r}from"./sdk-contracts.js";import{i}from"./recording-export-quality.js";import{D as a,E as o,T as s,a as c,b as l,i as u,k as d,o as f,r as p,t as ee,w as te,x as m,y as h}from"./runtime.js";import{r as g}from"./success-text.js";import{n as ne,t as re}from"./app-inventory.js";import"./app-inventory-contract.js";import{k as ie}from"./owner-identity.js";import{c as ae}from"./exec.js";import"./file.js";import{r as oe}from"./tv-remote.js";import"./command.js";import{r as _}from"./version.js";import{t as se}from"./keyboard-actions.js";import{i as ce}from"./quality-warnings.js";import{r as v}from"./png.js";import{i as le}from"./png-worker-client.js";import{t as ue}from"./png-size.js";import{i as y,n as de,r as fe}from"./screenshot-overlay-draw.js";import{t as pe}from"./png-encode.js";import{r as me}from"./artifact-paths.js";import{t as he}from"./mp4-duration.js";import{c as b,o as ge,r as _e,s as ve}from"./video.js";import x from"node:path";import S from"node:fs";import ye from"node:os";function C(e,t){if(e!==void 0)return w(e,t)}function w(e,t){let r=e?.trim();if(!r)throw new n(`INVALID_ARGS`,`${t} must be a non-empty string`);return r}const be=async(e,t={})=>{if(!e.backend.listDevices)throw new n(`UNSUPPORTED_OPERATION`,`admin.devices is not supported by this backend`);return{kind:`adminDevices`,devices:await e.backend.listDevices(m(e,t),t.filter)}},xe=async(e,t={})=>{if(!e.backend.bootDevice)throw new n(`UNSUPPORTED_OPERATION`,`admin.boot is not supported by this backend`);let r=D(t.target),i=await e.backend.bootDevice(m(e,t),r),a=l(i);return{kind:`deviceBooted`,...r?{target:r}:{},...a?{backendResult:a}:{},...g(`Booted device`)}},Se=async(e,t={})=>{if(!e.backend.shutdownDevice)throw new n(`UNSUPPORTED_OPERATION`,`admin.shutdown is not supported by this backend`);let r=D(t.target),i=await e.backend.shutdownDevice(m(e,t),r),a=l(i);return{kind:`deviceShutdown`,...r?{target:r}:{},...a?{backendResult:a}:{},...g(`Shutdown device`)}},Ce=async(e,t)=>await T(e,t,`install`),we=async(e,t)=>await T(e,t,`reinstall`),Te=async(e,t)=>await T(e,t,`installFromSource`);async function T(e,t,r){let i=r===`reinstall`?`reinstallApp`:`installApp`,a=e.backend[i];if(!a)throw new n(`UNSUPPORTED_OPERATION`,`admin.${r} is not supported by this backend`);let o=`app`in t&&t.app!==void 0?w(t.app,`app`):void 0;if(r!==`installFromSource`&&!o)throw new n(`INVALID_ARGS`,`admin.${r} requires app`);let s=m(e,t),c=await Ee(e,s,t.source);try{let t=await a.call(e.backend,s,{...o?{app:o}:{},source:c.source});return ke(r,o,c.source,t)}finally{await c.cleanup?.()}}async function Ee(e,t,n){let r=await De(e,E(n));try{return{source:E(e.backend.resolveInstallSource?await e.backend.resolveInstallSource(t,r.source):r.source),...r.cleanup?{cleanup:r.cleanup}:{}}}catch(e){if(r.cleanup)try{await r.cleanup()}catch{}throw e}}async function De(e,t){if(t.kind===`url`)return{source:t};let n=await u(e,t,{usage:`admin.install`,field:`source`});return{source:{kind:`path`,path:n.path},...n.cleanup?{cleanup:n.cleanup}:{}}}function E(e){if(!e||typeof e!=`object`)throw new n(`INVALID_ARGS`,`install source is required`);if(e.kind===`path`)return{kind:`path`,path:w(e.path,`source.path`)};if(e.kind===`uploadedArtifact`)return{kind:`uploadedArtifact`,id:w(e.id,`source.id`)};if(e.kind===`url`){let t=w(e.url,`source.url`);return Oe(t),{kind:`url`,url:t}}throw new n(`INVALID_ARGS`,`install source kind must be path, uploadedArtifact, or url`)}function Oe(e){let t;try{t=new URL(e)}catch{throw new n(`INVALID_ARGS`,`Invalid install source URL: ${e}`)}if(t.protocol!==`http:`&&t.protocol!==`https:`)throw new n(`INVALID_ARGS`,`Install source URL must use http or https`)}function D(e){if(!e)return;let t=C(e.id,`target.id`),n=C(e.name,`target.name`),r={...t?{id:t}:{},...n?{name:n}:{},...e.platform?{platform:e.platform}:{},...e.target?{target:e.target}:{},...e.headless===void 0?{}:{headless:e.headless}};return Object.keys(r).length>0?r:void 0}function ke(e,t,n,r){let i=l(r),a=e===`reinstall`?`appReinstalled`:e===`installFromSource`?`appInstalledFromSource`:`appInstalled`,o=O(r,`appName`),s=O(r,`appId`),c=O(r,`bundleId`),u=O(r,`packageName`),d=O(r,`launchTarget`),f=O(r,`installablePath`),p=O(r,`archivePath`);return{kind:a,...t?{app:t}:{},source:n,...s?{appId:s}:{},...o?{appName:o}:{},...c?{bundleId:c}:{},...u?{packageName:u}:{},...d?{launchTarget:d}:{},...f?{installablePath:f}:{},...p?{archivePath:p}:{},...i?{backendResult:i}:{},...g(`${e===`reinstall`?`Reinstalled`:`Installed`}: ${o??d??t??Ae(n)}`)}}function O(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:void 0}function Ae(e){return e.kind===`path`?e.path:e.kind===`uploadedArtifact`?e.id:e.url}const je=/^[A-Za-z0-9_.:-]{1,64}$/,Me=async(e,t)=>{if(!e.backend.openApp)throw new n(`UNSUPPORTED_OPERATION`,`apps.open is not supported by this backend`);let r=Re(t),i=await e.backend.openApp(A(e,t),r,{launchArgs:t.launchArgs,relaunch:t.relaunch}),a=l(i);return{kind:`appOpened`,target:r,relaunch:t.relaunch===!0,...a?{backendResult:a}:{},...g(`Opened: ${Be(r)}`)}},Ne=async(e,t={})=>{if(!e.backend.closeApp)throw new n(`UNSUPPORTED_OPERATION`,`apps.close is not supported by this backend`);let r=C(t.app,`app`),i=await e.backend.closeApp(A(e,t),r),a=l(i);return{kind:`appClosed`,...r?{app:r}:{},...a?{backendResult:a}:{},...g(r?`Closed: ${r}`:`Closed app`)}},Pe=async(e,t={})=>{if(!e.backend.listApps)throw new n(`UNSUPPORTED_OPERATION`,`apps.list is not supported by this backend`);return{kind:`appsList`,apps:await e.backend.listApps(A(e,t),re(t.filter))}},Fe=async(e,t)=>{if(!e.backend.getAppState)throw new n(`UNSUPPORTED_OPERATION`,`apps.state is not supported by this backend`);let r=w(t.app,`app`);return{kind:`appState`,app:r,state:await e.backend.getAppState(A(e,t),r)}},Ie=async(e,t)=>{if(!e.backend.pushFile)throw new n(`UNSUPPORTED_OPERATION`,`apps.push is not supported by this backend`);let r=w(t.app,`app`),i=await Ve(e,t.input);try{let n=await e.backend.pushFile(A(e,t),i.backendInput,r),a=l(n);return{kind:`appPushed`,app:r,inputKind:i.inputKind,...a?{backendResult:a}:{},...g(`Pushed to ${r}`)}}finally{await i.cleanup?.()}},Le=async(e,t)=>{if(!e.backend.triggerAppEvent)throw new n(`UNSUPPORTED_OPERATION`,`apps.triggerEvent is not supported by this backend`);let r=He(t.name);Ue(t.payload,`apps.triggerEvent payload for "${r}"`);let i=await e.backend.triggerAppEvent(A(e,t),{name:r,...t.payload?{payload:t.payload}:{}}),a=l(i);return{kind:`appEventTriggered`,name:r,...t.payload?{payload:t.payload}:{},...a?{backendResult:a}:{},...g(`Triggered app event: ${r}`)}};function Re(e){let t=C(e.app,`app`),r=C(e.appId,`appId`),i=C(e.bundleId,`bundleId`),a=C(e.packageName,`packageName`),o=C(e.url,`url`),s=C(e.activity,`activity`),c={...t?{app:t}:{},...r?{appId:r}:{},...i?{bundleId:i}:{},...a?{packageName:a}:{},...o?{url:o}:{},...s?{activity:s}:{}};if(!ze(c))throw new n(`INVALID_ARGS`,`apps.open requires app, appId, bundleId, packageName, url, or activity`);return c}function ze(e){return!!(e.app??e.appId??e.bundleId??e.packageName??e.url??e.activity)}function Be(e){return e.app??e.appId??e.bundleId??e.packageName??e.url??e.activity??`app`}async function Ve(e,t){if(!t||typeof t!=`object`)throw new n(`INVALID_ARGS`,`apps.push requires an input`);if(t.kind===`json`)return k(t.payload,`apps.push JSON payload`,8192),{backendInput:{kind:`json`,payload:t.payload},inputKind:`json`};let r=await u(e,t,{usage:`apps.push`,field:`input`});return{backendInput:{kind:`file`,path:r.path},inputKind:`file`,...r.cleanup?{cleanup:r.cleanup}:{}}}function He(e){let t=w(e,`name`);if(!je.test(t))throw new n(`INVALID_ARGS`,`Invalid apps.triggerEvent name: ${t}`,{hint:`Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash.`});return t}function Ue(e,t){e!==void 0&&k(e,t,8192)}function k(e,t,r){if(We(e,t),Buffer.byteLength(Ge(e,t),`utf8`)>r)throw new n(`INVALID_ARGS`,`${t} exceeds ${r} bytes`)}function We(e,t){if(!e||typeof e!=`object`||Array.isArray(e))throw new n(`INVALID_ARGS`,`${t} must be a JSON object`)}function Ge(e,t){try{let r=JSON.stringify(e);if(typeof r!=`string`)throw new n(`INVALID_ARGS`,`${t} must be JSON-serializable`);return r}catch{throw new n(`INVALID_ARGS`,`${t} must be JSON-serializable`)}}function A(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}const j={open:Me,close:Ne,list:Pe,state:Fe,push:Ie,triggerEvent:Le},Ke={devices:be,boot:xe,shutdown:Se,install:Ce,reinstall:we,installFromSource:Te};function qe(e){return{...h(j,e),list:(t={})=>j.list(e,{...t,filter:ne(t.filter)})}}const Je=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i,Ye=/\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g;function M(e){let t=!1,n=e;return n=n.replaceAll(/(authorization|token|secret|password|passwd|api[-_]?key)=([^&\s]+)/gi,(e,n)=>(t=!0,`${String(n)}=[REDACTED]`)),n=n.replaceAll(/("(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)"\s*:\s*")([^"]*)(")/gi,(e,n,r,i)=>(t=!0,`${String(n)}[REDACTED]${String(i)}`)),n=n.replaceAll(/\b(Bearer\s+)([^\s",;]+)/gi,(e,n)=>(t=!0,`${String(n)}[REDACTED]`)),n=n.replaceAll(/((?:authorization|cookie|token|secret|password|passwd|api[-_]?key)\s*[:=]\s*)([^\s,;&]+)/gi,(e,n)=>(t=!0,`${String(n)}[REDACTED]`)),n=n.replaceAll(Ye,()=>(t=!0,`[REDACTED]`)),n=Ze(n,()=>{t=!0}),{value:n,redacted:t}}function Xe(e){try{let t=new URL(e),n=Qe(t);return(t.username||t.password)&&(t.username=`REDACTED`,t.password=`REDACTED`,n=!0),{value:t.toString(),redacted:n}}catch{return}}function Ze(e,t){return/(https?:\/\/|token|secret|password|authorization|cookie|api[-_]?key)/i.test(e)?e.replaceAll(/https?:\/\/[^\s"'<>)]+/gi,e=>{let n=Xe(e);return n?(n.redacted&&t(),n.value):e}):e}function Qe(e){let t=!1;for(let n of Array.from(e.searchParams.keys()))Je.test(n)&&(e.searchParams.set(n,`[REDACTED]`),t=!0);return t}const N=2048,P=4096,F=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i;function $e(e){let t=e.redacted===!0;return{kind:`diagnosticsLogs`,entries:e.entries.map(e=>{let n=B(e.message,P),r=R(e.metadata);return t||=n.redacted||r.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.level?{level:e.level}:{},message:n.value??``,...e.source?{source:e.source}:{},...r.value?{metadata:r.value}:{}}}),...e.nextCursor?{nextCursor:e.nextCursor}:{},...e.timeWindow?{timeWindow:e.timeWindow}:{},...e.backend?{backend:e.backend}:{},redacted:t,...e.notes?{notes:e.notes}:{}}}function et(e,t){let n=e.redacted===!0;return{kind:`diagnosticsNetwork`,entries:e.entries.map(e=>{let r=e.url?nt(e.url):void 0,i=t===`headers`||t===`all`?I(e.requestHeaders):void 0,a=t===`headers`||t===`all`?I(e.responseHeaders):void 0,o=t===`body`||t===`all`?L(e.requestBody):void 0,s=t===`body`||t===`all`?L(e.responseBody):void 0,c=R(e.metadata);return n||=(r?.redacted??!1)||(i?.redacted??!1)||(a?.redacted??!1)||(o?.redacted??!1)||(s?.redacted??!1)||c.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.method?{method:e.method}:{},...r?{url:r.value}:{},...e.status===void 0?{}:{status:e.status},...e.durationMs===void 0?{}:{durationMs:e.durationMs},...i?.value?{requestHeaders:i.value}:{},...a?.value?{responseHeaders:a.value}:{},...o?.value===void 0?{}:{requestBody:o.value},...s?.value===void 0?{}:{responseBody:s.value},...c.value?{metadata:c.value}:{}}}),...e.nextCursor?{nextCursor:e.nextCursor}:{},...e.timeWindow?{timeWindow:e.timeWindow}:{},...e.backend?{backend:e.backend}:{},redacted:n,...e.notes?{notes:e.notes}:{}}}function tt(e){let t=e.redacted===!0;return{kind:`diagnosticsPerf`,metrics:e.metrics.map(e=>{let n=B(e.message,P),r=R(e.metadata);return t||=n.redacted||r.redacted,{name:e.name,...e.value===void 0?{}:{value:e.value},...e.unit?{unit:e.unit}:{},...e.status?{status:e.status}:{},...n.value===void 0?{}:{message:n.value},...r.value?{metadata:r.value}:{}}}),...e.startedAt?{startedAt:e.startedAt}:{},...e.endedAt?{endedAt:e.endedAt}:{},...e.backend?{backend:e.backend}:{},redacted:t,...e.notes?{notes:e.notes}:{}}}function I(e){if(!e)return{redacted:!1};let t=!1,n={};for(let[r,i]of Object.entries(e))if(F.test(r))n[r]=`[REDACTED]`,t=!0;else{let e=B(i,N);n[r]=e.value??``,t||=e.redacted}return{value:n,redacted:t}}function nt(e){return Xe(e)??B(e,N)}function L(e){return e===void 0?{redacted:!1}:rt(e)??B(e,N)}function rt(e){try{let t=z(JSON.parse(e),M);return V(JSON.stringify(t.value),N,t.redacted)}catch{return}}function R(e){return z(e,e=>B(e,N))}function z(e,t){if(e===void 0)return{redacted:!1};if(typeof e==`string`)return t(e);if(!e||typeof e!=`object`)return{value:e,redacted:!1};if(Array.isArray(e)){let n=!1;return{value:e.map(e=>{let r=z(e,t);return n||=r.redacted,r.value}),redacted:n}}let n=!1,r={};for(let[i,a]of Object.entries(e)){if(F.test(i)){r[i]=`[REDACTED]`,n=!0;continue}let e=z(a,t);r[i]=e.value,n||=e.redacted}return{value:r,redacted:n}}function B(e,t){if(e===void 0)return{redacted:!1};let n=M(e);return V(n.value,t,n.redacted)}function V(e,t,n){if(e===void 0)return{redacted:n};let r=e;return r.length>t&&(r=`${r.slice(0,t)}...[truncated]`,n=!0),{value:r,redacted:n}}const it=async(e,t={})=>{if(!e.backend.readLogs)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.logs is not supported by this backend`);return $e(await e.backend.readLogs(await H(e,t),st(t)))},at=async(e,t={})=>{if(!e.backend.dumpNetwork)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.network is not supported by this backend`);let r=ct(t);return et(await e.backend.dumpNetwork(await H(e,t),r),r.include??`summary`)},ot=async(e,t={})=>{if(!e.backend.measurePerf)throw new n(`UNSUPPORTED_OPERATION`,`diagnostics.perf is not supported by this backend`);return tt(await e.backend.measurePerf(await H(e,t),lt(t)))};async function H(e,t){let n=m(e,t),r=t.session?await e.sessions.get(t.session):void 0;return{...n,...t.appId??r?.appId?{appId:t.appId??r?.appId}:{},...t.appBundleId??r?.appBundleId?{appBundleId:t.appBundleId??r?.appBundleId}:{}}}function st(e){return{...U(e,100,500,`logs limit`),...e.levels===void 0?{}:{levels:G(e.levels,`levels`)},...e.search===void 0?{}:{search:w(e.search,`search`)},...e.source===void 0?{}:{source:w(e.source,`source`)}}}function ct(e){return{...U(e,25,200,`network limit`),include:ut(e.include)}}function lt(e){return{...W(e),...e.sampleMs===void 0?{}:{sampleMs:d(e.sampleMs,`sampleMs`,100,6e4)},...e.metrics===void 0?{}:{metrics:G(e.metrics,`metrics`,20)}}}function U(e,t,n,r){return{...W(e),...e.cursor===void 0?{}:{cursor:w(e.cursor,`cursor`)},limit:e.limit===void 0?t:d(e.limit,r,1,n)}}function W(e){return{...e.since===void 0?{}:{since:w(e.since,`since`)},...e.until===void 0?{}:{until:w(e.until,`until`)}}}function ut(e){if(e===void 0)return`summary`;if(e===`summary`||e===`headers`||e===`body`||e===`all`)return e;throw new n(`INVALID_ARGS`,`network include must be summary, headers, body, or all`)}function G(e,t,r=50){if(!Array.isArray(e))throw new n(`INVALID_ARGS`,`${t} must be an array of strings`);if(e.length>r)throw new n(`INVALID_ARGS`,`${t} must contain at most ${r} entries`);return e.map((e,n)=>w(e,`${t}[${n}]`))}const dt={logs:it,network:at,perf:ot},K=`contact_sheet_frame_extraction_failed`,q=`contact_sheet_no_frames`;function J(e=process.platform){if(e!==`darwin`)throw new n(`UNSUPPORTED_OPERATION`,`Contact sheets can only be built on macOS hosts, which is where the frame decoder runs`,{reason:`contact_sheet_unsupported_host`,hostPlatform:e,hint:`Run this command on the macOS host that recorded the clip, or read the video artifact itself.`})}async function ft(e){if(J(e.hostPlatform??process.platform),e.timesMs.length===0)throw new n(`COMMAND_FAILED`,`Contact sheet sampling requested no frames`,{reason:q,videoPath:e.videoPath});vt(e.signal);let t=await _t(e);vt(e.signal);let r;try{r=await ae(t,[`--input`,e.videoPath,`--output-dir`,e.scratchDir,`--times`,e.timesMs.join(`,`),`--max-width`,String(e.maxWidth)],{timeoutMs:9e4,env:ge(),allowFailure:!0,...e.signal===void 0?{}:{signal:e.signal}})}catch(t){Z(t,e.videoPath,`Failed to run the frame decoder`)}if(r.exitCode!==0)throw new n(`COMMAND_FAILED`,`Failed to extract frames from the recording: ${gt(r.stderr)||`exit ${r.exitCode}`}`,{reason:K,videoPath:e.videoPath,exitCode:r.exitCode});let i=pt(r.stdout,e.videoPath,e.scratchDir,e.timesMs.length);if(i.frames.length===0)throw new n(`COMMAND_FAILED`,`The recording returned no decodable frames for a contact sheet`,{reason:q,videoPath:e.videoPath,skippedSampleCount:i.skippedSampleCount});return i}function pt(e,t,n,r){let i;try{i=JSON.parse(e)}catch(e){throw X(t,`invalid manifest: ${String(e)}`)}let a=Q(i).frames;if(!Array.isArray(a))throw X(t,`manifest has no frames array`);let o=Q(i).skipped;if(a.length>r)throw X(t,`returned ${a.length} frames for ${r} requested samples`);let s=a.flatMap(e=>{let r=Q(e),i=mt(r.path),a=ht(r.actualTimeMs);if(i===void 0||a===void 0||a<0)throw X(t,`frame entry is missing a path or presentation time`);let o=x.resolve(n,x.basename(i));return S.existsSync(o)?[{requestedTimeMs:ht(r.requestedTimeMs)??a,actualTimeMs:a,path:o}]:[]});return{frames:s.sort((e,t)=>e.actualTimeMs-t.actualTimeMs),skippedSampleCount:Math.max(Array.isArray(o)?o.length:0,r-s.length)}}function Y(e,t,r){return new n(`COMMAND_FAILED`,e,{reason:K,videoPath:t},r)}function X(e,t){return Y(`Frame extraction returned an unreadable manifest: ${t}`,e)}function Z(e,i,a){throw r(e)||e instanceof n&&e.code===`COMMAND_FAILED`&&e.details?.reason?e:Y(`${a} for ${i}: ${t(e)}`,i,e)}function Q(e){return typeof e==`object`&&e?e:{}}function mt(e){return typeof e==`string`&&e!==``?e:void 0}function ht(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function gt(e){return(e.trim().split(`
|
|
2
|
+
`).pop()??``).trim()}async function _t(e){try{return await ve({sourcePath:b(`recording-frames.swift`,_()),extraSourcePaths:[b(`RecordingExportSupport.swift`,_())],cacheName:`recording-frames`,timeoutMs:12e4})}catch(t){Z(t,e.videoPath,`Could not build the frame decoder`)}}function vt(t){if(t?.aborted)throw e()}function yt(e,t){if(e===void 0||!Number.isFinite(e)||e<0)throw new n(`COMMAND_FAILED`,`Cannot plan a contact sheet: the video timeline of ${t} could not be read`,{reason:`contact_sheet_duration_unknown`,videoPath:t,hint:`Retry once the recording finished finalizing; a clip whose container is still being written has no readable duration.`});if(e<=250)return{durationMs:e,timesMs:e>0?[0,Math.round(e)]:[0]};let r=Math.min(48,Math.floor(e/250)+1),i=e/(r-1);return{durationMs:e,timesMs:Array.from({length:r},(e,t)=>Math.round(t*i))}}const bt=[360,320,280,240,200,160],xt=[255,255,255,255],St=[17,24,39,255],$=fe(2)+8;function Ct(e){let{cells:t}=e;if(t.length===0)throw new n(`COMMAND_FAILED`,`Contact sheet has no cells to render`);let r=Tt(t[0].image.height/Math.max(1,t[0].image.width),t.length,e),i=Ot(r.width,r.height,St);return t.forEach((e,t)=>{let n=t%r.columns,a=Math.floor(t/r.columns);wt(i,8+n*(r.cellWidth+8),8+a*($+r.cellHeight+8),e,r.cellWidth,r.cellHeight)}),{bytes:pe(i.data,r.width,r.height,4),width:r.width,height:r.height,cellWidth:r.cellWidth}}function wt(e,t,n,r,i,a){de(e,{x:t+4,y:n+4,text:jt(r.timeMs),color:xt,scale:2}),kt(e,ce(At(r.image),i,a),t,n+$)}function Tt(e,t,r){let i=Et(e,t,r.maxPixels);if(i)return i;let a=Dt(e,t,160);throw new n(`COMMAND_FAILED`,`Contact sheet would be ${a.width*a.height} pixels, above the configured maxImagePixels limit of ${r.maxPixels}`,{reason:`contact_sheet_pixel_budget_exceeded`,cellCount:r.cells.length,maxPixels:r.maxPixels,hint:`Shorten the recording or raise the command policy maxImagePixels limit.`})}function Et(e,t,n){for(let r of bt){let i=Dt(e,t,r);if(i.width*i.height<=n)return i}}function Dt(e,t,n){let r=Math.min(4,t),i=Math.ceil(t/r),a=Math.max(1,Math.round(n*e));return{columns:r,cellWidth:n,cellHeight:a,width:16+r*n+(r-1)*8,height:16+i*($+a)+(i-1)*8}}function Ot(e,t,n){let r=new v.PNG({width:e,height:t});for(let i=0;i<t;i+=1)for(let t=0;t<e;t+=1)y(r,t,i,n);return r}function kt(e,t,n,r){for(let i=0;i<t.height;i+=1)for(let a=0;a<t.width;a+=1){let o=(i*t.width+a)*4;y(e,n+a,r+i,[t.data[o],t.data[o+1],t.data[o+2],t.data[o+3]])}}function At(e){let t=new v.PNG({width:e.width,height:e.height});return Buffer.from(e.data.buffer,e.data.byteOffset,e.data.byteLength).copy(t.data),t}function jt(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=Math.floor(e%1e3);return`${[n,r,i].map(e=>String(e).padStart(2,`0`)).join(`:`)}.${String(a).padStart(3,`0`)}`}function Mt(e,t){if(e.width!==t.width||e.height!==t.height)return{status:`dimension_mismatch`};let n=e.width*e.height;if(n===0)return{status:`compared`,changedPixelRatio:0};if(e.data.length!==t.data.length)return{status:`dimension_mismatch`};let r=0;for(let n=0;n+3<e.data.length;n+=4)(e.data[n]!==t.data[n]||e.data[n+1]!==t.data[n+1]||e.data[n+2]!==t.data[n+2])&&(r+=1);return{status:`compared`,changedPixelRatio:r/n}}function Nt(e,t=.02,n=24){let r=[],i;for(let n of e){let e=i?Ft(i,n.image):1;e<t||(r.push({timeMs:n.timeMs,changedPixelRatio:e,image:n.image}),i=n.image)}Pt(r,e);let a=r.length>n?It(r,n):r;return{cells:a,keptCellCount:r.length,thinned:a.length<r.length}}function Pt(e,t){let n=t.at(-1);if(!n)return;let r=e.at(-1);!r||r.timeMs===n.timeMs||e.push({timeMs:n.timeMs,changedPixelRatio:Ft(r.image,n.image),image:n.image})}function Ft(e,t){let n=Mt(e,t);return n.status===`compared`?n.changedPixelRatio:1}function It(e,t){if(t<=1)return[e.at(-1)];let n=(e.length-1)/(t-1);return Array.from({length:t},(t,r)=>e[Math.round(r*n)])}async function Lt(e){J(e.hostPlatform??process.platform);let t=x.resolve(e.videoPath),r=x.resolve(e.outputPath??me(t));Bt(t,r);let i=await _e(t);if(i!==`mp4`)throw new n(`INVALID_ARGS`,i===`webm`?`Contact sheets need an MP4 recording; ${t} is WebM, whose frames this decoder does not read`:`Contact sheets need an MP4 recording; ${t} is not a readable MP4`,{reason:`contact_sheet_container_unsupported`,videoPath:t,container:i??`unknown`,hint:`Re-record on a backend that exports MP4, or pass the MP4 artifact the recording produced.`});let a=yt(he(t),t),o=S.mkdtempSync(x.join(ye.tmpdir(),`agent-device-contact-sheet-`));try{let n=await ft({videoPath:t,scratchDir:o,timesMs:a.timesMs,maxWidth:360,hostPlatform:e.hostPlatform??process.platform,...e.signal===void 0?{}:{signal:e.signal}}),i=await Rt(n.frames,e.maxPixels);zt(e.signal);let s=Nt(i,e.changedPixelThreshold??.02),c=Ct({cells:s.cells,maxPixels:e.maxPixels});return Gt(r,c.bytes),{path:r,videoPath:t,durationMs:a.durationMs,width:c.width,height:c.height,sampledFrameCount:a.timesMs.length,decodedFrameCount:n.frames.length,skippedSampleCount:n.skippedSampleCount,changedPixelThreshold:e.changedPixelThreshold??.02,cells:s.cells.map(Ut),...Wt(s,n)}}finally{S.rmSync(o,{recursive:!0,force:!0})}}async function Rt(e,t){let r=[];for(let i of e){let e=await ue(i.path);if(e.width>360)throw new n(`COMMAND_FAILED`,`Frame extraction returned a ${e.width}px-wide frame when the sheet asked for 360px cells`,{reason:K,framePath:i.path,frameWidth:e.width,frameWidthLimit:360});if(e.width*e.height>t)throw new n(`COMMAND_FAILED`,`Frame extraction returned a ${e.width}x${e.height} frame, above the ${t}-pixel budget for the whole sheet`,{reason:K,framePath:i.path,framePixels:e.width*e.height,maxPixels:t});let a=await le(S.readFileSync(i.path),`recording frame`);r.push({timeMs:i.actualTimeMs,image:a})}return r}function zt(t){if(t?.aborted)throw e()}function Bt(e,t){if(Vt(e,t)??t===e)throw new n(`INVALID_ARGS`,`A contact sheet cannot be written over the recording it describes: ${t}`,{reason:`contact_sheet_output_collides_with_input`,videoPath:e,outputPath:t,hint:`Choose a different --out path, or omit it to write beside the recording.`})}function Vt(e,t){let n=Ht(e),r=Ht(t);if(n!==void 0&&r!==void 0)return n.dev===r.dev&&n.ino===r.ino}function Ht(e){try{return S.statSync(e)}catch{return}}function Ut(e){return{timeMs:e.timeMs,changedPixelRatio:e.changedPixelRatio}}function Wt(e,t){let n=[];return t.skippedSampleCount>0&&n.push(`${t.skippedSampleCount} sample times returned no frame, so the sheet covers less of the recording than it asked for`),e.thinned&&n.push(`${e.keptCellCount} changes were found and 24 cells are printed, so the sheet thins evenly across the recording instead of showing every change`),n.length===0?{}:{warning:n.join(`; `)}}function Gt(e,t){try{S.mkdirSync(x.dirname(e),{recursive:!0}),ie({destination:e,contents:t})}catch(t){throw new n(`COMMAND_FAILED`,`Failed to write the contact sheet to ${e}: ${t instanceof Error?t.message:String(t)}`,{reason:`contact_sheet_output_write_failed`,outputPath:e})}}const Kt=async(e,t)=>{if(!t.video)throw new n(`INVALID_ARGS`,`record contact-sheet requires a recording to read`);Jt(t.changedPixelThreshold);let r=await u(e,t.video,{usage:`record contact-sheet`,field:`video`}),i;try{let n=qt(t,t.video,r.path);i=await p(e,n,{field:`path`,ext:`.png`,artifactType:`screen-recording-contact-sheet`});let a=await Lt({videoPath:r.path,outputPath:i.path,maxPixels:e.policy.maxImagePixels,...t.changedPixelThreshold===void 0?{}:{changedPixelThreshold:t.changedPixelThreshold},signal:t.signal??e.signal}),o=await i.publish();return{...a,path:Yt(a.path,o),...o?{artifact:o}:{}}}catch(e){throw await i?.cleanup?.(),e}finally{await r.cleanup?.()}};function qt(e,t,r){if(e.out)return e.out;if(t.kind===`path`)return{kind:`path`,path:x.resolve(me(t.path||r))};throw new n(`INVALID_ARGS`,`record contact-sheet needs an output path when the recording is an uploaded artifact`,{hint:"Pass --out <sheet.png> (CLI) or `out` (Node) to name where the sheet is written."})}function Jt(e){if(e!==void 0&&(!Number.isFinite(e)||e<0||e>1))throw new n(`INVALID_ARGS`,`record contact-sheet needs a changedPixelThreshold between 0 and 1, got ${e}`,{reason:`contact_sheet_threshold_invalid`,changedPixelThreshold:e,hint:`Omit it to use the calibrated default, or pass a share of the frame between 0 and 1.`})}function Yt(e,t){return t?t.kind===`localPath`?t.path:t.clientPath??e:e}const Xt=async(e,t)=>{let r=tn(t.action,`record`),i=r===`start`?e.backend.startRecording:e.backend.stopRecording;if(!i)throw new n(`UNSUPPORTED_OPERATION`,`record ${r} is not supported by this backend`);let a=t.out?await p(e,t.out,{field:`path`,ext:`.mp4`,artifactType:`screen-recording`}):void 0;try{let n=Qt(t,a?.path);return nn(r,await i.call(e.backend,m(e,t),n),await a?.publish())}catch(e){throw await a?.cleanup?.(),e}},Zt=async(e,t)=>{let r=tn(t.action,`trace`),i=r===`start`?e.backend.startTrace:e.backend.stopTrace;if(!i)throw new n(`UNSUPPORTED_OPERATION`,`trace ${r} is not supported by this backend`);let a=t.out?await p(e,t.out,{field:`outPath`,ext:`.trace`,artifactType:`trace-log`}):void 0;try{let n=a?.path?{outPath:a.path}:{};return rn(r,await i.call(e.backend,m(e,t),n),await a?.publish())}catch(e){throw await a?.cleanup?.(),e}};function Qt(e,t){let n={};t&&(n.outPath=t);let r=$t(e.fps);r!==void 0&&(n.fps=r);let i=en(e.quality);return i!==void 0&&(n.quality=i),e.hideTouches!==void 0&&(n.showTouches=e.hideTouches!==!0),n}function $t(e){return e===void 0?void 0:d(e,`fps`,1,60)}function en(e){if(e===void 0)return;let t=i(e);if(t===void 0)throw new n(`INVALID_ARGS`,`quality must be one of: medium, high (legacy numeric values 5-10 are accepted)`);return t}function tn(e,t){if(e===`start`||e===`stop`)return e;throw new n(`INVALID_ARGS`,`${t} action must be start or stop`)}function nn(e,t,n){return{...typeof t.path==`string`?{path:t.path}:{},...typeof t.telemetryPath==`string`?{telemetryPath:t.telemetryPath}:{},...typeof t.warning==`string`?{warning:t.warning}:{},...an(e,t,n,{startKind:`recordingStarted`,stopKind:`recordingStopped`,startMessage:`Recording started`,stopMessage:`Recording stopped`})}}function rn(e,t,n){return{...typeof t.outPath==`string`?{outPath:t.outPath}:{},...an(e,t,n,{startKind:`traceStarted`,stopKind:`traceStopped`,startMessage:`Trace started`,stopMessage:`Trace stopped`})}}function an(e,t,n,r){return{kind:e===`start`?r.startKind:r.stopKind,action:e,...n?{artifact:n}:{},backendResult:t,...g(e===`start`?r.startMessage:r.stopMessage)}}const on={record:Xt,trace:Zt,contactSheet:Kt},sn=async(e,t={})=>{if(!e.backend.pressBack)throw new n(`UNSUPPORTED_OPERATION`,`system.back is not supported by this backend`);let r=t.mode??`in-app`;if(r!==`in-app`&&r!==`system`)throw new n(`INVALID_ARGS`,`system.back mode must be in-app or system`);let i=await e.backend.pressBack(m(e,t),{mode:r}),a=l(i);return{kind:`systemBack`,mode:r,...a?{backendResult:a}:{},...g(`Back`)}},cn=async(e,t={})=>{if(!e.backend.pressHome)throw new n(`UNSUPPORTED_OPERATION`,`system.home is not supported by this backend`);let r=await e.backend.pressHome(m(e,t)),i=l(r);return{kind:`systemHome`,...i?{backendResult:i}:{},...g(`Home`)}},ln=async(e,t)=>{if(!e.backend.pressTvRemote)throw new n(`UNSUPPORTED_OPERATION`,`system.tvRemote is not supported by this backend`);let r=oe(t.button),i=t.durationMs===void 0?void 0:d(t.durationMs,`durationMs`,0,1e4),a=await e.backend.pressTvRemote(m(e,t),{button:r,...i===void 0?{}:{durationMs:i}}),o=l(a);return{kind:`tvRemotePressed`,button:r,...i===void 0?{}:{durationMs:i},...o?{backendResult:o}:{},...g(`Pressed TV remote ${r}`)}},un=async(e,t)=>{if(!e.backend.setOrientation)throw new n(`UNSUPPORTED_OPERATION`,`system.orientation is not supported by this backend`);let r=gn(t.orientation),i=await e.backend.setOrientation(m(e,t),r),a=l(i);return{kind:`systemOrientationSet`,orientation:r,...a?{backendResult:a}:{},...g(`Rotated to ${r}`)}},dn=async(e,t={})=>{if(!e.backend.setKeyboard)throw new n(`UNSUPPORTED_OPERATION`,`system.keyboard is not supported by this backend`);let r=t.action??`status`;if(!se(r))throw new n(`INVALID_ARGS`,`system.keyboard action must be status, get, dismiss, enter, or return`);let i=await e.backend.setKeyboard(m(e,t),{action:r}),a=l(i),o=Tn(i)?i:{};return r===`enter`||r===`return`?vn(o,a):r===`dismiss`?yn(r,o,a):xn(r,o,a)},fn=async(e,t)=>{if(t.action===`read`){if(!e.backend.getClipboard)throw new n(`UNSUPPORTED_OPERATION`,`system.clipboard read is not supported by this backend`);let r=await e.backend.getClipboard(m(e,t));return{kind:`clipboardText`,action:`read`,text:typeof r==`string`?r:r.text}}if(t.action!==`write`)throw new n(`INVALID_ARGS`,`system.clipboard action must be read or write`);if(!e.backend.setClipboard)throw new n(`UNSUPPORTED_OPERATION`,`system.clipboard write is not supported by this backend`);if(typeof t.text!=`string`)throw new n(`INVALID_ARGS`,`system.clipboard write requires text`);let r=await e.backend.setClipboard(m(e,t),t.text),i=l(r);return{kind:`clipboardUpdated`,action:`write`,textLength:Array.from(t.text).length,...i?{backendResult:i}:{},...g(`Clipboard updated`)}},pn=async(e,t={})=>{if(!e.backend.openSettings)throw new n(`UNSUPPORTED_OPERATION`,`system.settings is not supported by this backend`);let r=C(t.target,`target`),i=await e.backend.openSettings(m(e,t),r),a=l(i);return{kind:`settingsOpened`,...r?{target:r}:{},...a?{backendResult:a}:{},...g(r?`Opened settings: ${r}`:`Opened settings`)}},mn=async(e,t={})=>{if(!e.backend.handleAlert)throw new n(`UNSUPPORTED_OPERATION`,`system.alert is not supported by this backend`);let r=t.action??`get`;if(r!==`get`&&r!==`accept`&&r!==`dismiss`&&r!==`wait`)throw new n(`INVALID_ARGS`,`system.alert action must be get, accept, dismiss, or wait`);let i=t.timeoutMs===void 0?void 0:d(t.timeoutMs,`timeoutMs`,0,12e4);return _n(r,await e.backend.handleAlert(m(e,t),r,{timeoutMs:i}))},hn=async(e,t={})=>{if(!e.backend.openAppSwitcher)throw new n(`UNSUPPORTED_OPERATION`,`system.appSwitcher is not supported by this backend`);let r=await e.backend.openAppSwitcher(m(e,t)),i=l(r);return{kind:`appSwitcherOpened`,...i?{backendResult:i}:{},...g(`Opened app switcher`)}};function gn(e){switch(e){case`portrait`:case`portrait-upside-down`:case`landscape-left`:case`landscape-right`:return e;default:throw new n(`INVALID_ARGS`,`system.orientation must be portrait, portrait-upside-down, landscape-left, or landscape-right`)}}function _n(e,t){return e===`get`?Sn(t):e===`wait`?Cn(t):wn(e,t)}function vn(e,t){return{kind:`keyboardEnterPressed`,action:`enter`,state:e,...t?{backendResult:t}:{},...g(`Keyboard enter pressed`)}}function yn(e,t,n){return{kind:`keyboardDismissed`,action:e,state:t,...n?{backendResult:n}:{},...g(bn(t))}}function bn(e){return e.dismissed===!1?`Keyboard already hidden`:e.mechanism===`dismissKey`?`Keyboard dismissed via its dismiss key`:`Keyboard dismissed`}function xn(e,t,n){return{kind:`keyboardState`,action:e,state:t,...n?{backendResult:n}:{}}}function Sn(e){if(e.kind!==`alertStatus`)throw new n(`COMMAND_FAILED`,`system.alert get returned an invalid backend result`);return{kind:`alertStatus`,action:`get`,alert:e.alert}}function Cn(e){if(e.kind!==`alertWait`)throw new n(`COMMAND_FAILED`,`system.alert wait returned an invalid backend result`);return{kind:`alertWait`,action:`wait`,alert:e.alert,...e.waitedMs===void 0?{}:{waitedMs:e.waitedMs},...e.timedOut===void 0?{}:{timedOut:e.timedOut},...g(e.alert?`Alert visible`:`Alert wait timed out`)}}function wn(e,t){if(t.kind!==`alertHandled`)throw new n(`COMMAND_FAILED`,`system.alert ${e} returned an invalid backend result`);return{kind:`alertHandled`,action:e,handled:t.handled,...t.alert?{alert:t.alert}:{},...t.button?{button:t.button}:{},...g(t.handled?`Alert ${e}ed`:`No alert handled`)}}function Tn(e){return!!(e&&typeof e==`object`)}const En={back:sn,home:cn,orientation:un,keyboard:dn,clipboard:fn,settings:pn,alert:mn,appSwitcher:hn,tvRemote:ln};function Dn(e){return{capture:ee(e),selectors:f(e),interactions:c(e),system:h(En,e),apps:qe(e),admin:h(Ke,e),recording:h(on,e),observability:h(dt,e)}}function On(e){let t=te(e);return{...t,...Dn(t)}}export{On as createAgentDevice,s as createMemorySessionStore,o as localCommandPolicy,a as restrictedCommandPolicy};
|
package/dist/src/runtime2.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{N as e,U as t}from"./sdk-contracts.js";import{i as n}from"./sdk-batch-runner.js";import{A as r}from"./sdk-device.js";import{Yt as i,tn as a}from"./sdk-batch.js";import{n as o}from"./device-shell.js";import{n as s,t as c}from"./android-snapshot-quality.js";import{i as l,n as u}from"./recording-stop-observation.js";import{n as d,r as f,t as p}from"./application-lifecycle-runtime.js";import{A as m,B as h,C as g,D as ee,G as te,H as ne,I as re,J as ie,N as ae,V as oe,d as se,h as ce,n as le,o as ue,s as de,v as fe,w as pe,x as me,z as he}from"./alert-runtime.js";import{n as ge}from"./audio-probe-runtime.js";import{n as _e}from"./perf-runtime.js";import{i as ve}from"./touch-runtime.js";import{a as ye,n as be}from"./durable-resource.js";import{n as xe}from"./async-lifecycle.js";import{i as Se,l as Ce,n as we,r as Te,t as Ee}from"./src7.js";import{n as De}from"./screen-recording-completion.js";import{a as _,c as Oe,n as ke,o as Ae,s as je,t as Me}from"./device-readiness-runtime.js";import{n as Ne}from"./screen-recording-runtime.js";import{readAndroidAppStateWithExecutor as Pe}from"./app-state.js";import{ANDROID_CLIPBOARD_SHELL_COMMAND_UNAVAILABLE_HINT as Fe}from"./clipboard-shell-response.js";import{i as Ie,t as Le}from"./gesture-admission.js";import{t as Re}from"./local-interactor-operation-set.js";import{a as ze,i as v,n as y,r as Be,t as Ve}from"./perf-runtime-operation-builder.js";import{t as He}from"./app-log-runtime.js";import{t as Ue}from"./mp4-duration.js";import{n as b,r as We}from"./managed-device-scope.js";import{a as Ge,i as Ke,n as qe,o as Je}from"./application-lifecycle-interaction.js";import x from"node:path";function Ye(e){return Ae(e)?Object.freeze({available:!0}):e.kind===`emulator`?Object.freeze({available:!1,reason:`unsupported-device-backend`,hint:`audio probe capture requires a macOS host.`}):Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`audio probe capture is supported for Android emulators on macOS hosts.`})}function Xe(e){let{resolveHost:t,device:n,owner:r}=e;return Object.freeze({...Ve({platform:`Android`,expectedProfileKind:`simpleperf`,start:async e=>await t().start(n,r,e),reattach:async e=>await t().reattach(n,e),cleanup:async e=>await t().cleanup(n,e),writeProfileReport:async e=>await t().writeProfileReport(n,e)}),perfFrames:async({appId:e})=>({metric:e?await v(t().sampleFrames(n,e)):y(`Android`,`package`),sampling:{method:`adb-shell-dumpsys-gfxinfo-framestats`,description:`Rendered-frame health from the current adb shell dumpsys gfxinfo <package> framestats window. Dropped frames use Android gfxinfo janky-frame/frame-deadline data when available; this is not video recording FPS.`,unit:`percent`,primaryField:`droppedFramePercent`,window:`since previous Android gfxinfo reset or app process start`,resetsAfterRead:!0,relatedActionsLimit:12}}),perfMemorySample:async({appId:e})=>({metric:e?await v(t().sampleMemory(n,e)):y(`Android`,`package`),sampling:{method:`adb-shell-dumpsys-meminfo`,description:`Memory snapshot from adb shell dumpsys meminfo <package>. Values are reported in kilobytes.`,unit:`kB`,topConsumerLimit:5}}),perfMemorySnapshot:async({appId:e,kind:r,outPath:i,artifactsDir:a})=>{let o=r??`android-hprof`,s=Ze();if(o!==`android-hprof`)return ze(`Android`,o,s,`Use perf memory snapshot --kind android-hprof for Android Java heap artifacts.`);if(!e)throw Be();let c=i??x.join(a,`memory-android-hprof-${Qe()}.hprof`);return{artifact:await t().captureMemorySnapshot(n,e,c),support:s,sampling:{method:`adb-shell-am-dumpheap`,description:`Java heap dump captured with adb shell am dumpheap, pulled to a local artifact path.`,defaultKind:`android-hprof`,artifactOnly:!0}}}})}function Ze(){return{platform:`android`,defaultKind:`android-hprof`,androidHprof:!0,memgraph:!1,heapprofd:!1,heapprofdDecision:`Deferred until Android Perfetto/heapprofd plumbing is available in the perf trace slice.`}}function Qe(){return new Date().toISOString().replaceAll(/[:.]/g,`-`)}function $e(t){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new e(`INVALID_ARGS`,`Invalid Android package name for logs: ${t}`)}const S=Object.freeze({resourceKind:He,version:1,encode:e=>({...e}),decode:e=>e.transport!==`android-logcat-local`&&e.transport!==`android-logcat-transport-composed`||!tt(e.outputPath)||!tt(e.pidPath)?{status:`invalid`,message:`Invalid Android app-log descriptor`}:{status:`decoded`,descriptor:Object.freeze({transport:e.transport,outputPath:e.outputPath,pidPath:e.pidPath})}});function et(e){let t=S.decode(e.descriptor);if(t.status!==`decoded`)throw TypeError(t.message);return be({resourceKind:He,sessionId:e.sessionId,device:{id:e.device.id,family:`android`,kind:e.device.kind,...e.device.target===void 0?{}:{target:e.device.target}},owner:e.owner,fence:e.fence,lifecycle:`open`,descriptor:ye(S,t.descriptor)})}function tt(e){return typeof e==`string`&&e.trim().length>0}function nt(e){return Te(e,{family:`android`,backend:`android`,label:`Android`,codec:S,startUnavailableHint:`The selected Android transport cannot start a background adb logcat stream.`,cleanupFailureMessage:`Android app-log cleanup did not settle every owned resource`,doctor:async({host:e,device:t,signal:n},r)=>await rt(e,t.id,r,n),validateStart:({input:e})=>$e(e.appBundleId),process:async({host:e,device:t,input:n})=>({resolvePid:async r=>await Se(e,it(t.id,n.appBundleId),r),command:e=>({kind:`android-adb`,serial:t.id,args:[`logcat`,`-v`,`time`,`--pid`,e],options:{allowFailure:!0}})}),descriptor:({artifacts:e,transport:t})=>({transport:t.mode===`transport-composed`?`android-logcat-transport-composed`:`android-logcat-local`,...e}),envelope:({input:e,device:t,owner:n,descriptor:r})=>et({sessionId:e.sessionId,device:t,owner:n,fence:e.fence,descriptor:r})})}async function rt(e,t,n,r){let i={};return i.adbAvailable=await Oe(async()=>je(await e.commands.run({executable:`adb`,args:o(`adb`,`shell`,[`echo`,`ok`],[`-s`,t]),allowFailure:!0,timeoutMs:1e3},r)),r),n&&(i.androidPidVisible=await Oe(async()=>!!await Se(e,it(t,n),r),r)),{backend:`android`,checks:i,notes:n?[]:[`No app bundle is tracked in this session. Run open <app> first for app-scoped logs.`]}}function it(e,t){return{executable:`adb`,args:o(`adb`,`shell`,[`pidof`,t],[`-s`,e]),allowFailure:!0,timeoutMs:5e3}}async function at(e,t,n,r){let i=await e.appLogs.readRecent(n.sessionId,n.maxScanLines),a=we(i.text,{...n,path:i.path,exists:i.exists,lineNumberOffset:i.skippedLines,backend:`android`}),o=[],s=await st(e,t,n,r);if(s&&n.appBundleId){$e(n.appBundleId);let c=await lt(e,t,n.appBundleId,r);if(c){let e=we(c.text,{...n,path:`${i.path} (adb logcat recovery)`,exists:!0,backend:`android`});e.dump.entries.length>0&&(a=Ee(e,a,n.maxEntries),o.push(s.reason===`stale-active`?`Session app log stream was still bound to prior Android PID ${s.trackedPid}. Recovered recent Android HTTP entries from adb logcat for PID set ${c.pids.join(`, `)}.`:`Session app log stream was inactive. Recovered recent Android HTTP entries from adb logcat for PID set ${c.pids.join(`, `)}.`))}}return n.appLogSnapshot?n.appLogSnapshot.state!==`active`&&o.length===0&&o.push(`Session app log stream is inactive. Run logs clear --restart, reproduce the request window again, then rerun network dump.`):o.push(`Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests.`),a.dump.entries.length===0&&o.push(`No HTTP(s) entries were found in recent session app logs.`),Object.freeze({source:`app-log`,backend:`android`,dump:a.dump,notes:Object.freeze(o)})}async function ot(e,t,n){n.throwIfAborted();try{let r=await e.commands.run(t,n);return n.throwIfAborted(),r}catch{n.throwIfAborted();return}}async function st(e,t,n,r){if(!n.appBundleId||n.appLogSnapshot?.state===void 0)return;if(n.appLogSnapshot.state!==`active`)return{reason:`inactive`};let i=ct(await e.appLogs.readProcessMarker(n.sessionId));if(!i)return;let a=await ut(e,t.id,n.appBundleId,r);if(!(!a||a===i))return{reason:`stale-active`,trackedPid:i}}function ct(e){if(e.status===`decoded`)return/(?:^|\s)--pid\s+(\d+)(?:\s|$)/.exec(e.marker.command)?.[1]}async function lt(e,t,n,r){let i=await ut(e,t.id,n,r),a=await ot(e,{executable:`adb`,args:[`-s`,t.id,`logcat`,`-d`,`-v`,`time`,`-t`,`4000`],allowFailure:!0,timeoutMs:3e3},r);if(!a||a.exitCode!==0||!a.stdout.trim())return;let o=dt(a.stdout,n,i);if(o.length===0)return;let s=new Set(o),c=a.stdout.split(`
|
|
2
2
|
`).filter(e=>{if(!e.trim())return!1;if(e.includes(n))return!0;let t=/\(\s*(\d+)\)\s*:/.exec(e)?.[1];return!!(t&&s.has(t))}).join(`
|
|
3
3
|
`);return c.trim()?{text:c,pids:o}:void 0}async function ut(e,t,n,r){let i=await ot(e,{executable:`adb`,args:o(`adb`,`shell`,[`pidof`,n],[`-s`,t]),allowFailure:!0},r);if(!i)return;let a=i.stdout.trim().split(/\s+/)[0];return a&&/^\d+$/.test(a)?a:void 0}function dt(e,t,n){let r=new Set(n?[n]:[]),i=t.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`),a=[RegExp(`\\bStart proc\\s+(\\d+):${i}(?:\\b|/)`,`i`),RegExp(`\\b(\\d+):${i}(?:\\b|/)`,`i`),RegExp(`${i}.*?\\bpid\\s*[=:]?\\s*(\\d+)\\b`,`i`),RegExp(`\\bpid\\s*[=:]?\\s*(\\d+)\\b.*${i}`,`i`)];for(let n of e.split(`
|
|
4
|
-
`))if(n.includes(t))for(let e of a){let t=e.exec(n)?.[1];t&&/^\d+$/.test(t)&&r.add(t)}return Object.freeze([...r])}function S(e,t){if(t===1)return e;let n=b.parse(e);return b.join(n.dir,`${n.name}.part-${String(t).padStart(3,`0`)}${n.ext||`.mp4`}`)}const ft=/^(?:\/sdcard|\/data\/local\/tmp)\/agent-device-recording-\d{1,20}\.mp4$/,pt=/^(?:\/sdcard|\/data\/local\/tmp)\/agent-device-recording-active\.json$/;function mt(e){return _t(e)&&vt(e)&&yt(e)}function ht(e){if(!w(e))return!1;let t=e;return bt(t)&&xt(t)&&St(t)&&Ct(t)&&(t.completion===void 0||At(t))}function gt(e,t){return jt(e,t)&&C(e,t.outputPath,t.clientOutputPath)}function _t(e){return e.backend===`adb-screenrecord`&&typeof e.manifestPath==`string`&&pt.test(e.manifestPath)&&typeof e.outputPath==`string`}function vt(e){return Nt(e.clientOutputPath)&&v(e)}function yt(e){return Mt(e.transportMode)}function bt(e){return e.version===1&&e.resourceKind===`screen-recording`&&typeof e.fenceToken==`string`&&Number.isInteger(e.fenceGeneration)&&typeof e.sessionId==`string`&&typeof e.deviceId==`string`&&Number.isFinite(e.startedAt)}function xt(e){return typeof e.outputPath==`string`&&Nt(e.clientOutputPath)&&v(e)}function St(e){return Mt(e.transportMode)&&(e.pendingRemotePath===void 0||Pt(e.pendingRemotePath))}function Ct(e){return Array.isArray(e.chunks)&&e.chunks.every(wt)&&(e.chunks.length>0||e.pendingRemotePath!==void 0)&&(e.completion===void 0||Tt(e.completion))}function wt(e,t){if(!w(e))return!1;let n=e;return n.index===t+1&&Pt(n.remotePath)&&Ft(n.remotePid)&&Ft(n.remoteStartTime)}function Tt(e){if(!w(e))return!1;let t=e;return Dt(t)&&Ot(t)&&Et(t)&&(t.chunks===void 0||t.chunks.every(kt))}function Et(e){return(e.stopObservation===void 0||u(e.stopObservation))&&(e.nativePathDisposition===void 0||l(e.nativePathDisposition))}function Dt(e){return typeof e.backend==`string`&&typeof e.outPath==`string`&&(e.clientOutPath===void 0||typeof e.clientOutPath==`string`)&&Number.isFinite(e.startedAt)&&Number.isFinite(e.completedAt)&&(e.capturedDurationMs===void 0||Number.isFinite(e.capturedDurationMs))}function Ot(e){return v(e)}function kt(e,t){return e.index===t+1&&typeof e.path==`string`&&(e.clientOutPath===void 0||typeof e.clientOutPath==`string`)}function At(e){let t=e.completion;return t!==void 0&&jt(t,e)&&t.startedAt===e.startedAt&&C(t,e.outputPath,e.clientOutputPath,e.chunks.length)}function jt(e,t){return e.backend===`adb screenrecord`&&e.outPath===t.outputPath&&e.clientOutPath===t.clientOutputPath&&e.scope===t.scope&&e.showTouches===t.showTouches&&e.recordOnlySession===t.recordOnlySession&&It(e.activeSessionApp,t.activeSessionApp)}function C(e,t,n,r=e.chunks===void 0?1:e.chunks.length){return r===1?e.chunks===void 0:e.chunks?.length===r&&e.chunks.every((e,r)=>e.path===S(t,r+1)&&e.clientOutPath===(n===void 0?void 0:S(n,r+1)))}function w(e){return typeof e==`object`&&!!e}function Mt(e){return e===`local`||e===`transport-composed`}function Nt(e){return e===void 0||typeof e==`string`}function Pt(e){return typeof e==`string`&&ft.test(e)}function Ft(e){return typeof e==`string`&&/^\d+$/.test(e)}function It(e,t){return JSON.stringify(e)===JSON.stringify(t)}const T=Object.freeze({resourceKind:je,version:1,encode:e=>({...e}),decode:e=>mt(e)?{status:`decoded`,descriptor:Object.freeze({backend:`adb-screenrecord`,manifestPath:e.manifestPath,outputPath:e.outputPath,...e.clientOutputPath===void 0?{}:{clientOutputPath:e.clientOutputPath},scope:e.scope,showTouches:e.showTouches,recordOnlySession:e.recordOnlySession,transportMode:e.transportMode,...e.activeSessionApp===void 0?{}:{activeSessionApp:e.activeSessionApp},...e.exportQuality===void 0?{}:{exportQuality:e.exportQuality}})}:{status:`invalid`,message:`Invalid Android screen-recording descriptor`}});function E(e,t,n,r,i,a=`local`){return Object.freeze({version:1,resourceKind:`screen-recording`,fenceToken:t.fence.token,fenceGeneration:t.fence.generation,sessionId:t.sessionId,deviceId:e.id,startedAt:n,outputPath:t.outputPath,...t.clientOutputPath===void 0?{}:{clientOutputPath:t.clientOutputPath},scope:t.scope,showTouches:t.showTouches,recordOnlySession:t.recordOnlySession,...t.activeSessionApp===void 0?{}:{activeSessionApp:t.activeSessionApp},...t.exportQuality===void 0?{}:{exportQuality:t.exportQuality},chunks:r,...i===void 0?{}:{pendingRemotePath:i},transportMode:a})}function Lt(e,t){return Object.freeze({...e,completion:t})}function D(e){try{let t=e&&JSON.parse(e);return ht(t)?t:void 0}catch{return}}function Rt(e,t,n){return e.deviceId===t.id&&e.deviceId===n.device.id&&e.fenceToken===n.fence.token&&e.fenceGeneration===n.fence.generation&&e.sessionId===n.sessionId}function zt(e,t){return e.outputPath===t.outputPath&&e.clientOutputPath===t.clientOutputPath&&e.scope===t.scope&&e.showTouches===t.showTouches&&e.recordOnlySession===t.recordOnlySession&&JSON.stringify(e.activeSessionApp)===JSON.stringify(t.activeSessionApp)&&e.exportQuality===t.exportQuality&&e.transportMode===t.transportMode&&(e.completion===void 0||gt(e.completion,t))}function O(e){switch(e){case`missing`:case`ownership-lost`:case`foreign-writer`:return!0;case`owned-alive`:case`uncertain`:return!1}}function Bt(e){switch(e){case`missing`:case`ownership-lost`:return!0;case`foreign-writer`:case`owned-alive`:case`uncertain`:return!1}}const Vt=1e4,Ht=1e3;var k=class extends Error{constructor(e){super(`Android screenrecord launch rollback could not be confirmed`,{cause:e})}};function A(e,t=Date.now()){return[...new Set(e?[e,`/sdcard`,`/data/local/tmp`]:[`/sdcard`,`/data/local/tmp`])].map(e=>`${e}/agent-device-recording-${t}.mp4`)}async function Ut(e,t,n,r){let i;try{if(i=(await e.start({remotePath:t,quality:n.exportQuality??`medium`},r)).process,!/^\d+$/.test(i.pid)||!/^\d+$/.test(i.startTime)||i.remotePath!==t)throw Error(`Android screenrecord returned an invalid process identity`);if(!await Yt(e,t,i,r))throw Error(`Android screenrecord did not begin producing frames`);return{index:1,remotePath:t,remotePid:i.pid,remoteStartTime:i.startTime}}catch(t){throw i&&Wt(i)&&!await Xt(e,i)?new k(t):r?.aborted?r.reason:t}}function Wt(e){return/^\d+$/.test(e.pid)&&/^\d+$/.test(e.startTime)&&e.remotePath.length>0}async function j(e,t){let n=t.at(-1),r=!1,i;for(let a of[...t].reverse())try{let t=await N(e,a);a===n&&(r=t)}catch(e){i??=e}if(i)throw i;return r}async function Gt(e,t){for(let n of t){let t;for(let r=0;r<3;r+=1){let i=await e.size(n.remotePath);if(typeof i==`number`&&i>0&&i===t)break;if(t=typeof i==`number`&&i>0?i:void 0,r===2)throw Error(`Android recording artifact is not stable: ${n.remotePath}`);await new Promise(e=>setTimeout(e,250))}}}async function Kt(e,t,n){for(let[r,i]of t.entries())await Zt(e,i.remotePath,S(n,r+1))}async function M(e,t){let n;for(let r of t)try{if(!await e.remove(r.remotePath))throw Error(`failed to remove Android recording artifact: ${r.remotePath}`)}catch(e){n??=e}if(n)throw n}async function qt(e,t){for(let n of t)if(await e.exists(n.remotePath)!==!1)return`retirable`;return`retired`}async function Jt(e,t){try{await j(e,t)}finally{await M(e,t)}}async function Yt(e,t,n,r){for(let i=0;i<3;i+=1){if(r?.throwIfAborted(),await e.exists(t,r)===!0)return!0;if(await e.inspect(n,r)!==`owned-alive`)return!1;i<2&&await new Promise(e=>setTimeout(e,250))}return!0}async function Xt(e,t){try{let n=await e.stop(t,{force:!0});return(n===`stopped`||n===`already-missing`)&&await e.remove(t.remotePath)}catch{return!1}}async function N(e,t){if(!t)return!1;let n={pid:t.remotePid,remotePath:t.remotePath,startTime:t.remoteStartTime},r=await e.stop(n);if(r===`already-missing`)return!0;if(r===`ownership-lost`)throw Error(`Android screenrecord ownership could not be confirmed for pid ${t.remotePid}`);if(await Qt(e,n))return!1;let i=await e.stop(n,{force:!0});if(i===`stopped`||i===`already-missing`)return!1;throw Error(`failed to stop Android screenrecord pid ${t.remotePid}`)}async function Zt(e,t,n){for(let r=0;r<3;r+=1){let i=await e.pullPlayable({remotePath:t,outputPath:n});if(i.exitCode===0&&i.playable)return;r+1<3&&await $t(1e3)}throw Error(`failed to retrieve playable Android recording`)}async function Qt(e,t){for(let n=0;n<=Vt;n+=Ht){let r=await e.inspect(t);if(r===`missing`)return!0;if(O(r))throw Error(`Android screenrecord ownership could not be confirmed for pid ${t.pid}`);n<Vt&&await $t(Ht)}return!1}function $t(e){return new Promise(t=>setTimeout(t,e))}async function P(e,t,n,r){await e.writeManifest({manifestPath:t,contents:JSON.stringify(n)},r)}async function F(e,t){if(!await e.removeManifest(t))throw Error(`failed to remove Android recording manifest: ${t}`)}async function en(e,t){let n=(await tn(e)).flatMap(n=>nn(n,t,e.mode));for(let t of n)await an(e,t.evidence,t.manifestPath)}async function tn(e){return await Promise.all(A(void 0).map(async t=>{let n=e.manifestPathFor(t);return{manifestPath:n,read:await e.readManifest(n)}}))}function nn(e,t,n){if(e.read.status===`missing`)return[];if(e.read.status!==`read`)throw cn(e.manifestPath,e.read.message);let r=D(e.read.contents);if(r===void 0)throw ln(e.manifestPath);if(r.transportMode!==n)throw un(e.manifestPath,r,n);if(!rn(r,t))throw dn(e.manifestPath,r,t);return[{manifestPath:e.manifestPath,evidence:r}]}function rn(e,t){return e.completion!==void 0||e.deviceId!==t.id}async function an(e,t,n){if(await on(e,t),await M(e,t.chunks),await sn(e,t),await F(e,n),(await e.readManifest(n)).status!==`missing`)throw mn(n)}async function on(e,t){for(let n of t.chunks){let t=await e.inspect({pid:n.remotePid,remotePath:n.remotePath,startTime:n.remoteStartTime});if(!Bt(t))throw t===`uncertain`?hn(n.remotePath):fn(n.remotePath,t===`owned-alive`?`named-recorder`:`other-recorder`)}let n=t.pendingRemotePath;if(n===void 0)return;let r=await e.probeRunningWriters(n);if(r.writers.length>0)throw fn(n,`other-recorder`);if(!r.conclusive)throw hn(n)}async function sn(e,t){let n=t.pendingRemotePath;if(n!==void 0&&!await e.remove(n))throw pn(n)}function cn(e,n){return new t(`COMMAND_FAILED`,`Android screenrecord native recovery evidence is unavailable: ${e}`,{reason:`native_recovery_evidence_unavailable`,manifestPath:e,hint:`Confirm the device is online and its storage readable, then run record start again.`},Error(n))}function ln(e){return new t(`COMMAND_FAILED`,`Android screenrecord native recovery evidence is unreadable: ${e}`,{reason:`native_recovery_evidence_unreadable`,manifestPath:e,hint:I(e)})}function un(e,n,r){return new t(`COMMAND_FAILED`,`Android screenrecord native recovery evidence was written by the ${n.transportMode} transport, not this ${r} one: ${e}`,{reason:`native_recovery_evidence_transport_mismatch`,manifestPath:e,evidenceTransportMode:n.transportMode,hint:I(e)})}function dn(e,n,r){return new t(`DEVICE_IN_USE`,`Android screenrecord native recovery evidence already exists: ${e} (open recording of session "${n.sessionId}" on ${r.id})`,{reason:`native_recovery_evidence_open`,manifestPath:e,sessionId:n.sessionId,retriable:!1,hint:`Run record stop --session ${n.sessionId} to retire it, or close that session. If it is already closed, ${I(e)}`})}function fn(e,n){let r=n===`named-recorder`;return new t(`DEVICE_IN_USE`,`Android screenrecord recovery evidence is retained: ${r?`its recorder`:`another recorder`} is writing ${e}`,{reason:`native_recording_artifact_claimed`,remotePath:e,writer:n,...r?{retriable:!1}:{},hint:r?`Run record stop for the session that owns that recording before starting another.`:`Android ends any recorder after 180 seconds. Run record start again once that recorder has stopped.`})}function pn(e){return new t(`COMMAND_FAILED`,`Android screenrecord recovery evidence could not remove ${e}`,{reason:`native_recording_artifact_removal_failed`,remotePath:e,hint:`Confirm the device is online and run record start again.`})}function mn(e){return new t(`COMMAND_FAILED`,`Android screenrecord recovery evidence removal could not be confirmed: ${e}`,{reason:`native_recovery_evidence_retirement_unconfirmed`,manifestPath:e,hint:`Run record start again; the marker is retired from the beginning.`})}function hn(e){return new t(`COMMAND_FAILED`,`Android screenrecord recovery evidence cannot be safely retired: ${e}`,{reason:`native_recording_recorder_unproven`,remotePath:e,hint:`Confirm the device is online and run record start again.`})}function I(e){return`no recording session can retire this marker; remove it on the device with \`adb shell rm -f ${e}\`.`}async function gn(e){let{transport:t,device:n,input:r,startedAt:i,signal:a,prepareOutput:o}=e;await en(t,n),await o();let s;for(let e of A(void 0)){let o=t.manifestPathFor(e);await P(t,o,E(n,r,i,[],e,t.mode),a);let c,l;try{l=Date.now(),c=await Ut(t,e,r,a)}catch(e){if(a.aborted)throw await _n(t,o,e),a.reason;await bn(t,o,e),s=e;continue}try{await P(t,o,E(n,r,i,[c],void 0,t.mode),a)}catch(e){throw await vn(t,o,c),e}return{chunk:c,manifestPath:o,startedAtMs:l}}throw s??Error(`Android screenrecord did not begin producing frames`)}async function _n(e,t,n){n instanceof k||await F(e,t).catch(()=>{})}async function vn(e,t,n){try{await Jt(e,[n])}catch{return}await F(e,t).catch(()=>{})}async function yn(e){let{transport:t,device:n,input:r,startedAt:i,chunks:a,manifestPath:o,preferredDir:s}=e,c;for(let e of A(s)){await P(t,o,E(n,r,i,a,e,t.mode));try{return await Ut(t,e,r)}catch(e){if(e instanceof k)throw e;try{await P(t,o,E(n,r,i,a,void 0,t.mode))}catch{throw new k(e)}c=e}}throw c??Error(`failed to start next Android recording chunk`)}async function bn(e,t,n){if(n instanceof k)throw n;try{await F(e,t)}catch{throw new k(n)}}function xn(e,t){return Object.freeze({backend:`adb screenrecord`,outPath:e.outputPath,...e.clientOutputPath?{clientOutPath:e.clientOutputPath}:{},startedAt:t,scope:e.scope,showTouches:e.showTouches,recordOnlySession:e.recordOnlySession,...e.activeSessionApp?{activeSessionApp:e.activeSessionApp}:{},...e.exportQuality?{exportQuality:e.exportQuality}:{},gestureEvents:[]})}function Sn(e){let t=Cn(e.chunkPaths);if(t===void 0)return{};let n=e.stoppedAtMs-e.startedAtMs;return n-t<2e3?{capturedDurationMs:t}:{capturedDurationMs:t,idleTailWarning:`Android screenrecord encodes a frame only when the screen changes, so this video ends at the last frame it encoded: it covers ${wn(t)}s of the ${wn(n)}s recording window.`}}function Cn(e){let t=0;for(let n of e){let e=Ue(n);if(e===void 0)return;t+=e}return t}function wn(e){return(e/1e3).toFixed(1)}async function Tn(e){let{host:t,transport:n,evidence:r,recording:i,startedAtMs:a,progress:o}=e,s=e.reachedLimit===!0;return await An(e,await Ae({snapshot:i,progress:o,steps:{stop:async()=>(s=await j(n,r.chunks)||s,await Gt(n,r.chunks),{observation:{recorder:`confirmed`},...s?{warning:`Android adb screenrecord stopped before record stop, likely after reaching the 180s platform limit. The MP4 may be truncated; final interactions after the limit are not in the video.`}:{}}),collect:e=>Kt(n,r.chunks,e),finalize:({collectedPath:e,exportPath:n,stoppedAtMs:o})=>En({host:t,evidence:r,recording:i,startedAtMs:a,stoppedAtMs:o,collectedPath:e,exportPath:n}),discard:e=>On(t,e,r.chunks.length)}}))}async function En(e){let{host:t,evidence:n,recording:r,collectedPath:i,exportPath:a}=e,o=jn({collectedPath:i,exportPath:a,exportClientPath:r.clientOutPath,count:n.chunks.length}),s=o.length>1,c;try{await Dn(t,o),c=await t.screenRecording.finalize.complete({outputPath:a,showTouches:!s&&r.showTouches,gestureEvents:r.gestureEvents,exportQuality:r.exportQuality??`medium`,targetLabel:`Android recording`})}catch(e){for(let{served:e}of o)await t.screenRecording.outputs.remove(e.path);throw e}let l=Sn({chunkPaths:o.map(({collected:e})=>e.path),startedAtMs:e.startedAtMs,stoppedAtMs:e.stoppedAtMs});return kn({finalization:c,captured:l,recording:r,chunked:s,files:o})}async function Dn(e,t){for(let{collected:n,served:r}of t)await e.screenRecording.outputs.copy({from:n.path,to:r.path})}async function On(e,t,n){for(let r=1;r<=n;r+=1)await e.screenRecording.outputs.remove(S(t,r))}function kn(e){let{finalization:t,captured:n,recording:r,chunked:i,files:a}=e,o=[t.warning,...i?[`Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks.`]:[],n.idleTailWarning].filter(e=>e!==void 0&&e.length>0);return{...t.telemetryPath===void 0?{}:{telemetryPath:t.telemetryPath},...o.length===0?{}:{warning:o.join(` `)},...i&&r.showTouches&&r.gestureEvents.length>0?{overlayWarning:`touch overlay burn-in is skipped for chunked Android recordings; returning raw chunks plus gesture telemetry`}:{},...n.capturedDurationMs===void 0?{}:{capturedDurationMs:n.capturedDurationMs},...i?{chunks:a.map(e=>e.served)}:{},nativePathDisposition:`retirable`}}async function An(e,t){let{transport:n,evidence:r,manifestPath:i}=e;return await P(n,i,Lt(r,t.result)),await M(n,r.chunks),{status:`completed`,result:{...t.result,nativePathDisposition:await qt(n,r.chunks)}}}function jn(e){return Object.freeze(Array.from({length:e.count},(t,n)=>({collected:Object.freeze({index:n+1,path:S(e.collectedPath,n+1)}),served:Object.freeze({index:n+1,path:S(e.exportPath,n+1),...e.exportClientPath===void 0?{}:{clientOutPath:S(e.exportClientPath,n+1)}})})))}async function Mn(e,t,n){try{let r=t.pendingRemotePath;if(await j(e,[...t.chunks,...await Nn(e,t)]),await M(e,t.chunks),r!==void 0&&!await e.remove(r))throw Error(`failed to remove Android recording artifact: ${r}`);return await F(e,n),{status:`cleaned`}}catch(e){return Pn(e)}}async function Nn(e,t){let n=t.pendingRemotePath;if(n===void 0)return[];let r=await e.probeRunningWriters(n);if(!r.conclusive)throw Error(`cannot list every recorder writing Android artifact: ${n}`);return r.writers.map((e,r)=>({index:t.chunks.length+1+r,remotePath:n,remotePid:e.pid,remoteStartTime:e.startTime}))}function Pn(e){return{status:`cleanup-pending`,reason:`transport-failed`,message:e instanceof Error?e.message:String(e)}}async function Fn(e){let{transport:t,device:n,envelope:r,descriptor:i}=e;if(i.transportMode!==t.mode)return{status:`transport-unavailable`};let a=await t.readManifest(i.manifestPath);if(a.status===`unavailable`)return{status:`transport-unavailable`};let o=a.status===`read`?D(a.contents):void 0;return o&&Rt(o,n,r)&&zt(o,i)?{status:`matched`,evidence:o}:{status:`ownership-lost`}}async function In(e){let t=await e.transport.readManifest(e.manifestPath);if(t.status!==`read`)return;let n=D(t.contents);return n&&Ln(n,e)?n:void 0}function Ln(e,t){return e.deviceId===t.deviceId&&e.sessionId===t.sessionId&&e.fenceToken===t.fence.token&&e.fenceGeneration===t.fence.generation}async function Rn(e){let{host:t,transport:n,device:r,input:i}=e,a=T.decode(i.envelope.descriptor.body);if(a.status!==`decoded`)return R(`descriptor-invalid`);let o=await Fn({transport:n,device:r,envelope:i.envelope,descriptor:a.descriptor});return o.status===`matched`?await zn({host:t,transport:n,device:r,input:i,descriptor:a.descriptor,evidence:o.evidence}):R(o.status===`transport-unavailable`?`transport-not-reattachable`:`ownership-fence-lost`)}async function L(e){let t=T.decode(e.input.envelope.descriptor.body);if(t.status!==`decoded`)return{status:`cleanup-pending`,reason:`manual-recovery-required`};let n=await Fn({transport:e.transport,device:e.device,envelope:e.input.envelope,descriptor:t.descriptor});return n.status===`matched`?await Mn(e.transport,n.evidence,t.descriptor.manifestPath):n.status===`transport-unavailable`?{status:`cleanup-pending`,reason:`owner-unavailable`}:{status:`cleanup-pending`,reason:`ownership-fence-lost`}}async function zn(e){let{host:t,transport:n,device:r,input:i,descriptor:a,evidence:o}=e;if(o.completion!==void 0){let e=await Bn(n,o);return e.status===`terminal`?{status:`completed`,result:{...o.completion,nativePathDisposition:e.nativePathDisposition}}:R(`ownership-fence-lost`,`Android recording completed evidence still names a live or unverifiable recorder.`)}if(o.pendingRemotePath!==void 0)return R(`transport-not-reattachable`,`Android recording launch was interrupted before its process identity was committed.`);let s=o.chunks.at(-1);if(!s)return{status:`missing`};let c=await n.inspect({pid:s.remotePid,remotePath:s.remotePath,startTime:s.remoteStartTime});if(c!==`owned-alive`&&await n.exists(s.remotePath)===!1)return R(`transport-not-reattachable`,`Android recording process ended before its artifact could be recovered.`);let l=Vn(i.envelope.sessionId,i.envelope.fence,a),u=!1;return{status:`active`,handle:Ee(xn(l,o.startedAt),{finish:async(e,r)=>{let i=await Tn({host:t,transport:n,evidence:o,manifestPath:a.manifestPath,recording:e,startedAtMs:o.startedAt,reachedLimit:O(c),progress:r});return u=!0,i},forceCleanup:async()=>u?{status:`cleaned`}:await L({transport:n,device:r,input:i})})}}async function Bn(e,t){try{for(let n of t.chunks)if(!O(await e.inspect({pid:n.remotePid,remotePath:n.remotePath,startTime:n.remoteStartTime})))return{status:`retained`};return{status:`terminal`,nativePathDisposition:await qt(e,t.chunks)}}catch{return{status:`retained`}}}function Vn(e,t,n){return{sessionId:e,outputPath:n.outputPath,...n.clientOutputPath===void 0?{}:{clientOutputPath:n.clientOutputPath},scope:n.scope,showTouches:n.showTouches,hideTouchesRequested:!1,recordOnlySession:n.recordOnlySession,...n.activeSessionApp===void 0?{}:{activeSessionApp:n.activeSessionApp},...n.exportQuality===void 0?{}:{exportQuality:n.exportQuality},fence:t}}function R(e,t){return{status:`unreattachable`,reason:e,...t===void 0?{}:{message:t}}}async function Hn(e){let{host:t,device:n,owner:r,signal:i}=e,a=await t.screenRecording.android.resolve(n);return Object.freeze({screenRecordingStart:async e=>await Un({host:t,transport:a,device:n,owner:r,input:e,signal:i}),screenRecordingReattach:async e=>await Rn({host:t,transport:a,device:n,input:e}),screenRecordingCleanup:async e=>await L({transport:a,device:n,input:e})})}async function Un(e){let{host:t,transport:n,device:i,owner:a,input:o,signal:s}=e;s.throwIfAborted();let c=Date.now(),l=await gn({transport:n,device:i,input:o,startedAt:c,signal:s,prepareOutput:async()=>await t.screenRecording.outputs.prepare(o.outputPath)}),u=l.manifestPath,d=[l.chunk],f,p,m,h=!1,g=()=>{f=setTimeout(()=>{p=ee().catch(e=>{m=e})},17e4),f.unref?.()},ee=async()=>{let e=d.at(-1);if(!e)throw Error(`Android recording has no active chunk`);let t=!1,r;try{r=await yn({transport:n,device:i,input:o,startedAt:c,chunks:d,manifestPath:u,preferredDir:b.posix.dirname(e.remotePath)})}catch(a){await N(n,e),t=!0;try{r=await yn({transport:n,device:i,input:o,startedAt:c,chunks:d,manifestPath:u,preferredDir:b.posix.dirname(e.remotePath)})}catch(e){throw e instanceof Error?e:a}}let a=[...d,{...r,index:d.length+1}];try{await P(n,u,E(i,o,c,a,void 0,n.mode))}catch(a){if(await Jt(n,[r]).catch(()=>{}),t)await P(n,u,E(i,o,c,d,r.remotePath,n.mode)).catch(()=>{});else try{await P(n,u,E(i,o,c,d,void 0,n.mode))}catch{await N(n,e).catch(()=>{}),await P(n,u,E(i,o,c,d,r.remotePath,n.mode)).catch(()=>{})}throw a}d=a,t||await N(n,e),g()};g();let _=Ee(xn(o,c),{finish:async(e,r)=>{if(f&&clearTimeout(f),await p,m)throw m;let a=await Tn({host:t,transport:n,evidence:E(i,o,c,d,void 0,n.mode),manifestPath:u,recording:e,startedAtMs:l.startedAtMs,progress:r});return h=!0,a},forceCleanup:async()=>{if(f&&clearTimeout(f),h)return{status:`cleaned`};try{await p}catch(e){m=e}let e=await In({transport:n,deviceId:i.id,sessionId:o.sessionId,fence:o.fence,manifestPath:u});return e?await Mn(n,e,u):{status:`cleanup-pending`,reason:`ownership-fence-lost`}}});return Object.freeze({pendingHandle:new be(_),envelope:ye({resourceKind:je,sessionId:o.sessionId,device:r(i),owner:a,fence:o.fence,lifecycle:`open`,descriptor:ve(T,{backend:`adb-screenrecord`,manifestPath:u,outputPath:o.outputPath,...o.clientOutputPath===void 0?{}:{clientOutputPath:o.clientOutputPath},scope:o.scope,showTouches:o.showTouches,recordOnlySession:o.recordOnlySession,...o.activeSessionApp===void 0?{}:{activeSessionApp:o.activeSessionApp},...o.exportQuality===void 0?{}:{exportQuality:o.exportQuality},transportMode:n.mode})})})}const z=12e4,Wn=1e3;async function B(e,t,n,r){return r.throwIfAborted(),await We(t)?{...t,booted:!0}:t.kind===`emulator`&&(t.booted!==!0||!V(t))?await Gn(e,t,n,r):(t.booted!==!0&&await Yn(e,t.id,z,r),{...t,booted:!0})}async function Gn(e,t,n,r){await Kn(e);let i=Xn(n),a=qn(await e.deviceReadiness.androidEmulator.discover(i,r),t.name,n.serial),o=V(a)?a:void 0,s=o?void 0:e.deviceReadiness.androidEmulator.launch(a.name,n.headless);try{let t=o??await Jn(e,a.name,i,n.serial,r);return await Yn(e,t.id,z,r),{...(await e.deviceReadiness.androidEmulator.discover(i,r)).find(e=>e.id===t.id)??t,name:a.name,booted:!0}}catch(t){throw s!==void 0&&r.aborted&&await e.deviceReadiness.androidEmulator.terminate(s),r.throwIfAborted(),t}}async function Kn(e){if(await e.toolchains.prepare(`android`),!await e.commands.which(`adb`))throw new t(`TOOL_MISSING`,`adb not found in PATH`);if(!await e.commands.which(`emulator`))throw new t(`TOOL_MISSING`,`emulator not found in PATH`)}function qn(e,n,r){let i=Zn(e,n,r);if(i)return i;throw new t(`DEVICE_NOT_FOUND`,`No Android emulator AVD named ${n}`,{requestedAvdName:n,availableAvds:e.map(e=>e.name),hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."})}async function Jn(e,n,r,i,a){let o=e.clock.now()+z;for(;e.clock.now()<o;){let t=Zn(await e.deviceReadiness.androidEmulator.discover(r,a),n,i);if(t&&V(t))return t;await e.clock.sleep(Wn,a)}throw new t(`COMMAND_FAILED`,`Android emulator did not appear in time`,{avdName:n,serial:i,timeoutMs:z})}async function Yn(e,n,r,i){let a=e.clock.now()+r;for(;e.clock.now()<a;){if((await e.commands.run({executable:`adb`,args:o(`adb`,`shell`,[`getprop`,`sys.boot_completed`],[`-s`,n]),allowFailure:!0,timeoutMs:Math.min(1e4,Math.max(1e3,a-e.clock.now()))},i)).stdout.trim()===`1`)return;await e.clock.sleep(Wn,i)}throw new t(`COMMAND_FAILED`,`Android device failed to finish booting`,{serial:n,timeoutMs:r,reason:`ANDROID_BOOT_TIMEOUT`})}function Xn(e){return{platform:`android`,kind:`emulator`,...e.serial?{serial:e.serial}:{},...e.androidSerialAllowlist?{androidSerialAllowlist:[...e.androidSerialAllowlist]}:{}}}function Zn(e,t,n){let r=Qn(t);return e.find(e=>e.platform===`android`&&e.kind===`emulator`&&Qn(e.name)===r&&(!n||!V(e)||e.id===n))}function V(e){return e.id.startsWith(`emulator-`)}function Qn(e){return e.toLowerCase().replaceAll(`_`,` `).replaceAll(/\s+/g,` `).trim()}async function $n(e,t,n){try{let r=await e.snapshot({appBundleId:t,signal:n,transient:{settleBy:Date.now()+6e3}});return{observation:`androidSnapshot`in r&&r.androidSnapshot?.systemSurfaceOnly===!0?`unobservable`:`observable`}}catch(e){return n.throwIfAborted(),c(e)?{observation:`unobservable`}:{observation:`probe-failed`,failure:er(e)}}}function er(t){let n=e(t),r=s(n)??n.details?.reason;return typeof r==`string`?{code:n.code,reason:r}:{code:n.code}}function tr(e){let{host:t,device:n,signal:r}=e,i=qe({device:n,signal:r,resolveInteractor:t.localInteractors.resolve});return Object.freeze({resolveOpenTarget:async e=>await t.androidApplications.resolveOpenTarget(n,e),prepareApplicationOpen:async e=>{await B(t,n,{headless:!1},r)},openApplication:async e=>await nr(t,i,e),applyRuntimeHints:async e=>await t.androidApplications.applyRuntimeHints(n,e),clearRuntimeHints:async e=>await t.androidApplications.clearRuntimeHints(n,e),closeApplication:async e=>{e.ensureReady&&await B(t,n,{headless:!1},r),await Ge({device:n,interactor:await i.resolveInteractor(e.execution,e.appBundleId),positionals:e.positionals})},finalizeApplicationClose:async e=>{await t.androidApplications.restoreTestIme(n,{stateDir:e.stateDir});let i=e.shutdownTarget&&n.kind===`emulator`?await t.deviceShutdown.android.shutdownTarget(n,r):void 0;return i===void 0?{}:{shutdown:i}},prepareAppleRunner:ir,configureProviderPortReverse:ir})}async function nr(e,n,r){let i={};if(r.relaunch&&r.target){let e=Date.now();await Ge({device:n.device,interactor:await n.resolveInteractor(r.execution,r.appBundleId),positionals:[r.appBundleId??r.target]}),i.relaunchCloseDurationMs=H(e)}if(f(r.runtimeHints)){if(!r.applyRuntimeHints)throw new t(`COMMAND_FAILED`,`Runtime hint operation was not admitted for this open.`,{reason:`runtime-hints-operation-missing`});let e=Date.now();await r.applyRuntimeHints({appId:r.appBundleId,values:r.runtimeHints}),i.runtimeHintsDurationMs=H(e)}let a=Date.now();await Je({device:n.device,interactor:await n.resolveInteractor(r.execution,r.appBundleId),positionals:r.positionals,appBundleId:r.appBundleId,execution:r.execution}),i.openDispatchDurationMs=H(a),r.enableTestIme&&await e.androidApplications.activateTestIme(n.device,{stateDir:r.stateDir});let o=Ke(r);if(o){let e=Date.now();await Je({device:n.device,interactor:await n.resolveInteractor({...r.execution,clearAppState:void 0,launchConsole:void 0,launchArgs:void 0},r.appBundleId),positionals:[o],appBundleId:r.appBundleId,execution:{...r.execution,clearAppState:void 0,launchConsole:void 0,launchArgs:void 0}}),i.launchUrlDurationMs=H(e)}else i.launchUrlDurationMs=0;let s=await e.androidApplications.inferOpenedAppBundleId(n.device,r.target,r.appBundleId);s&&await e.androidApplications.resetFramePerfStats(n.device,s);let c=Date.now();return Object.assign(i,await rr(n,r,s)),i.postOpenSettleDurationMs=H(c),{appBundleId:s,timing:i}}async function rr(e,t,r){if(!t.target||n(t.target))return{};if(!r)return{postOpenObservation:`app-unidentified`};let i=await $n(await e.resolveInteractor(t.execution,r),r,e.signal);return i.observation===`probe-failed`?{postOpenObservation:`probe-failed`,postOpenObservationFailure:i.failure}:{postOpenObservation:i.observation}}function H(e){return Math.max(0,Date.now()-e)}async function ir(){throw new t(`UNSUPPORTED_OPERATION`,`This lifecycle operation is unavailable for Android.`)}async function U(e,t,n,r,i){W(n);let a=r?void 0:await lr(e,t,i);if(b.extname(n).toLowerCase()===`.aab`?await cr(e,t,n,i):K(await e.androidTools.installPackage(t,n,{replace:!0},i),`adb install failed`),r)return r;let o=[...await lr(e,t,i)].filter(e=>!a?.has(e));return o.length===1?o[0]:void 0}function W(e){if(y()&&b.extname(e).toLowerCase()===`.aab`)throw new t(`UNSUPPORTED_OPERATION`,`Managed Android deployment does not support app bundles.`,{reason:`managed-bundle-install-unavailable`,hint:`Install an APK on this managed device.`})}async function ar(e,t,n,r){let i=await G(e,t,[`uninstall`,n],r);if(i.exitCode===0)return;let a=`${i.stdout}\n${i.stderr}`.toLowerCase();a.includes(`unknown package`)||a.includes(`not installed`)||K(i,`adb uninstall failed for ${n}`)}async function or(e,n,r,i){let a=r.payload,s=typeof a.action==`string`&&a.action.trim()?a.action.trim():`${r.appId}.TEST_PUSH`,c=[`am`,`broadcast`,`-a`,s,`-p`,r.appId];typeof a.receiver==`string`&&a.receiver.trim()&&c.push(`-n`,a.receiver.trim());let l=a.extras??{};if(typeof l!=`object`||!l||Array.isArray(l))throw new t(`INVALID_ARGS`,`Android push payload extras must be an object`);let u=0;for(let[e,t]of Object.entries(l))e&&(ur(c,e,t),u+=1);return K(await G(e,n,o(`adb`,`shell`,c),i),`adb push broadcast failed`),{action:s,extrasCount:u}}function sr(e){let t=new Set([`com`,`android`,`google`,`app`,`apps`,`service`,`services`,`mobile`,`client`]),n=e.split(/[._-]+/).map(e=>e.trim().toLowerCase()).filter(Boolean),r=[...n].reverse().find(e=>!t.has(e))??n.at(-1)??e;return r.charAt(0).toUpperCase()+r.slice(1)}async function cr(e,n,r,i){if(await e.androidTools.installBundle(n,r,`universal`,i))return;let a=await e.commands.which(`bundletool`),o=e.androidDeployment.bundletoolJar;if(!a&&!o)throw new t(`TOOL_MISSING`,`bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR.`);let s=a?`bundletool`:`java`,c=a?[]:[`-jar`,o],l=await e.temporaryFiles.create({prefix:`agent-device-aab-`,suffix:`.apks`}),u=l.path;try{K(await e.commands.run({executable:s,args:[...c,`build-apks`,`--bundle`,r,`--output`,u,`--mode`,`universal`]},i),`bundletool build-apks failed`),K(await e.commands.run({executable:s,args:[...c,`install-apks`,`--apks`,u,`--device-id`,n.id]},i),`bundletool install-apks failed`)}finally{await l[Symbol.asyncDispose]()}}async function lr(e,t,n){let r=await G(e,t,o(`adb`,`shell`,[`pm`,`list`,`packages`]),n);return K(r,`adb package inventory failed`),new Set(r.stdout.split(`
|
|
5
|
-
`).map(e=>e.replace(`package:`,``).trim()).filter(Boolean))}function ur(e,n,r){if(typeof r==`string`)e.push(`--es`,n,r);else if(typeof r==`boolean`)e.push(`--ez`,n,String(r));else if(typeof r==`number`&&Number.isFinite(r))e.push(Number.isInteger(r)?`--ei`:`--ef`,n,String(r));else throw new t(`INVALID_ARGS`,`Unsupported Android broadcast extra type for "${n}". Use string, boolean, or number.`)}async function G(e,t,n,r,i=15e3){return await e.androidTools.runAdb(t,n,{timeoutMs:i,allowFailure:!0},r)}function K(e,n){if(e.exitCode===0)return;let r={stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode};throw new t(`COMMAND_FAILED`,n,r)}const dr=Object.freeze({available:!0});function fr(e){let t=gr(e);return Object.freeze({deployApp:t,materializeAppSource:t,deployMaterializedApp:t,sendPushNotification:t})}function pr(e){let{host:t,device:n,signal:r}=e;return fr(n).deployApp.available?Object.freeze({deployApp:async e=>await mr(t,n,e,r),materializeAppSource:async e=>await t.androidDeployment.prepareArtifact(e,{signal:r}),deployMaterializedApp:async e=>await hr(t,n,e,r),sendPushNotification:async e=>await or(t,n,e,r)}):Object.freeze({})}async function mr(e,t,n,r){if(n.replaceExisting)return await e.androidDeployment.withInvalidatedAppResolutionCache(t,async()=>{let i;try{y()&&(i=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!1,signal:r}),W(i.installablePath)),t.booted!==!0&&await B(e,t,{headless:!1},r);let a=await e.androidDeployment.resolveAppPackage(t,n.app);return await ar(e,t,a,r),i??=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!1,signal:r}),await U(e,t,i.installablePath,void 0,r),{packageName:a,launchTarget:a}}finally{await i?.cleanup()}});let i;try{y()&&(i=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!0,signal:r}),W(i.installablePath)),t.booted!==!0&&await B(e,t,{headless:!1},r),i??=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!0,signal:r});let a=await U(e,t,i.installablePath,i.packageName,r);return a?{packageName:a,appName:sr(a),launchTarget:a}:{}}finally{await i?.cleanup()}}async function hr(e,n,r,i){let a=await U(e,n,r.artifact.installablePath,r.artifact.packageName,i);if(!a)throw new t(`COMMAND_FAILED`,`Installed Android app identity could not be resolved from the artifact or device state`);return{packageName:a,appName:sr(a),launchTarget:a}}function gr(e){return e.kind===`emulator`||e.kind===`device`?dr:Object.freeze({available:!1,reason:`unsupported-device-kind`})}const q=i(`android`),J=Object.freeze({available:!0}),_r=Object.freeze({available:!1,reason:`unsupported-device-kind`}),vr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`focus is supported on Android emulators and physical devices.`}),yr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`keyboard actions are supported on Android emulators and physical devices.`}),br=Object.freeze({available:!1,reason:`unsupported-platform-leaf`}),xr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Android has no key event for this system button.`}),Sr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`fold drives the hinge of a foldable iPhone simulator; the Android emulator posture control is not driven by agent-device yet.`}),Cr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Headless boot is supported only for Android emulators.`}),wr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Android appstate is supported only for Android emulators and devices.`}),Tr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Apple runner preparation is supported only for Apple targets.`}),Er=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`open is supported only for Android emulators and devices.`}),Dr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`close is supported only for Android emulators and devices.`}),Or=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Runtime hints are supported only for Android emulators and devices.`}),kr=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Port reverse is supported only by an owning provider runtime.`}),Ar=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`shutdown is supported only for Apple simulators and Android emulators.`}),jr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`screenshot is supported only for Android emulators and devices.`}),Y=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`snapshot is supported only for Android emulators and devices.`}),Mr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Re-run without --actions, or target an iOS simulator.`}),Nr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`viewport resizes web targets only (--platform web).`}),Pr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`the stateless audio page probe is a web-session operation; Android targets use the host capture.`});function Fr(e){let t=Ir(e),n=Lr(e),r=Rr(e);return p({resolveOpenTarget:t,prepareApplicationOpen:t,openApplication:t,applyRuntimeHints:r,clearRuntimeHints:r,closeApplication:n,finalizeApplicationClose:n,prepareAppleRunner:Tr,configureProviderPortReverse:kr})}function Ir(e){return e.kind===`emulator`||e.kind===`device`?J:Er}function Lr(e){return e.kind===`emulator`||e.kind===`device`?J:Dr}function Rr(e){return e.kind===`emulator`||e.kind===`device`?J:Or}const X=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Gestures are supported on Android emulators and physical devices.`}),zr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:Fe}),Br=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:Pe});function Vr(e,t){return e.kind===`simulator`?X:e.target===`tv`?t:J}function Z(e){return e.kind===`simulator`?X:J}function Q(e){return e.kind===`simulator`?vr:J}const $=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:Ne}),Hr=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`Could not determine whether this Android build supports a shell clipboard: the adb probe did not complete. Retry once the device is reachable.`});async function Ur(e,t){let n=e.androidTools?.probeClipboardShellSupport;return n?await n.call(e.androidTools,t):`probe-failed`}const Wr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`tv-remote is supported only on Android TV targets.`});function Gr(e){return e.kind!==`simulator`&&e.target===`tv`?J:Wr}function Kr(e){let t=nt(e),n=new Map,r=async t=>{if(t.kind===`simulator`)return $;let r=n.get(t.id)??await Ur(e,t);return r!==`probe-failed`&&n.set(t.id,r),r===`supported`?J:r===`unsupported`?$:Hr},i=async e=>{let n=await t.inspectFacts(e),i=fr(e),a=await r(e);return Object.freeze({device:n.device,operations:{...n.operations,...i,appState:e.kind===`simulator`?wr:J,networkDump:J,screenRecordingStart:J,screenRecordingReattach:J,screenRecordingCleanup:J,..._({capture:e.kind===`simulator`?Y:J,customActions:Mr,withoutActiveApp:e.kind===`simulator`?Y:J}),...re({capture:e.kind===`simulator`?jr:J}),...ae({findText:Y}),...h({setViewport:Nr}),...me({focus:Q(e)}),...ne({unsupported:X,plan:Z(e),directionalFling:Z(e),multiTouch:Vr(e,zr),targetAuthoredDrag:Vr(e,Br),viewport:Z(e)}),...ie({scroll:Z(e)}),...m({type:Q(e)}),..._e({unsupported:vr,tap:Q(e),longPress:Q(e),hover:br,fill:Q(e)}),...ee({readTextAtPoint:e.kind===`simulator`?_r:J}),...fe({back:Q(e)}),...oe({unsupported:xr,home:Q(e),appSwitcher:Q(e)}),setFoldPose:Sr,...ue({triggerAppEvent:Q(e)}),...le({setSetting:Q(e),readSetting:Q(e)}),...ce({read:Q(e),wait:Q(e),accept:Q(e),dismiss:Q(e)}),...g({orientation:Q(e)}),...pe({tvRemote:Gr(e)}),...de({unsupported:yr,status:Q(e),dismiss:Q(e),enter:Q(e)}),...se({unsupported:a.available?$:a,read:a,write:a}),...he({capture:Ye(e),query:Pr}),...ge({frames:Q(e),memorySample:Q(e),memorySnapshot:Q(e),nativeCapture:Q(e),profileReport:Q(e)}),ensureReady:J,bootTarget:J,bootTargetHeadless:e.kind===`emulator`?J:Cr,listApps:J,...Fr(e),shutdownTarget:e.kind===`emulator`?J:Ar}})};return Object.freeze({owner:q,ownsDevice:e=>e.platform===`android`,inspectFacts:i,bind:async n=>{let r=await t.bind(n),o=await i(n.device),s=await Hn({host:e,device:n.device,owner:q,signal:n.scope.signal});return Object.freeze({device:r.device,owner:q,facts:o,operations:Object.freeze({...r.operations,...pr({host:e,device:n.device,signal:n.scope.signal}),...o.operations.appState.available?{appState:async()=>{n.scope.signal.throwIfAborted();let{runAndroidAdb:e}=await import(`./adb.js`).then(e=>e.t);return await Me(async(t,r)=>await e(n.device,t,{...r,signal:n.scope.signal}),n.scope.signal)}}:{},networkDump:async t=>await at(e,n.device,t,n.scope.signal),...s,...a(o.operations.audioProbeStart,()=>Se({host:e.audioProbe.hostCapture,device:n.device,owner:q})),...a(o.operations.perfFrames,()=>Xe({resolveHost:()=>e.perf.android,device:n.device,owner:q})),...qr(e,n,o),ensureReady:async t=>await B(e,n.device,{...t,headless:!1},n.scope.signal),bootTarget:async t=>await B(e,n.device,{...t,headless:!1},n.scope.signal),...o.operations.bootTargetHeadless.available?{bootTargetHeadless:async t=>await B(e,n.device,{...t,headless:!0},n.scope.signal)}:{},listApps:async e=>{n.scope.signal.throwIfAborted();let{listAndroidApps:t}=await import(`./app-lifecycle.js`).then(e=>e.t);return(await t(e.device,e.filter)).map(e=>({id:e.package,name:e.name}))},...d(tr({host:e,device:n.device,signal:n.scope.signal}),o.operations),...o.operations.shutdownTarget.available?{shutdownTarget:async()=>await e.deviceShutdown.android.shutdownTarget(n.device,n.scope.signal)}:{}}),[Symbol.asyncDispose]:async()=>await r[Symbol.asyncDispose]()})},shutdown:async()=>await t.shutdown()})}function qr(e,t,n){let r={device:t.device,signal:t.scope.signal,resolveInteractor:e.localInteractors.resolve};return{...n.operations.captureSnapshot.available?te(r):{},...Ie({...r,facts:n.operations,pause:async n=>await e.clock.sleep(n,t.scope.signal)})}}export{Kr as createAndroidPlatformRuntime};
|
|
4
|
+
`))if(n.includes(t))for(let e of a){let t=e.exec(n)?.[1];t&&/^\d+$/.test(t)&&r.add(t)}return Object.freeze([...r])}function C(e,t){if(t===1)return e;let n=x.parse(e);return x.join(n.dir,`${n.name}.part-${String(t).padStart(3,`0`)}${n.ext||`.mp4`}`)}const ft=/^(?:\/sdcard|\/data\/local\/tmp)\/agent-device-recording-\d{1,20}\.mp4$/,pt=/^(?:\/sdcard|\/data\/local\/tmp)\/agent-device-recording-active\.json$/;function mt(e){return _t(e)&&vt(e)&&yt(e)}function ht(e){if(!w(e))return!1;let t=e;return bt(t)&&xt(t)&&St(t)&&Ct(t)&&(t.completion===void 0||At(t))}function gt(e,t){return jt(e,t)&&Mt(e,t.outputPath,t.clientOutputPath)}function _t(e){return e.backend===`adb-screenrecord`&&typeof e.manifestPath==`string`&&pt.test(e.manifestPath)&&typeof e.outputPath==`string`}function vt(e){return Pt(e.clientOutputPath)&&_(e)}function yt(e){return Nt(e.transportMode)}function bt(e){return e.version===1&&e.resourceKind===`screen-recording`&&typeof e.fenceToken==`string`&&Number.isInteger(e.fenceGeneration)&&typeof e.sessionId==`string`&&typeof e.deviceId==`string`&&Number.isFinite(e.startedAt)}function xt(e){return typeof e.outputPath==`string`&&Pt(e.clientOutputPath)&&_(e)}function St(e){return Nt(e.transportMode)&&(e.pendingRemotePath===void 0||Ft(e.pendingRemotePath))}function Ct(e){return Array.isArray(e.chunks)&&e.chunks.every(wt)&&(e.chunks.length>0||e.pendingRemotePath!==void 0)&&(e.completion===void 0||Tt(e.completion))}function wt(e,t){if(!w(e))return!1;let n=e;return n.index===t+1&&Ft(n.remotePath)&&It(n.remotePid)&&It(n.remoteStartTime)}function Tt(e){if(!w(e))return!1;let t=e;return Dt(t)&&Ot(t)&&Et(t)&&(t.chunks===void 0||t.chunks.every(kt))}function Et(e){return(e.stopObservation===void 0||u(e.stopObservation))&&(e.nativePathDisposition===void 0||l(e.nativePathDisposition))}function Dt(e){return typeof e.backend==`string`&&typeof e.outPath==`string`&&(e.clientOutPath===void 0||typeof e.clientOutPath==`string`)&&Number.isFinite(e.startedAt)&&Number.isFinite(e.completedAt)&&(e.capturedDurationMs===void 0||Number.isFinite(e.capturedDurationMs))}function Ot(e){return _(e)}function kt(e,t){return e.index===t+1&&typeof e.path==`string`&&(e.clientOutPath===void 0||typeof e.clientOutPath==`string`)}function At(e){let t=e.completion;return t!==void 0&&jt(t,e)&&t.startedAt===e.startedAt&&Mt(t,e.outputPath,e.clientOutputPath,e.chunks.length)}function jt(e,t){return e.backend===`adb screenrecord`&&e.outPath===t.outputPath&&e.clientOutPath===t.clientOutputPath&&e.scope===t.scope&&e.showTouches===t.showTouches&&e.recordOnlySession===t.recordOnlySession&&Lt(e.activeSessionApp,t.activeSessionApp)}function Mt(e,t,n,r=e.chunks===void 0?1:e.chunks.length){return r===1?e.chunks===void 0:e.chunks?.length===r&&e.chunks.every((e,r)=>e.path===C(t,r+1)&&e.clientOutPath===(n===void 0?void 0:C(n,r+1)))}function w(e){return typeof e==`object`&&!!e}function Nt(e){return e===`local`||e===`transport-composed`}function Pt(e){return e===void 0||typeof e==`string`}function Ft(e){return typeof e==`string`&&ft.test(e)}function It(e){return typeof e==`string`&&/^\d+$/.test(e)}function Lt(e,t){return JSON.stringify(e)===JSON.stringify(t)}const T=Object.freeze({resourceKind:Ne,version:1,encode:e=>({...e}),decode:e=>mt(e)?{status:`decoded`,descriptor:Object.freeze({backend:`adb-screenrecord`,manifestPath:e.manifestPath,outputPath:e.outputPath,...e.clientOutputPath===void 0?{}:{clientOutputPath:e.clientOutputPath},scope:e.scope,showTouches:e.showTouches,recordOnlySession:e.recordOnlySession,transportMode:e.transportMode,...e.activeSessionApp===void 0?{}:{activeSessionApp:e.activeSessionApp},...e.exportQuality===void 0?{}:{exportQuality:e.exportQuality}})}:{status:`invalid`,message:`Invalid Android screen-recording descriptor`}});function E(e,t,n,r,i,a=`local`){return Object.freeze({version:1,resourceKind:`screen-recording`,fenceToken:t.fence.token,fenceGeneration:t.fence.generation,sessionId:t.sessionId,deviceId:e.id,startedAt:n,outputPath:t.outputPath,...t.clientOutputPath===void 0?{}:{clientOutputPath:t.clientOutputPath},scope:t.scope,showTouches:t.showTouches,recordOnlySession:t.recordOnlySession,...t.activeSessionApp===void 0?{}:{activeSessionApp:t.activeSessionApp},...t.exportQuality===void 0?{}:{exportQuality:t.exportQuality},chunks:r,...i===void 0?{}:{pendingRemotePath:i},transportMode:a})}function Rt(e,t){return Object.freeze({...e,completion:t})}function D(e){try{let t=e&&JSON.parse(e);return ht(t)?t:void 0}catch{return}}function zt(e,t,n){return e.deviceId===t.id&&e.deviceId===n.device.id&&e.fenceToken===n.fence.token&&e.fenceGeneration===n.fence.generation&&e.sessionId===n.sessionId}function Bt(e,t){return e.outputPath===t.outputPath&&e.clientOutputPath===t.clientOutputPath&&e.scope===t.scope&&e.showTouches===t.showTouches&&e.recordOnlySession===t.recordOnlySession&&JSON.stringify(e.activeSessionApp)===JSON.stringify(t.activeSessionApp)&&e.exportQuality===t.exportQuality&&e.transportMode===t.transportMode&&(e.completion===void 0||gt(e.completion,t))}function O(e){switch(e){case`missing`:case`ownership-lost`:case`foreign-writer`:return!0;case`owned-alive`:case`uncertain`:return!1}}function Vt(e){switch(e){case`missing`:case`ownership-lost`:return!0;case`foreign-writer`:case`owned-alive`:case`uncertain`:return!1}}const Ht=1e4,k=1e3;var A=class extends Error{constructor(e){super(`Android screenrecord launch rollback could not be confirmed`,{cause:e})}};function j(e,t=Date.now()){return[...new Set(e?[e,`/sdcard`,`/data/local/tmp`]:[`/sdcard`,`/data/local/tmp`])].map(e=>`${e}/agent-device-recording-${t}.mp4`)}async function Ut(e,t,n,r){let i;try{if(i=(await e.start({remotePath:t,quality:n.exportQuality??`medium`},r)).process,!/^\d+$/.test(i.pid)||!/^\d+$/.test(i.startTime)||i.remotePath!==t)throw Error(`Android screenrecord returned an invalid process identity`);if(!await Yt(e,t,i,r))throw Error(`Android screenrecord did not begin producing frames`);return{index:1,remotePath:t,remotePid:i.pid,remoteStartTime:i.startTime}}catch(t){throw i&&Wt(i)&&!await Xt(e,i)?new A(t):r?.aborted?r.reason:t}}function Wt(e){return/^\d+$/.test(e.pid)&&/^\d+$/.test(e.startTime)&&e.remotePath.length>0}async function M(e,t){let n=t.at(-1),r=!1,i;for(let a of[...t].reverse())try{let t=await P(e,a);a===n&&(r=t)}catch(e){i??=e}if(i)throw i;return r}async function Gt(e,t){for(let n of t){let t;for(let r=0;r<3;r+=1){let i=await e.size(n.remotePath);if(typeof i==`number`&&i>0&&i===t)break;if(t=typeof i==`number`&&i>0?i:void 0,r===2)throw Error(`Android recording artifact is not stable: ${n.remotePath}`);await new Promise(e=>setTimeout(e,250))}}}async function Kt(e,t,n){for(let[r,i]of t.entries())await Zt(e,i.remotePath,C(n,r+1))}async function N(e,t){let n;for(let r of t)try{if(!await e.remove(r.remotePath))throw Error(`failed to remove Android recording artifact: ${r.remotePath}`)}catch(e){n??=e}if(n)throw n}async function qt(e,t){for(let n of t)if(await e.exists(n.remotePath)!==!1)return`retirable`;return`retired`}async function Jt(e,t){try{await M(e,t)}finally{await N(e,t)}}async function Yt(e,t,n,r){for(let i=0;i<3;i+=1){if(r?.throwIfAborted(),await e.exists(t,r)===!0)return!0;if(await e.inspect(n,r)!==`owned-alive`)return!1;i<2&&await new Promise(e=>setTimeout(e,250))}return!0}async function Xt(e,t){try{let n=await e.stop(t,{force:!0});return(n===`stopped`||n===`already-missing`)&&await e.remove(t.remotePath)}catch{return!1}}async function P(e,t){if(!t)return!1;let n={pid:t.remotePid,remotePath:t.remotePath,startTime:t.remoteStartTime},r=await e.stop(n);if(r===`already-missing`)return!0;if(r===`ownership-lost`)throw Error(`Android screenrecord ownership could not be confirmed for pid ${t.remotePid}`);if(await Qt(e,n))return!1;let i=await e.stop(n,{force:!0});if(i===`stopped`||i===`already-missing`)return!1;throw Error(`failed to stop Android screenrecord pid ${t.remotePid}`)}async function Zt(e,t,n){for(let r=0;r<3;r+=1){let i=await e.pullPlayable({remotePath:t,outputPath:n});if(i.exitCode===0&&i.playable)return;r+1<3&&await $t(1e3)}throw Error(`failed to retrieve playable Android recording`)}async function Qt(e,t){for(let n=0;n<=Ht;n+=k){let r=await e.inspect(t);if(r===`missing`)return!0;if(O(r))throw Error(`Android screenrecord ownership could not be confirmed for pid ${t.pid}`);n<Ht&&await $t(k)}return!1}function $t(e){return new Promise(t=>setTimeout(t,e))}async function F(e,t,n,r){await e.writeManifest({manifestPath:t,contents:JSON.stringify(n)},r)}async function I(e,t){if(!await e.removeManifest(t))throw Error(`failed to remove Android recording manifest: ${t}`)}async function en(e,t){let n=(await tn(e)).flatMap(n=>nn(n,t,e.mode));for(let t of n)await an(e,t.evidence,t.manifestPath)}async function tn(e){return await Promise.all(j(void 0).map(async t=>{let n=e.manifestPathFor(t);return{manifestPath:n,read:await e.readManifest(n)}}))}function nn(e,t,n){if(e.read.status===`missing`)return[];if(e.read.status!==`read`)throw cn(e.manifestPath,e.read.message);let r=D(e.read.contents);if(r===void 0)throw ln(e.manifestPath);if(r.transportMode!==n)throw un(e.manifestPath,r,n);if(!rn(r,t))throw dn(e.manifestPath,r,t);return[{manifestPath:e.manifestPath,evidence:r}]}function rn(e,t){return e.completion!==void 0||e.deviceId!==t.id}async function an(e,t,n){if(await on(e,t),await N(e,t.chunks),await sn(e,t),await I(e,n),(await e.readManifest(n)).status!==`missing`)throw mn(n)}async function on(e,t){for(let n of t.chunks){let t=await e.inspect({pid:n.remotePid,remotePath:n.remotePath,startTime:n.remoteStartTime});if(!Vt(t))throw t===`uncertain`?hn(n.remotePath):fn(n.remotePath,t===`owned-alive`?`named-recorder`:`other-recorder`)}let n=t.pendingRemotePath;if(n===void 0)return;let r=await e.probeRunningWriters(n);if(r.writers.length>0)throw fn(n,`other-recorder`);if(!r.conclusive)throw hn(n)}async function sn(e,t){let n=t.pendingRemotePath;if(n!==void 0&&!await e.remove(n))throw pn(n)}function cn(t,n){return new e(`COMMAND_FAILED`,`Android screenrecord native recovery evidence is unavailable: ${t}`,{reason:`native_recovery_evidence_unavailable`,manifestPath:t,hint:`Confirm the device is online and its storage readable, then run record start again.`},Error(n))}function ln(t){return new e(`COMMAND_FAILED`,`Android screenrecord native recovery evidence is unreadable: ${t}`,{reason:`native_recovery_evidence_unreadable`,manifestPath:t,hint:L(t)})}function un(t,n,r){return new e(`COMMAND_FAILED`,`Android screenrecord native recovery evidence was written by the ${n.transportMode} transport, not this ${r} one: ${t}`,{reason:`native_recovery_evidence_transport_mismatch`,manifestPath:t,evidenceTransportMode:n.transportMode,hint:L(t)})}function dn(t,n,r){return new e(`DEVICE_IN_USE`,`Android screenrecord native recovery evidence already exists: ${t} (open recording of session "${n.sessionId}" on ${r.id})`,{reason:`native_recovery_evidence_open`,manifestPath:t,sessionId:n.sessionId,retriable:!1,hint:`Run record stop --session ${n.sessionId} to retire it, or close that session. If it is already closed, ${L(t)}`})}function fn(t,n){let r=n===`named-recorder`;return new e(`DEVICE_IN_USE`,`Android screenrecord recovery evidence is retained: ${r?`its recorder`:`another recorder`} is writing ${t}`,{reason:`native_recording_artifact_claimed`,remotePath:t,writer:n,...r?{retriable:!1}:{},hint:r?`Run record stop for the session that owns that recording before starting another.`:`Android ends any recorder after 180 seconds. Run record start again once that recorder has stopped.`})}function pn(t){return new e(`COMMAND_FAILED`,`Android screenrecord recovery evidence could not remove ${t}`,{reason:`native_recording_artifact_removal_failed`,remotePath:t,hint:`Confirm the device is online and run record start again.`})}function mn(t){return new e(`COMMAND_FAILED`,`Android screenrecord recovery evidence removal could not be confirmed: ${t}`,{reason:`native_recovery_evidence_retirement_unconfirmed`,manifestPath:t,hint:`Run record start again; the marker is retired from the beginning.`})}function hn(t){return new e(`COMMAND_FAILED`,`Android screenrecord recovery evidence cannot be safely retired: ${t}`,{reason:`native_recording_recorder_unproven`,remotePath:t,hint:`Confirm the device is online and run record start again.`})}function L(e){return`no recording session can retire this marker; remove it on the device with \`adb shell rm -f ${e}\`.`}async function gn(e){let{transport:t,device:n,input:r,startedAt:i,signal:a,prepareOutput:o}=e;await en(t,n),await o();let s;for(let e of j(void 0)){let o=t.manifestPathFor(e);await F(t,o,E(n,r,i,[],e,t.mode),a);let c,l;try{l=Date.now(),c=await Ut(t,e,r,a)}catch(e){if(a.aborted)throw await _n(t,o,e),a.reason;await bn(t,o,e),s=e;continue}try{await F(t,o,E(n,r,i,[c],void 0,t.mode),a)}catch(e){throw await vn(t,o,c),e}return{chunk:c,manifestPath:o,startedAtMs:l}}throw s??Error(`Android screenrecord did not begin producing frames`)}async function _n(e,t,n){n instanceof A||await I(e,t).catch(()=>{})}async function vn(e,t,n){try{await Jt(e,[n])}catch{return}await I(e,t).catch(()=>{})}async function yn(e){let{transport:t,device:n,input:r,startedAt:i,chunks:a,manifestPath:o,preferredDir:s}=e,c;for(let e of j(s)){await F(t,o,E(n,r,i,a,e,t.mode));try{return await Ut(t,e,r)}catch(e){if(e instanceof A)throw e;try{await F(t,o,E(n,r,i,a,void 0,t.mode))}catch{throw new A(e)}c=e}}throw c??Error(`failed to start next Android recording chunk`)}async function bn(e,t,n){if(n instanceof A)throw n;try{await I(e,t)}catch{throw new A(n)}}function xn(e,t){return Object.freeze({backend:`adb screenrecord`,outPath:e.outputPath,...e.clientOutputPath?{clientOutPath:e.clientOutputPath}:{},startedAt:t,scope:e.scope,showTouches:e.showTouches,recordOnlySession:e.recordOnlySession,...e.activeSessionApp?{activeSessionApp:e.activeSessionApp}:{},...e.exportQuality?{exportQuality:e.exportQuality}:{},gestureEvents:[]})}function Sn(e){let t=Cn(e.chunkPaths);if(t===void 0)return{};let n=e.stoppedAtMs-e.startedAtMs;return n-t<2e3?{capturedDurationMs:t}:{capturedDurationMs:t,idleTailWarning:`Android screenrecord encodes a frame only when the screen changes, so this video ends at the last frame it encoded: it covers ${wn(t)}s of the ${wn(n)}s recording window.`}}function Cn(e){let t=0;for(let n of e){let e=Ue(n);if(e===void 0)return;t+=e}return t}function wn(e){return(e/1e3).toFixed(1)}async function Tn(e){let{host:t,transport:n,evidence:r,recording:i,startedAtMs:a,progress:o}=e,s=e.reachedLimit===!0;return await An(e,await ke({snapshot:i,progress:o,steps:{stop:async()=>(s=await M(n,r.chunks)||s,await Gt(n,r.chunks),{observation:{recorder:`confirmed`},...s?{warning:`Android adb screenrecord stopped before record stop, likely after reaching the 180s platform limit. The MP4 may be truncated; final interactions after the limit are not in the video.`}:{}}),collect:e=>Kt(n,r.chunks,e),finalize:({collectedPath:e,exportPath:n,stoppedAtMs:o})=>En({host:t,evidence:r,recording:i,startedAtMs:a,stoppedAtMs:o,collectedPath:e,exportPath:n}),discard:e=>On(t,e,r.chunks.length)}}))}async function En(e){let{host:t,evidence:n,recording:r,collectedPath:i,exportPath:a}=e,o=jn({collectedPath:i,exportPath:a,exportClientPath:r.clientOutPath,count:n.chunks.length}),s=o.length>1,c;try{await Dn(t,o),c=await t.screenRecording.finalize.complete({outputPath:a,showTouches:!s&&r.showTouches,gestureEvents:r.gestureEvents,exportQuality:r.exportQuality??`medium`,targetLabel:`Android recording`})}catch(e){for(let{served:e}of o)await t.screenRecording.outputs.remove(e.path);throw e}let l=Sn({chunkPaths:o.map(({collected:e})=>e.path),startedAtMs:e.startedAtMs,stoppedAtMs:e.stoppedAtMs});return kn({finalization:c,captured:l,recording:r,chunked:s,files:o})}async function Dn(e,t){for(let{collected:n,served:r}of t)await e.screenRecording.outputs.copy({from:n.path,to:r.path})}async function On(e,t,n){for(let r=1;r<=n;r+=1)await e.screenRecording.outputs.remove(C(t,r))}function kn(e){let{finalization:t,captured:n,recording:r,chunked:i,files:a}=e,o=[t.warning,...i?[`Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks.`]:[],n.idleTailWarning].filter(e=>e!==void 0&&e.length>0);return{...t.telemetryPath===void 0?{}:{telemetryPath:t.telemetryPath},...o.length===0?{}:{warning:o.join(` `)},...i&&r.showTouches&&r.gestureEvents.length>0?{overlayWarning:`touch overlay burn-in is skipped for chunked Android recordings; returning raw chunks plus gesture telemetry`}:{},...n.capturedDurationMs===void 0?{}:{capturedDurationMs:n.capturedDurationMs},...i?{chunks:a.map(e=>e.served)}:{},nativePathDisposition:`retirable`}}async function An(e,t){let{transport:n,evidence:r,manifestPath:i}=e;return await F(n,i,Rt(r,t.result)),await N(n,r.chunks),{status:`completed`,result:{...t.result,nativePathDisposition:await qt(n,r.chunks)}}}function jn(e){return Object.freeze(Array.from({length:e.count},(t,n)=>({collected:Object.freeze({index:n+1,path:C(e.collectedPath,n+1)}),served:Object.freeze({index:n+1,path:C(e.exportPath,n+1),...e.exportClientPath===void 0?{}:{clientOutPath:C(e.exportClientPath,n+1)}})})))}async function Mn(e,t,n){try{let r=t.pendingRemotePath;if(await M(e,[...t.chunks,...await Nn(e,t)]),await N(e,t.chunks),r!==void 0&&!await e.remove(r))throw Error(`failed to remove Android recording artifact: ${r}`);return await I(e,n),{status:`cleaned`}}catch(e){return Pn(e)}}async function Nn(e,t){let n=t.pendingRemotePath;if(n===void 0)return[];let r=await e.probeRunningWriters(n);if(!r.conclusive)throw Error(`cannot list every recorder writing Android artifact: ${n}`);return r.writers.map((e,r)=>({index:t.chunks.length+1+r,remotePath:n,remotePid:e.pid,remoteStartTime:e.startTime}))}function Pn(e){return{status:`cleanup-pending`,reason:`transport-failed`,message:e instanceof Error?e.message:String(e)}}async function Fn(e){let{transport:t,device:n,envelope:r,descriptor:i}=e;if(i.transportMode!==t.mode)return{status:`transport-unavailable`};let a=await t.readManifest(i.manifestPath);if(a.status===`unavailable`)return{status:`transport-unavailable`};let o=a.status===`read`?D(a.contents):void 0;return o&&zt(o,n,r)&&Bt(o,i)?{status:`matched`,evidence:o}:{status:`ownership-lost`}}async function In(e){let t=await e.transport.readManifest(e.manifestPath);if(t.status!==`read`)return;let n=D(t.contents);return n&&Ln(n,e)?n:void 0}function Ln(e,t){return e.deviceId===t.deviceId&&e.sessionId===t.sessionId&&e.fenceToken===t.fence.token&&e.fenceGeneration===t.fence.generation}async function Rn(e){let{host:t,transport:n,device:r,input:i}=e,a=T.decode(i.envelope.descriptor.body);if(a.status!==`decoded`)return R(`descriptor-invalid`);let o=await Fn({transport:n,device:r,envelope:i.envelope,descriptor:a.descriptor});return o.status===`matched`?await Bn({host:t,transport:n,device:r,input:i,descriptor:a.descriptor,evidence:o.evidence}):R(o.status===`transport-unavailable`?`transport-not-reattachable`:`ownership-fence-lost`)}async function zn(e){let t=T.decode(e.input.envelope.descriptor.body);if(t.status!==`decoded`)return{status:`cleanup-pending`,reason:`manual-recovery-required`};let n=await Fn({transport:e.transport,device:e.device,envelope:e.input.envelope,descriptor:t.descriptor});return n.status===`matched`?await Mn(e.transport,n.evidence,t.descriptor.manifestPath):n.status===`transport-unavailable`?{status:`cleanup-pending`,reason:`owner-unavailable`}:{status:`cleanup-pending`,reason:`ownership-fence-lost`}}async function Bn(e){let{host:t,transport:n,device:r,input:i,descriptor:a,evidence:o}=e;if(o.completion!==void 0){let e=await Vn(n,o);return e.status===`terminal`?{status:`completed`,result:{...o.completion,nativePathDisposition:e.nativePathDisposition}}:R(`ownership-fence-lost`,`Android recording completed evidence still names a live or unverifiable recorder.`)}if(o.pendingRemotePath!==void 0)return R(`transport-not-reattachable`,`Android recording launch was interrupted before its process identity was committed.`);let s=o.chunks.at(-1);if(!s)return{status:`missing`};let c=await n.inspect({pid:s.remotePid,remotePath:s.remotePath,startTime:s.remoteStartTime});if(c!==`owned-alive`&&await n.exists(s.remotePath)===!1)return R(`transport-not-reattachable`,`Android recording process ended before its artifact could be recovered.`);let l=Hn(i.envelope.sessionId,i.envelope.fence,a),u=!1;return{status:`active`,handle:De(xn(l,o.startedAt),{finish:async(e,r)=>{let i=await Tn({host:t,transport:n,evidence:o,manifestPath:a.manifestPath,recording:e,startedAtMs:o.startedAt,reachedLimit:O(c),progress:r});return u=!0,i},forceCleanup:async()=>u?{status:`cleaned`}:await zn({transport:n,device:r,input:i})})}}async function Vn(e,t){try{for(let n of t.chunks)if(!O(await e.inspect({pid:n.remotePid,remotePath:n.remotePath,startTime:n.remoteStartTime})))return{status:`retained`};return{status:`terminal`,nativePathDisposition:await qt(e,t.chunks)}}catch{return{status:`retained`}}}function Hn(e,t,n){return{sessionId:e,outputPath:n.outputPath,...n.clientOutputPath===void 0?{}:{clientOutputPath:n.clientOutputPath},scope:n.scope,showTouches:n.showTouches,hideTouchesRequested:!1,recordOnlySession:n.recordOnlySession,...n.activeSessionApp===void 0?{}:{activeSessionApp:n.activeSessionApp},...n.exportQuality===void 0?{}:{exportQuality:n.exportQuality},fence:t}}function R(e,t){return{status:`unreattachable`,reason:e,...t===void 0?{}:{message:t}}}async function Un(e){let{host:t,device:n,owner:r,signal:i}=e,a=await t.screenRecording.android.resolve(n);return Object.freeze({screenRecordingStart:async e=>await Wn({host:t,transport:a,device:n,owner:r,input:e,signal:i}),screenRecordingReattach:async e=>await Rn({host:t,transport:a,device:n,input:e}),screenRecordingCleanup:async e=>await zn({transport:a,device:n,input:e})})}async function Wn(e){let{host:t,transport:n,device:i,owner:a,input:o,signal:s}=e;s.throwIfAborted();let c=Date.now(),l=await gn({transport:n,device:i,input:o,startedAt:c,signal:s,prepareOutput:async()=>await t.screenRecording.outputs.prepare(o.outputPath)}),u=l.manifestPath,d=[l.chunk],f,p,m,h=!1,g=()=>{f=setTimeout(()=>{p=ee().catch(e=>{m=e})},17e4),f.unref?.()},ee=async()=>{let e=d.at(-1);if(!e)throw Error(`Android recording has no active chunk`);let t=!1,r;try{r=await yn({transport:n,device:i,input:o,startedAt:c,chunks:d,manifestPath:u,preferredDir:x.posix.dirname(e.remotePath)})}catch(a){await P(n,e),t=!0;try{r=await yn({transport:n,device:i,input:o,startedAt:c,chunks:d,manifestPath:u,preferredDir:x.posix.dirname(e.remotePath)})}catch(e){throw e instanceof Error?e:a}}let a=[...d,{...r,index:d.length+1}];try{await F(n,u,E(i,o,c,a,void 0,n.mode))}catch(a){if(await Jt(n,[r]).catch(()=>{}),t)await F(n,u,E(i,o,c,d,r.remotePath,n.mode)).catch(()=>{});else try{await F(n,u,E(i,o,c,d,void 0,n.mode))}catch{await P(n,e).catch(()=>{}),await F(n,u,E(i,o,c,d,r.remotePath,n.mode)).catch(()=>{})}throw a}d=a,t||await P(n,e),g()};g();let te=De(xn(o,c),{finish:async(e,r)=>{if(f&&clearTimeout(f),await p,m)throw m;let a=await Tn({host:t,transport:n,evidence:E(i,o,c,d,void 0,n.mode),manifestPath:u,recording:e,startedAtMs:l.startedAtMs,progress:r});return h=!0,a},forceCleanup:async()=>{if(f&&clearTimeout(f),h)return{status:`cleaned`};try{await p}catch(e){m=e}let e=await In({transport:n,deviceId:i.id,sessionId:o.sessionId,fence:o.fence,manifestPath:u});return e?await Mn(n,e,u):{status:`cleanup-pending`,reason:`ownership-fence-lost`}}});return Object.freeze({pendingHandle:new xe(te),envelope:be({resourceKind:Ne,sessionId:o.sessionId,device:r(i),owner:a,fence:o.fence,lifecycle:`open`,descriptor:ye(T,{backend:`adb-screenrecord`,manifestPath:u,outputPath:o.outputPath,...o.clientOutputPath===void 0?{}:{clientOutputPath:o.clientOutputPath},scope:o.scope,showTouches:o.showTouches,recordOnlySession:o.recordOnlySession,...o.activeSessionApp===void 0?{}:{activeSessionApp:o.activeSessionApp},...o.exportQuality===void 0?{}:{exportQuality:o.exportQuality},transportMode:n.mode})})})}const Gn=1e3;async function z(e,t,n,r){return r.throwIfAborted(),await We(t)?{...t,booted:!0}:t.kind===`emulator`&&(t.booted!==!0||!B(t))?await Kn(e,t,n,r):(t.booted!==!0&&await Xn(e,t.id,Qn(e,n),r),{...t,booted:!0})}async function Kn(e,t,n,r){await qn(e);let i=$n(n),a=Qn(e,n),o=Jn(await e.deviceReadiness.androidEmulator.discover(i,r),t.name,n.serial),s=B(o)?o:void 0,c=s?void 0:e.deviceReadiness.androidEmulator.launch(o.name,n.headless);try{let t=s??await Yn(e,o.name,i,n.serial,a,r);return await Xn(e,t.id,a,r),{...(await e.deviceReadiness.androidEmulator.discover(i,r)).find(e=>e.id===t.id)??t,name:o.name,booted:!0}}catch(t){throw c!==void 0&&r.aborted&&await e.deviceReadiness.androidEmulator.terminate(c),r.throwIfAborted(),t}}async function qn(t){if(await t.toolchains.prepare(`android`),!await t.commands.which(`adb`))throw new e(`TOOL_MISSING`,`adb not found in PATH`);if(!await t.commands.which(`emulator`))throw new e(`TOOL_MISSING`,`emulator not found in PATH`)}function Jn(t,n,r){let i=er(t,n,r);if(i)return i;throw new e(`DEVICE_NOT_FOUND`,`No Android emulator AVD named ${n}`,{requestedAvdName:n,availableAvds:t.map(e=>e.name),hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."})}async function Yn(e,t,n,r,i,a){for(;e.clock.now()<i;){let i=er(await e.deviceReadiness.androidEmulator.discover(n,a),t,r);if(i&&B(i))return i;await e.clock.sleep(Gn,a)}throw Zn(`Android emulator did not appear in time`,{avdName:t,serial:r})}async function Xn(e,t,n,r){for(;e.clock.now()<n;){if((await e.commands.run({executable:`adb`,args:o(`adb`,`shell`,[`getprop`,`sys.boot_completed`],[`-s`,t]),allowFailure:!0,timeoutMs:Math.min(1e4,Math.max(1e3,n-e.clock.now()))},r)).stdout.trim()===`1`)return;await e.clock.sleep(Gn,r)}throw Zn(`Android device failed to finish booting`,{serial:t})}function Zn(t,n){return new e(`COMMAND_FAILED`,t,{...n,reason:Me,hint:`The emulator keeps booting in the background. Retry once it is up, or pass a larger --timeout.`})}function Qn(e,t){return t.deadlineAtMs??e.clock.now()+12e4}function $n(e){return{platform:`android`,kind:`emulator`,...e.serial?{serial:e.serial}:{},...e.androidSerialAllowlist?{androidSerialAllowlist:[...e.androidSerialAllowlist]}:{}}}function er(e,t,n){let r=tr(t);return e.find(e=>e.platform===`android`&&e.kind===`emulator`&&tr(e.name)===r&&(!n||!B(e)||e.id===n))}function B(e){return e.id.startsWith(`emulator-`)}function tr(e){return e.toLowerCase().replaceAll(`_`,` `).replaceAll(/\s+/g,` `).trim()}async function nr(e,t,n){try{let r=await e.snapshot({appBundleId:t,signal:n,transient:{settleBy:Date.now()+6e3}});return{observation:`androidSnapshot`in r&&r.androidSnapshot?.systemSurfaceOnly===!0?`unobservable`:`observable`}}catch(e){return n.throwIfAborted(),c(e)?{observation:`unobservable`}:{observation:`probe-failed`,failure:rr(e)}}}function rr(e){let n=t(e),r=s(n)??n.details?.reason;return typeof r==`string`?{code:n.code,reason:r}:{code:n.code}}function ir(e){let{host:t,device:n,signal:r}=e,i=qe({device:n,signal:r,resolveInteractor:t.localInteractors.resolve});return Object.freeze({resolveOpenTarget:async e=>await t.androidApplications.resolveOpenTarget(n,e),prepareApplicationOpen:async e=>{await z(t,n,{headless:!1,deadlineAtMs:e.execution.startupDeadlineAtMs},r)},openApplication:async e=>await ar(t,i,e),applyRuntimeHints:async e=>await t.androidApplications.applyRuntimeHints(n,e),clearRuntimeHints:async e=>await t.androidApplications.clearRuntimeHints(n,e),closeApplication:async e=>{e.ensureReady&&await z(t,n,{headless:!1},r),await Ge({device:n,interactor:await i.resolveInteractor(e.execution,e.appBundleId),positionals:e.positionals})},finalizeApplicationClose:async e=>{await t.androidApplications.restoreTestIme(n,{stateDir:e.stateDir});let i=e.shutdownTarget&&n.kind===`emulator`?await t.deviceShutdown.android.shutdownTarget(n,r):void 0;return i===void 0?{}:{shutdown:i}},prepareAppleRunner:sr,configureProviderPortReverse:sr})}async function ar(t,n,r){let i={};if(r.relaunch&&r.target){let e=Date.now();await Ge({device:n.device,interactor:await n.resolveInteractor(r.execution,r.appBundleId),positionals:[r.appBundleId??r.target]}),i.relaunchCloseDurationMs=V(e)}if(f(r.runtimeHints)){if(!r.applyRuntimeHints)throw new e(`COMMAND_FAILED`,`Runtime hint operation was not admitted for this open.`,{reason:`runtime-hints-operation-missing`});let t=Date.now();await r.applyRuntimeHints({appId:r.appBundleId,values:r.runtimeHints}),i.runtimeHintsDurationMs=V(t)}let a=Date.now();await Je({device:n.device,interactor:await n.resolveInteractor(r.execution,r.appBundleId),positionals:r.positionals,appBundleId:r.appBundleId,execution:r.execution}),i.openDispatchDurationMs=V(a),r.enableTestIme&&await t.androidApplications.activateTestIme(n.device,{stateDir:r.stateDir});let o=Ke(r);if(o){let e=Date.now();await Je({device:n.device,interactor:await n.resolveInteractor({...r.execution,clearAppState:void 0,launchConsole:void 0,launchArgs:void 0},r.appBundleId),positionals:[o],appBundleId:r.appBundleId,execution:{...r.execution,clearAppState:void 0,launchConsole:void 0,launchArgs:void 0}}),i.launchUrlDurationMs=V(e)}else i.launchUrlDurationMs=0;let s=await t.androidApplications.inferOpenedAppBundleId(n.device,r.target,r.appBundleId);s&&await t.androidApplications.resetFramePerfStats(n.device,s);let c=Date.now();return Object.assign(i,await or(n,r,s)),i.postOpenSettleDurationMs=V(c),{appBundleId:s,timing:i}}async function or(e,t,r){if(!t.target||n(t.target))return{};if(!r)return{postOpenObservation:`app-unidentified`};let i=await nr(await e.resolveInteractor(t.execution,r),r,e.signal);return i.observation===`probe-failed`?{postOpenObservation:`probe-failed`,postOpenObservationFailure:i.failure}:{postOpenObservation:i.observation}}function V(e){return Math.max(0,Date.now()-e)}async function sr(){throw new e(`UNSUPPORTED_OPERATION`,`This lifecycle operation is unavailable for Android.`)}async function H(e,t,n,r,i){U(n);let a=r?void 0:await W(e,t,i);if(x.extname(n).toLowerCase()===`.aab`?await dr(e,t,n,i):K(await e.androidTools.installPackage(t,n,{replace:!0},i),`adb install failed`),r)return r;let o=[...await W(e,t,i)].filter(e=>!a?.has(e));return o.length===1?o[0]:void 0}function U(t){if(b()&&x.extname(t).toLowerCase()===`.aab`)throw new e(`UNSUPPORTED_OPERATION`,`Managed Android deployment does not support app bundles.`,{reason:`managed-bundle-install-unavailable`,hint:`Install an APK on this managed device.`})}async function cr(e,t,n,r){let i=await G(e,t,[`uninstall`,n],r);if(i.exitCode===0)return;let a=`${i.stdout}\n${i.stderr}`.toLowerCase();a.includes(`unknown package`)||a.includes(`not installed`)||K(i,`adb uninstall failed for ${n}`)}async function lr(t,n,r,i){let a=r.payload,s=typeof a.action==`string`&&a.action.trim()?a.action.trim():`${r.appId}.TEST_PUSH`,c=[`am`,`broadcast`,`-a`,s,`-p`,r.appId];typeof a.receiver==`string`&&a.receiver.trim()&&c.push(`-n`,a.receiver.trim());let l=a.extras??{};if(typeof l!=`object`||!l||Array.isArray(l))throw new e(`INVALID_ARGS`,`Android push payload extras must be an object`);let u=0;for(let[e,t]of Object.entries(l))e&&(fr(c,e,t),u+=1);return K(await G(t,n,o(`adb`,`shell`,c),i),`adb push broadcast failed`),{action:s,extrasCount:u}}function ur(e){let t=new Set([`com`,`android`,`google`,`app`,`apps`,`service`,`services`,`mobile`,`client`]),n=e.split(/[._-]+/).map(e=>e.trim().toLowerCase()).filter(Boolean),r=[...n].reverse().find(e=>!t.has(e))??n.at(-1)??e;return r.charAt(0).toUpperCase()+r.slice(1)}async function dr(t,n,r,i){if(await t.androidTools.installBundle(n,r,`universal`,i))return;let a=await t.commands.which(`bundletool`),o=t.androidDeployment.bundletoolJar;if(!a&&!o)throw new e(`TOOL_MISSING`,`bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR.`);let s=a?`bundletool`:`java`,c=a?[]:[`-jar`,o],l=await t.temporaryFiles.create({prefix:`agent-device-aab-`,suffix:`.apks`}),u=l.path;try{K(await t.commands.run({executable:s,args:[...c,`build-apks`,`--bundle`,r,`--output`,u,`--mode`,`universal`]},i),`bundletool build-apks failed`),K(await t.commands.run({executable:s,args:[...c,`install-apks`,`--apks`,u,`--device-id`,n.id]},i),`bundletool install-apks failed`)}finally{await l[Symbol.asyncDispose]()}}async function W(e,t,n){let r=await G(e,t,o(`adb`,`shell`,[`pm`,`list`,`packages`]),n);return K(r,`adb package inventory failed`),new Set(r.stdout.split(`
|
|
5
|
+
`).map(e=>e.replace(`package:`,``).trim()).filter(Boolean))}function fr(t,n,r){if(typeof r==`string`)t.push(`--es`,n,r);else if(typeof r==`boolean`)t.push(`--ez`,n,String(r));else if(typeof r==`number`&&Number.isFinite(r))t.push(Number.isInteger(r)?`--ei`:`--ef`,n,String(r));else throw new e(`INVALID_ARGS`,`Unsupported Android broadcast extra type for "${n}". Use string, boolean, or number.`)}async function G(e,t,n,r,i=15e3){return await e.androidTools.runAdb(t,n,{timeoutMs:i,allowFailure:!0},r)}function K(t,n){if(t.exitCode===0)return;let r={stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode};throw new e(`COMMAND_FAILED`,n,r)}const pr=Object.freeze({available:!0});function mr(e){let t=vr(e);return Object.freeze({deployApp:t,materializeAppSource:t,deployMaterializedApp:t,sendPushNotification:t})}function hr(e){let{host:t,device:n,signal:r}=e;return mr(n).deployApp.available?Object.freeze({deployApp:async e=>await gr(t,n,e,r),materializeAppSource:async e=>await t.androidDeployment.prepareArtifact(e,{signal:r}),deployMaterializedApp:async e=>await _r(t,n,e,r),sendPushNotification:async e=>await lr(t,n,e,r)}):Object.freeze({})}async function gr(e,t,n,r){if(n.replaceExisting)return await e.androidDeployment.withInvalidatedAppResolutionCache(t,async()=>{let i;try{b()&&(i=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!1,signal:r}),U(i.installablePath)),t.booted!==!0&&await z(e,t,{headless:!1},r);let a=await e.androidDeployment.resolveAppPackage(t,n.app);return await cr(e,t,a,r),i??=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!1,signal:r}),await H(e,t,i.installablePath,void 0,r),{packageName:a,launchTarget:a}}finally{await i?.cleanup()}});let i;try{b()&&(i=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!0,signal:r}),U(i.installablePath)),t.booted!==!0&&await z(e,t,{headless:!1},r),i??=await e.androidDeployment.prepareArtifact({source:{kind:`path`,path:n.appPath}},{resolveIdentity:!0,signal:r});let a=await H(e,t,i.installablePath,i.packageName,r);return a?{packageName:a,appName:ur(a),launchTarget:a}:{}}finally{await i?.cleanup()}}async function _r(t,n,r,i){let a=await H(t,n,r.artifact.installablePath,r.artifact.packageName,i);if(!a)throw new e(`COMMAND_FAILED`,`Installed Android app identity could not be resolved from the artifact or device state`);return{packageName:a,appName:ur(a),launchTarget:a}}function vr(e){return e.kind===`emulator`||e.kind===`device`?pr:Object.freeze({available:!1,reason:`unsupported-device-kind`})}const q=i(`android`),J=Object.freeze({available:!0}),yr=Object.freeze({available:!1,reason:`unsupported-device-kind`}),br=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`focus is supported on Android emulators and physical devices.`}),xr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`keyboard actions are supported on Android emulators and physical devices.`}),Sr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`}),Cr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Android has no key event for this system button.`}),wr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`fold drives the hinge of a foldable iPhone simulator; the Android emulator posture control is not driven by agent-device yet.`}),Tr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Headless boot is supported only for Android emulators.`}),Er=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Android appstate is supported only for Android emulators and devices.`}),Dr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Apple runner preparation is supported only for Apple targets.`}),Or=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`open is supported only for Android emulators and devices.`}),kr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`close is supported only for Android emulators and devices.`}),Ar=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Runtime hints are supported only for Android emulators and devices.`}),jr=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Port reverse is supported only by an owning provider runtime.`}),Mr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`shutdown is supported only for Apple simulators and Android emulators.`}),Nr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`screenshot is supported only for Android emulators and devices.`}),Y=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`snapshot is supported only for Android emulators and devices.`}),Pr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`Re-run without --actions, or target an iOS simulator.`}),Fr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`viewport resizes web targets only (--platform web).`}),Ir=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:`the stateless audio page probe is a web-session operation; Android targets use the host capture.`});function Lr(e){let t=Rr(e),n=zr(e),r=Br(e);return p({resolveOpenTarget:t,prepareApplicationOpen:t,openApplication:t,applyRuntimeHints:r,clearRuntimeHints:r,closeApplication:n,finalizeApplicationClose:n,prepareAppleRunner:Dr,configureProviderPortReverse:jr})}function Rr(e){return e.kind===`emulator`||e.kind===`device`?J:Or}function zr(e){return e.kind===`emulator`||e.kind===`device`?J:kr}function Br(e){return e.kind===`emulator`||e.kind===`device`?J:Ar}const X=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`Gestures are supported on Android emulators and physical devices.`}),Vr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:Le}),Hr=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:Ie});function Ur(e,t){return e.kind===`simulator`?X:e.target===`tv`?t:J}function Z(e){return e.kind===`simulator`?X:J}function Q(e){return e.kind===`simulator`?br:J}const $=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:Fe}),Wr=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`Could not determine whether this Android build supports a shell clipboard: the adb probe did not complete. Retry once the device is reachable.`});async function Gr(e,t){let n=e.androidTools?.probeClipboardShellSupport;return n?await n.call(e.androidTools,t):`probe-failed`}const Kr=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`tv-remote is supported only on Android TV targets.`});function qr(e){return e.kind!==`simulator`&&e.target===`tv`?J:Kr}function Jr(e){let t=nt(e),n=new Map,r=async t=>{if(t.kind===`simulator`)return $;let r=n.get(t.id)??await Gr(e,t);return r!==`probe-failed`&&n.set(t.id,r),r===`supported`?J:r===`unsupported`?$:Wr},i=async e=>{let n=await t.inspectFacts(e),i=mr(e),a=await r(e);return Object.freeze({device:n.device,operations:{...n.operations,...i,appState:e.kind===`simulator`?Er:J,networkDump:J,screenRecordingStart:J,screenRecordingReattach:J,screenRecordingCleanup:J,...te({capture:e.kind===`simulator`?Y:J,customActions:Pr,withoutActiveApp:e.kind===`simulator`?Y:J}),...ie({capture:e.kind===`simulator`?Nr:J}),...oe({findText:Y}),...h({setViewport:Fr}),...he({focus:Q(e)}),...re({unsupported:X,plan:Z(e),directionalFling:Z(e),multiTouch:Ur(e,Vr),targetAuthoredDrag:Ur(e,Hr),viewport:Z(e)}),...ae({scroll:Z(e)}),...m({type:Q(e)}),...ve({unsupported:br,tap:Q(e),longPress:Q(e),hover:Sr,fill:Q(e)}),...ee({readTextAtPoint:e.kind===`simulator`?yr:J}),...pe({back:Q(e)}),...se({unsupported:Cr,home:Q(e),appSwitcher:Q(e)}),setFoldPose:wr,...de({triggerAppEvent:Q(e)}),...ue({setSetting:Q(e),readSetting:Q(e)}),...le({read:Q(e),wait:Q(e),accept:Q(e),dismiss:Q(e)}),...g({orientation:Q(e)}),...me({tvRemote:qr(e)}),...fe({unsupported:xr,status:Q(e),dismiss:Q(e),enter:Q(e)}),...ce({unsupported:a.available?$:a,read:a,write:a}),...ge({capture:Ye(e),query:Ir}),..._e({frames:Q(e),memorySample:Q(e),memorySnapshot:Q(e),nativeCapture:Q(e),profileReport:Q(e)}),ensureReady:J,bootTarget:J,bootTargetHeadless:e.kind===`emulator`?J:Tr,listApps:J,...Lr(e),shutdownTarget:e.kind===`emulator`?J:Mr}})};return Object.freeze({owner:q,ownsDevice:e=>e.platform===`android`,inspectFacts:i,bind:async n=>{let r=await t.bind(n),o=await i(n.device),s=await Un({host:e,device:n.device,owner:q,signal:n.scope.signal});return Object.freeze({device:r.device,owner:q,facts:o,operations:Object.freeze({...r.operations,...hr({host:e,device:n.device,signal:n.scope.signal}),...o.operations.appState.available?{appState:async()=>{n.scope.signal.throwIfAborted();let{runAndroidAdb:e}=await import(`./adb.js`).then(e=>e.t);return await Pe(async(t,r)=>await e(n.device,t,{...r,signal:n.scope.signal}),n.scope.signal)}}:{},networkDump:async t=>await at(e,n.device,t,n.scope.signal),...s,...a(o.operations.audioProbeStart,()=>Ce({host:e.audioProbe.hostCapture,device:n.device,owner:q})),...a(o.operations.perfFrames,()=>Xe({resolveHost:()=>e.perf.android,device:n.device,owner:q})),...Yr(e,n,o),ensureReady:async t=>await z(e,n.device,{...t,headless:!1},n.scope.signal),bootTarget:async t=>await z(e,n.device,{...t,headless:!1},n.scope.signal),...o.operations.bootTargetHeadless.available?{bootTargetHeadless:async t=>await z(e,n.device,{...t,headless:!0},n.scope.signal)}:{},listApps:async e=>{n.scope.signal.throwIfAborted();let{listAndroidApps:t}=await import(`./app-lifecycle.js`).then(e=>e.t);return(await t(e.device,e.filter)).map(e=>({id:e.package,name:e.name}))},...d(ir({host:e,device:n.device,signal:n.scope.signal}),o.operations),...o.operations.shutdownTarget.available?{shutdownTarget:async()=>await e.deviceShutdown.android.shutdownTarget(n.device,n.scope.signal)}:{}}),[Symbol.asyncDispose]:async()=>await r[Symbol.asyncDispose]()})},shutdown:async()=>await t.shutdown()})}function Yr(e,t,n){let r={device:t.device,signal:t.scope.signal,resolveInteractor:e.localInteractors.resolve};return{...n.operations.captureSnapshot.available?ne(r):{},...Re({...r,facts:n.operations,pause:async n=>await e.clock.sleep(n,t.scope.signal)})}}export{Jr as createAndroidPlatformRuntime};
|
package/dist/src/runtime3.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{U as e}from"./sdk-contracts.js";function t(e){return Object.freeze({canShutdownTarget:n,shutdownTarget:async(t,n)=>await r(e.commands,t,n)})}function n(e){return e.platform===`android`&&e.kind===`emulator`}async function r(t,n,r){if(n.booted===!1)return i();r.throwIfAborted();try{let e=await t.run({executable:`adb`,args:[`-s`,n.id,`emu`,`kill`],allowFailure:!0,timeoutMs:15e3},r);r.throwIfAborted();let i=e.exitCode??-1;return{success:i===0,exitCode:i,stdout:e.stdout,stderr:e.stderr}}catch(t){r.throwIfAborted();let n=e(t);return{success:!1,exitCode:-1,stdout:``,stderr:n.message,error:n}}}function i(){return{success:!0,exitCode:0,stdout:``,stderr:``}}export{t as createAndroidShutdownRuntime};
|