agent-device 0.20.9 → 0.20.10
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.20.9.apk → agent-device-android-ime-helper-0.20.10.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.10.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.manifest.json → agent-device-android-ime-helper-0.20.10.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.apk → agent-device-android-snapshot-helper-0.20.10.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.manifest.json → agent-device-android-snapshot-helper-0.20.10.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +6 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +4 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +94 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +22 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +3 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +10 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +30 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +8 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +133 -63
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +13 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentation.swift +183 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationTests.swift +0 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +20 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +19 -0
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.d.ts +61 -0
- package/dist/src/ai-sdk.js +1 -0
- package/dist/src/android-adb.d.ts +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/apps.js +5 -5
- package/dist/src/audio-probe.js +1 -1
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +30 -23
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +7 -7
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +1582 -0
- package/dist/src/command-tools.js +2 -0
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/debug-symbols.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/dispatch.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/helper-package-install.js +1 -1
- package/dist/src/helper.js +1 -1
- package/dist/src/ime-lifecycle.js +1 -1
- package/dist/src/ime-recovery-marker.js +1 -1
- package/dist/src/index.d.ts +2 -1578
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions3.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-common.js +1 -1
- package/dist/src/interaction-runtime.js +1 -1
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +2 -2
- package/dist/src/internal/daemon.js +4 -4
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun.d.ts +10 -2
- package/dist/src/linux.js +1 -1
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/{screenshot-geometry.js → mobile-snapshot-semantics.js} +1 -1
- package/dist/src/perf.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +4 -4
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/png-resize.js +1 -1
- package/dist/src/provider.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/registry.js +27 -27
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +5 -5
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-sequence.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +3 -3
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/screenshot-result.js +4 -4
- package/dist/src/screenshot.js +1 -1
- package/dist/src/script-source-bundle.js +16 -0
- package/dist/src/sdk-android-adb.d.ts +40 -40
- package/dist/src/sdk-android-adb.js +4 -4
- package/dist/src/sdk-batch-runner.js +3 -3
- package/dist/src/sdk-contracts.d.ts +122 -85
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-selectors.d.ts +89 -77
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +10 -3
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session2.js +7 -8
- package/dist/src/shared.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-scope.js +1 -0
- package/dist/src/snapshot.js +6 -6
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -1
- package/dist/src/src4.js +1 -0
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/verified-file.js +1 -1
- package/dist/src/web.js +1 -1
- package/package.json +21 -8
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +0 -1
- package/dist/src/cancel.js +0 -1
- package/dist/src/prepare-kind.js +0 -15
- package/dist/src/selector-vocabulary.js +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{E as e,_ as t,n}from"./sdk-contracts.js";import{Fr as r,f as i,p as a,x as o}from"./sdk-batch-runner.js";import{i as s,t as c}from"./sdk-device.js";import{Nt as l,Pt as u,jt as ee,pn as te}from"./script-source-bundle.js";import{_ as d,g as f,h as p,s as m,v as h}from"./registry.js";import{t as g}from"./session.js";import{i as ne,n as _,t as v}from"./command-metadata.js";import{t as y}from"./cli-output.js";import{n as b,r as re,t as ie}from"./cli-config.js";const x=[`simulator`,`emulator`,`device`];function S(e){return{type:`number`,...e?{description:e}:{}}}function C(e,t){return{type:`string`,enum:e,...t?{description:t}:{}}}function w(e){return{type:`string`,const:e}}function T(e){return{type:[`string`,`null`],...e?{description:e}:{}}}function E(e,t=[],n){return{type:`object`,...n?{description:n}:{},properties:e,...t.length>0?{required:t}:{}}}const D={type:`array`,items:{type:`string`}},O=E({wallClockMs:S(`Total wall-clock time for the request in milliseconds.`),runnerRoundTrips:S(`Number of real runner round-trips made while serving the request.`),nodeCount:S(`Number of nodes in the original node tree when the response carries one.`)},[`wallClockMs`,`runnerRoundTrips`]),k=E({field:h(),artifactType:h(),path:h(),localPath:h(),fileName:h()},[`field`]);function A(e={}){let t=e.properties??{},n=e.required??[];return E({targetKind:C([`point`,`ref`,`selector`],`Resolved interaction target kind.`),x:S(`Resolved interaction x coordinate when available.`),y:S(`Resolved interaction y coordinate when available.`),referenceWidth:S(`Reference frame width for visualizing the interaction point.`),referenceHeight:S(`Reference frame height for visualizing the interaction point.`),ref:h(`Snapshot ref without the @ prefix when the target was an @ref.`),selector:h(`Selector expression when the target was a selector.`),selectorChain:D,refLabel:h(),targetHittable:f(),hint:h(),warning:h(),message:h(),evidence:N,resolution:M,cost:O,maestroNonHittableCoordinateFallbackAllowed:f(`Whether the direct iOS Maestro coordinate fallback was allowed for this selector.`),maestroNonHittableCoordinateFallbackUsed:f(`Whether the direct iOS Maestro coordinate fallback was actually used.`),maestroFallbackReason:w(`non-hittable-coordinate`),...t},[`targetKind`,...n])}const j=E({diagnosticRef:h(`Opaque non-@ diagnostic token. Never a snapshot ref: not issued via refsGeneration and cannot be pinned or reused as an @ref target. UTF-8 truncated to 256 bytes.`),role:h(`UTF-8 truncated to 256 bytes.`),label:h(`UTF-8 truncated to 256 bytes.`)},[`diagnosticRef`]),M={type:`object`,description:`Pre-action disclosure of how the acting path resolved its target. Absent when resolutionDisclosure is inapplicable for the path.`,oneOf:[E({source:w(`runtime`),phase:w(`pre-action`),kind:w(`unique`)},[`source`,`phase`,`kind`]),E({source:w(`runtime`),phase:w(`pre-action`),kind:w(`disambiguated`),matchCount:S(`Total matches resolveSelectorChain found before disambiguation.`),winnerDiagnostic:j,tiebreak:C([`visible`,`deepest`,`smallest-area`,`structural-equivalence`],`The comparison that decided the winner.`),alternatives:{type:`array`,description:`At most 5 losing candidates, document order. Present at default/full response levels and omitted in digest. The winner is never included.`,items:j}},[`source`,`phase`,`kind`,`matchCount`,`winnerDiagnostic`,`tiebreak`]),E({source:w(`ref`),phase:w(`pre-action`),kind:w(`exact`)},[`source`,`phase`,`kind`]),E({source:w(`ref`),phase:w(`pre-action`),kind:w(`label-fallback`)},[`source`,`phase`,`kind`]),E({source:w(`direct-ios`),kind:w(`not-observed`)},[`source`,`kind`])]},N=E({foregroundApp:h(`Foreground app bundle id or name, when the capture carries it.`),nodeCount:S(`Node count in the post-action interactive-only capture.`),interactiveNodeCount:S(`Subset of nodeCount the platform reports as hittable.`),digest:h(`Order-independent digest of the post-action node multiset.`),changedFromBefore:f(`Whether the post-action digest differs from the pre-action capture digest. false is evidence, not failure.`)},[`nodeCount`,`interactiveNodeCount`,`digest`,`changedFromBefore`]),P=E({settled:f(`Whether the UI held the quiet window before the deadline. false is advisory, not failure.`),waitedMs:S(),captures:S(),quietMs:S(),timeoutMs:S(),refsGeneration:S(`Snapshot generation of the stored settled tree; refs on added diff lines were minted from it.`),refs:{type:`array`,items:E({ref:h(`Plain ref body (e12) minted from the stored settled tree.`)},[`ref`])},diff:E({summary:E({additions:S(),removals:S(),unchanged:S()},[`additions`,`removals`,`unchanged`]),lines:{type:`array`,items:E({kind:C([`added`,`removed`]),text:h(),ref:h(`Plain ref body (e12) for added lines.`)},[`kind`,`text`])},truncated:f(`Lines were capped to the response bound.`)},[`summary`,`lines`],`Settled diff vs the pre-action tree (changed lines only).`),tail:{type:`array`,description:`Unchanged interactive refs tail: still-present, actionable elements from the settled tree, attached only when diff carries zero added-line refs (a modal-dismiss/toast-only diff).`,items:E({ref:h(`Plain ref body (e12) minted from the stored settled tree.`),role:h(),label:h()},[`ref`,`role`])},tailTruncated:f(`Present (true) when tail candidates exceeded the response cap.`),hint:h()},[`settled`,`waitedMs`,`captures`,`quietMs`,`timeoutMs`]),F={platform:C(s),target:C(c),device:h(`Human-readable device name.`),id:h(`Stable device id.`),kind:C(x)},I=[`platform`,`target`,`device`,`id`,`kind`],ae=E({success:f(),exitCode:S(),stdout:h(),stderr:h(),error:d(`Normalized error detail when shutdown failed.`)},[`success`,`exitCode`,`stdout`,`stderr`]);function oe(e){return{...e,properties:{...e.properties??{},settle:P}}}const L=A({properties:{evidence:N,settle:P,button:C([`secondary`,`middle`]),count:S(`Number of press/click repetitions.`),intervalMs:S(`Delay between repeated press/click actions.`),holdMs:S(`Hold duration for each action.`),jitterPx:S(`Randomization radius in pixels.`),doubleTap:f(`Whether the command requested a double-tap action.`)}}),R={text:h(`Text submitted to the field.`),delayMs:S(`Delay between typed characters in milliseconds.`),evidence:N,settle:P},z=E({resourceId:T(`Android resource id of the exact field that changed.`),className:T(`Android class name of the exact field that changed.`),packageName:T(`Android package name that owns the exact field.`),rect:E({x:S(),y:S(),width:S(),height:S()},[`x`,`y`,`width`,`height`],`Screen-space rectangle of the exact field that changed.`)},[`resourceId`,`className`,`packageName`,`rect`],`Target identity captured before fill and matched after fill.`),B={press:L,click:L,fill:{type:`object`,description:`Fill response. Android may return target-bound unconfirmed evidence when the exact app-owned field changed but formatting prevented raw equality.`,oneOf:[{...A({properties:R,required:[`text`]}),not:E({},[`verification`])},A({properties:{...R,verification:w(`unconfirmed`),requested:h(`Literal text requested by the fill command.`),before:T(`Raw target text captured before the fill.`),after:T(`Raw target text captured after the fill.`),target:z},required:[`text`,`verification`,`requested`,`before`,`after`,`target`]})]},longpress:A({properties:{durationMs:S(),settle:P,gesture:w(`longpress`)}}),hover:A({properties:{settle:P,gesture:w(`hover`)}}),find:E({ref:h(`Snapshot ref without the @ prefix when the find action returns one.`),refsGeneration:S(`ADR 0014 ref frame epoch for read-only find actions.`),found:f(`Whether a wait/exists/read-only find satisfied its condition.`),waitedMs:S(`Milliseconds waited for a read-only find condition.`),text:h(`Text value returned by find get_text.`),node:d(`Snapshot node for find get_attrs/get_text.`),matches:{type:`array`,description:`Every match for the read-only find list action (#1625): { ref, node } each.`,items:d(`One listed match with its snapshot ref and node.`)},locator:h(`Locator kind used for the find action.`),query:h(`Query argument used for the find action.`),x:S(`Resolved x coordinate for mutating find actions.`),y:S(`Resolved y coordinate for mutating find actions.`),message:h(`Diagnostic message for mutating find actions.`),settle:P,cost:O},[],`Daemon response data for the find command.`),boot:E({...F,booted:{type:`boolean`,const:!0}},[...I,`booted`]),shutdown:E({...F,shutdown:ae},[...I,`shutdown`]),viewport:E({width:S(),height:S(),message:h()},[`width`,`height`,`message`]),...m,back:oe(m.back),wait:E({waitedMs:S(),kind:w(`selector`),text:h(),selector:h(),captures:S(),nodeCount:S(),hint:h(),warning:h()},[`waitedMs`]),prepare:E({action:w(`ios-runner`),platform:C(s),deviceId:h(),deviceName:h(),kind:C(x),durationMs:S(),runner:E({},[]),cache:C([`exact`,`restore-key`,`miss`,`external`]),artifact:C([`valid`,`rebuilt`]),buildMs:S(),connectMs:S(),healthCheckMs:S(),xctestrunPath:h(),recoveryReason:h(),failureReason:h(),timing:E({totalMs:S(),additiveParts:E({buildMs:S(),connectAfterBuildMs:S(),healthCheckMs:S()},[`connectAfterBuildMs`,`healthCheckMs`]),containment:E({connectMs:{type:`array`,items:w(`buildMs`)},healthCheckMs:{type:`array`,items:h()}},[`healthCheckMs`]),note:h()},[`totalMs`,`additiveParts`,`containment`,`note`]),message:h()},[`action`,`platform`,`deviceId`,`deviceName`,`kind`,`durationMs`,`runner`,`connectMs`,`healthCheckMs`,`timing`,`message`]),push:{type:`object`,oneOf:[E({platform:w(`ios`),bundleId:h(),message:h()},[`platform`,`bundleId`,`message`]),E({platform:w(`android`),package:h(),action:h(),extrasCount:S(),message:h()},[`platform`,`package`,`action`,`extrasCount`,`message`])]},"trigger-app-event":E({event:h(),eventUrl:h(),transport:w(`deep-link`),message:h()},[`event`,`eventUrl`,`transport`,`message`]),clipboard:{type:`object`,oneOf:[E({action:w(`read`),text:h()},[`action`,`text`]),E({action:w(`write`),textLength:S(),message:h()},[`action`,`textLength`,`message`])]},appstate:{type:`object`,oneOf:[E({platform:C([`ios`,`macos`]),appName:h(),appBundleId:h(),source:w(`session`),surface:C(g),device_udid:h(`iOS only — the session device UDID.`),ios_simulator_device_set:{type:[`string`,`null`],description:`iOS only — the simulator set path, or null when unknown.`}},[`platform`,`appName`,`source`,`surface`]),E({platform:w(`android`),package:h(),activity:h()},[`platform`,`package`,`activity`])]},keyboard:E({platform:C([`android`,`ios`]),action:C([`status`,`dismiss`,`enter`]),visible:f(),wasVisible:f(),dismissed:f(),attempts:S(),inputType:h(),type:C([`text`,`number`,`email`,`phone`,`password`,`datetime`,`unknown`]),inputMethodPackage:h(),focusedPackage:h(),focusedResourceId:h(),inputOwner:C([`app`,`ime`,`unknown`]),message:h()},[`platform`,`action`]),doctor:E({status:C([`pass`,`warn`,`fail`,`info`]),summary:h(),kind:C([`auto`,`react-native`,`expo`,`repack`]),platform:h(),target:C(c),targetApp:h(),metro:E({host:h(),port:S()},[`host`,`port`]),checks:{type:`array`,items:E({id:h(),status:C([`pass`,`warn`,`fail`,`info`]),summary:h(),hint:h(),command:h(),evidence:d()},[`id`,`status`,`summary`])}},[`status`,`summary`,`kind`,`checks`]),diff:E({mode:w(`snapshot`),baselineInitialized:f(),summary:E({additions:S(),removals:S(),unchanged:S()},[`additions`,`removals`,`unchanged`]),lines:{type:`array`,items:E({kind:C([`added`,`removed`]),text:h(),ref:h()},[`kind`,`text`])},warnings:D},[`mode`,`baselineInitialized`,`summary`,`lines`]),replay:E({replayed:S(),healed:S(),session:h(),sessionActive:f(`True iff the session is still active — the script had no terminal close.`),artifactPaths:D,snapshotDiagnostics:d(),message:h()},[`replayed`,`healed`,`session`,`sessionActive`,`artifactPaths`,`message`]),test:E({total:S(),executed:S(),passed:S(),failed:S(),skipped:S(),notRun:S(),durationMs:S(),failures:{type:`array`,items:d()},tests:{type:`array`,items:d()},snapshotDiagnostics:d()},[`total`,`executed`,`passed`,`failed`,`skipped`,`notRun`,`durationMs`,`failures`,`tests`]),record:{type:`object`,oneOf:[E({recording:w(`started`),outPath:h(),sessionStateDir:h(),recordingBackend:h(),recordingScope:h(),recordOnlySession:f(),activeSessionApp:d(),showTouches:f()},[`recording`,`outPath`,`sessionStateDir`,`showTouches`]),E({recording:w(`stopped`),outPath:h(),telemetryPath:h(),artifacts:{type:`array`,items:k},recordingBackend:h(),recordingScope:h(),recordOnlySession:f(),activeSessionApp:d(),durationMs:S(),showTouches:f(),warning:h(),overlayWarning:h(),chunks:{type:`array`,items:d()}},[`recording`,`outPath`,`artifacts`,`durationMs`,`showTouches`])]},trace:{type:`object`,oneOf:[E({trace:w(`started`),outPath:h()},[`trace`,`outPath`]),E({trace:w(`stopped`),outPath:h(),artifacts:{type:`array`,items:k}},[`trace`,`outPath`,`artifacts`])]}},V={devices:{type:`object`,properties:{devices:{type:`array`,items:{type:`object`,properties:{platform:{type:`string`,enum:s},target:{type:`string`,enum:c},kind:{type:`string`,enum:x},id:{type:`string`},name:{type:`string`}},required:[`platform`,`target`,`kind`,`id`,`name`]}}},required:[`devices`]},apps:{type:`object`,properties:{apps:{type:`array`,items:{type:`string`}}},required:[`apps`]}},H={...B,...V};function U(t){return e(t)}function W(e){let t=[`Error (${e.code}): ${e.message}`];e.hint&&t.push(`Hint: ${e.hint}`),t.push(...l(e.details)),e.supportedOn&&t.push(`Supported on: ${e.supportedOn}`);let n=ee(e.details);return n&&t.push(n),t.join(`
|
|
2
|
+
`)}function G(e,t,n){let r=ie({command:e,cwd:process.cwd(),cliFlags:t}),i={};for(let[t,a]of Object.entries(r))Object.hasOwn(n,t)&&re(t,e)&&(i[t]=a);return b(i,t)}const K={devices:e=>({devices:e.map(te)}),apps:e=>({apps:e})};function q(e,t){let n=K[e];return n?n(t):t}function se(){let e=new Map;return{pinInput:(t,n,r)=>xe(t,n,fe(e,r,n.session)),mergeCommandResult:(t,n,r,i)=>pe(e,t,n,r,i),mergeErrorDetails:(t,n,r)=>{let i=J(n,r);ce(e,i,t),ye(e,i,t)}}}function ce(e,t,n){let r=n?.refsGeneration;typeof r==`number`&&Y(e,t,u(n),r)}const le=new Set([`snapshot`,`find`]),ue=new Set(i.map(e=>e.name).filter(_).filter(e=>a(e))),de=new Set([`press`,`click`,`fill`,`longpress`,`hover`,`get`]);function fe(e,t,n){return e.get(J(t,n))}function J(e,t){let n=typeof t==`string`&&t.length>0?t:`default`;return`${e??``}\u0000${n}`}function pe(e,t,n,r,i){let a=J(r,i);if(ue.has(t)){ge(e,a,_e(n));return}le.has(t)&&(t===`find`?he(e,a,n):me(e,a,n))}function me(e,t,n){let r=n.refsGeneration;if(typeof r!=`number`){e.delete(t);return}let i=[];for(let{ref:e}of n.refs??[])i.push(e);for(let e of n.nodes??[])i.push(e.ref);Y(e,t,i,r)}function he(e,t,n){let r=n.refsGeneration;if(typeof r!=`number`)return;let i=[];typeof n.ref==`string`&&n.ref.startsWith(`@`)&&i.push(n.ref.slice(1));for(let e of n.matches??[])typeof e.ref==`string`&&e.ref.length>0&&i.push(e.ref.startsWith(`@`)?e.ref.slice(1):e.ref);Y(e,t,i,r)}function ge(e,t,n){n?.refsGeneration!==void 0&&Y(e,t,[...n.diff?.lines??[],...n.refs??[],...n.tail??[]].map(e=>e.ref).filter(e=>typeof e==`string`),n.refsGeneration)}function _e(e){let t=e.settle;return typeof t==`object`&&t?t:void 0}function Y(e,t,n,r){if(n.length===0)return;let i=e.get(t)??new Map;e.set(t,i),ve(i,n,r)}function ve(e,t,n){for(let r of t)e.delete(r),e.set(r,n);for(;e.size>1e3;)e.delete(e.keys().next().value)}function ye(e,t,n){let i=r(r(n?.divergence)?.screen);if(i?.state!==`available`)return;let a=i.refsGeneration;if(typeof a!=`number`)return;let o=[];be(i.refs,o),Y(e,t,o,a)}function be(e,t){if(Array.isArray(e))for(let n of e){let e=r(n)?.ref;typeof e==`string`&&e.length>0&&t.push(e)}}function xe(e,t,n){return n===void 0||n.size===0?t:e===`wait`?Se(t,n)??t:de.has(e)?Ce(t,n)??t:t}function Se(e,t){if(typeof e.ref!=`string`)return;let n=X(e.ref,t);return n===e.ref?void 0:{...e,ref:n}}function Ce(e,t){let n=r(e.target);if(n?.kind!==`ref`||typeof n.ref!=`string`)return;let i=X(n.ref,t);return i===n.ref?void 0:{...e,target:{...n,ref:i}}}function X(e,t){if(!e.startsWith(`@`)||e.includes(`~`))return e;let n=t.get(e.slice(1));return n===void 0?e:`${e}~s${n}`}function we(){return ne().map(e=>{let t=e.name in H?H[e.name]:void 0;return{name:e.name,description:p(e),inputSchema:Q(e.name,e.inputSchema),...t?{outputSchema:t}:{}}})}function Z(e={}){let n=se();return{execute:async(r,i)=>{if(!_(r))throw new t(`INVALID_ARGS`,`Unknown command tool: ${r}`);let a=Q(r,v(r).inputSchema).properties,o=G(r,i,a),s=ke(o),c=Ne(o),l=n.pinInput(r,c,s.client.stateDir),u=await De(e,s.client);try{let t=await(e.runCommand??Oe)(u,r,l);return n.mergeCommandResult(r,t,s.client.stateDir,c.session),{isError:!1,structuredContent:q(r,t),content:[{type:`text`,text:Pe({name:r,input:c,result:t,outputFormat:s.outputFormat,responseLevel:s.client.responseLevel})}]}}catch(e){return Te(e,n,s.client.stateDir,c.session)}}}}function Te(e,t,n,r){let i=U(e);return t.mergeErrorDetails(i.details,n,r),{isError:!0,structuredContent:i,content:[{type:`text`,text:W(i)}]}}const Ee=Z();async function De(e,t){if(e.createClient)return await e.createClient(t);let{createAgentDeviceClient:n}=await import(`./agent-device-client.js`).then(e=>e.t);return n(t)}async function Oe(e,t,n){return await(await import(`./command-surface.js`).then(e=>e.t)).runCommand(e,t,n)}function ke(e){return{client:Ae(e),outputFormat:Me(e.mcpOutputFormat)}}function Ae(e){let n=e.stateDir,r=e.includeCost,i=e.responseLevel,a={};if(n!==void 0){if(typeof n!=`string`||n.length===0)throw new t(`INVALID_ARGS`,`Expected stateDir to be a non-empty string.`);a.stateDir=n}if(r!==void 0){if(typeof r!=`boolean`)throw new t(`INVALID_ARGS`,`Expected includeCost to be a boolean.`);r&&(a.cost=!0)}let o=je(i);return o!==void 0&&(a.responseLevel=o),a}function je(e){if(e===void 0)return;let r=n.find(t=>t===e);if(r===void 0)throw new t(`INVALID_ARGS`,`Expected responseLevel to be one of 'digest', 'default', or 'full'.`);return r}function Me(e){if(e===void 0)return`optimized`;if(e!==`optimized`&&e!==`json`)throw new t(`INVALID_ARGS`,`Expected mcpOutputFormat to be "optimized" or "json".`);return e}function Ne(e){let{stateDir:t,mcpOutputFormat:n,includeCost:r,responseLevel:i,...a}=e;return a}function Q(e,t){let n=o(e);return{...t,properties:{...t.properties,...n&&!t.properties?.noRecord?{noRecord:{type:`boolean`,description:`Do not record this action.`}}:{},stateDir:{type:`string`,description:`Agent-device state directory.`},mcpOutputFormat:{type:`string`,enum:[`optimized`,`json`],description:`MCP text content format. Defaults to optimized agent-friendly text; use json for JSON text. Structured content is always returned separately.`},includeCost:{type:`boolean`,description:`Include per-command agent-cost (cost.wallClockMs, …) in structuredContent. Defaults to off; the default response shape is unchanged.`},responseLevel:{type:`string`,enum:[`digest`,`default`,`full`],description:`Response verbosity: token-cheap digest / default (today) / full. Defaults to default; the default response shape is unchanged.`}}}}function Pe(e){if(e.outputFormat===`json`||e.responseLevel!==void 0&&e.responseLevel!=="default")return $(e.result);let t=y({name:e.name,input:e.input,result:e.result});return typeof t?.text==`string`?t.text:$(t?.data??e.result)}function $(e){return typeof e==`string`?e:JSON.stringify(e,null,2)}export{U as a,W as i,Z as n,we as r,Ee as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{_ as t,a as n,b as r,c as i}from"./sdk-device.js";import{Kt as a,Xt as o,Yt as s,t as c}from"./prepare-kind.js";import{_ as l}from"./screenshot-result.js";import{n as u,t as d}from"./command-catalog.js";import{t as f}from"./sdk-remote-config.js";import{A as p,x as m}from"./sdk-android-adb.js";import{v as h}from"./url.js";import{a as g,i as _}from"./client-metro.js";import{n as ee}from"./metro2.js";import{n as te,r as v,t as ne}from"./remote-config2.js";import{a as y,i as b}from"./src2.js";import x from"node:path";import S from"node:crypto";import C from"node:fs";const w={slug:`react-devtools-companion`,runArg:h,displayName:`React DevTools companion`};async function T(e){return await _({...e,definition:w,localBaseUrl:e.localBaseUrl??`http://127.0.0.1:8097`,registerPath:`/api/react-devtools/companion/register`,unregisterPath:`/api/react-devtools/companion/unregister`,devicePort:e.devicePort??8097})}async function E(e){return await g({...e,definition:w})}function D(e){return e===`android-instance`||e===`ios-instance`}function re(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function ie(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function O(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!ie(e)}function ae(e){let t=new URL(e);t.search=``,t.hash=``;let n=t.pathname.replace(/\/+$/,``);return t.pathname=n.endsWith(`/index.bundle`)?n.slice(0,-13)||`/`:n||`/`,t.toString().replace(/\/+$/,``)}function oe(e){let t=e?.metroPublicBaseUrl?.trim();return t?ae(t):null}function se(t,n={}){if(!O(t)||!n.flags?.metroProxyBaseUrl||!D(n.flags.leaseBackend))return t;let r=oe(n.flags);if(!r)throw new e(`INVALID_ARGS`,`cdp remote bridge target discovery requires a React Native dev-server public base URL.`,{hint:`Include metroPublicBaseUrl in the remote config so cdp can reach the local or tunneled Metro/Re.Pack CDP endpoint without bridge proxy authentication.`});return[...t,`--url`,r]}async function ce(e,t={}){return(await m(`npm`,re(se(e,t)),{cwd:t.cwd??process.cwd(),env:t.env??process.env,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode}function k(e){let t=P(e);if(!C.existsSync(t))return null;let n;try{n=JSON.parse(C.readFileSync(t,`utf8`))}catch(t){return z(e,t),null}return me(n)?n:(z(e),null)}function A(e){let t=P({stateDir:e.stateDir,session:e.state.session});C.mkdirSync(x.dirname(t),{recursive:!0}),R(t,e.state),R(F(e.stateDir),{session:e.state.session})}function j(e){return{baseUrl:pe(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function M(e){C.rmSync(P(e),{force:!0});let t=F(e.stateDir);L(e.stateDir)===e.session&&C.rmSync(t,{force:!0})}function le(t){let n=t.validateRemoteConfigHash??!0,r=t.remoteConfig?te({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}):void 0,i=k(t)??(t.allowActiveFallback?I({stateDir:t.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&N(i.remoteConfigPath)!==i.remoteConfigHash)throw new e(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let c=fe(i,t),l=a(i);return{runtime:i.runtime,connection:o(l),flags:{...c,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??c.daemonBaseUrl,daemonAuthToken:c.daemonAuthToken,daemonTransport:i.daemon?.transport??c.daemonTransport,daemonServerMode:i.daemon?.serverMode??c.daemonServerMode,...s(l),sessionIsolation:`tenant`,session:i.session,platform:i.platform??c.platform,target:i.target??c.target}}}function ue(e){return o(a(e))}function N(t){try{return S.createHash(`sha256`).update(C.readFileSync(t)).digest(`hex`)}catch(n){throw new e(`INVALID_ARGS`,`Remote config file not found: ${t}`,{cause:n instanceof Error?n.message:String(n)})}}function P(e){return x.join(e.stateDir,`remote-connections`,`${B(e.session)}.json`)}function F(e){return x.join(e,`remote-connections`,`.active-session.json`)}function I(e){let t=L(e.stateDir);return t?k({stateDir:e.stateDir,session:t}):null}function L(e){let t=F(e);if(C.existsSync(t))try{let e=JSON.parse(C.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function de(e){if(e)return S.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function fe(e,t){try{return v({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function R(e,t){let n=`${e}.${process.pid}.${S.randomUUID()}.tmp`;try{C.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),C.renameSync(n,e)}catch(e){throw C.rmSync(n,{force:!0}),e}}function pe(e){if(!e)return;let t=new URL(e);t.username=``,t.password=``;for(let e of[...t.searchParams.keys()])/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,``)}function z(e,t){p({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),M(e)}function B(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${S.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function me(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&he(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&ge(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&_e(t.daemon)}function he(e,t){return t.every(t=>typeof e[t]==`string`)}function ge(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function _e(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:ve(e)}function ve(e){let t=e;return(t.baseUrl===void 0||typeof t.baseUrl==`string`)&&(t.authToken===void 0||typeof t.authToken==`string`)&&(t.transport===void 0||typeof t.transport==`string`)&&(t.serverMode===void 0||typeof t.serverMode==`string`)}const ye=f.map(e=>e.key);function V(e){let t={};for(let n of ye){let r=e[n];r!==void 0&&(t[n]=r)}return t}function be(e){return e.remoteConfig?{...V(v({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function xe(e){return e===`cloud`||e===`proxy`||H(e)}function H(e){return e===`limrun`||y(e)}function Se(){return[`cloud`,`proxy`,b.browserStack,b.awsDeviceFarm,`limrun`].join(`, `)}function U(e){return!H(e)}function Ce(e){return e===`proxy`?`proxy`:H(e)?`direct-device-provider`:`remote-provider`}function W(e){return{providerDeviceOrientation:e.providerDeviceOrientation,providerGeoLocation:e.providerGeoLocation,providerTimezone:e.providerTimezone,providerLanguage:e.providerLanguage,providerLocale:e.providerLocale,providerNetworkProfile:e.providerNetworkProfile,providerCustomNetwork:e.providerCustomNetwork,providerNoResignApp:e.providerNoResignApp}}function we(e){return{metroProjectRoot:e.metroProjectRoot,metroKind:e.metroKind,metroPublicBaseUrl:e.metroPublicBaseUrl,metroProxyBaseUrl:e.metroProxyBaseUrl,metroPreparePort:e.metroPreparePort,metroListenHost:e.metroListenHost,metroStatusHost:e.metroStatusHost,metroStartupTimeoutMs:e.metroStartupTimeoutMs,metroProbeTimeoutMs:e.metroProbeTimeoutMs,metroRuntimeFile:e.metroRuntimeFile,metroNoReuseExisting:e.metroNoReuseExisting,metroNoInstallDeps:e.metroNoInstallDeps,launchUrl:e.launchUrl}}const G=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),K=new Set([`open`]),Te=new Set([u.open,u.install,u.reinstall,d.installSource]);async function Ee(t){let{command:n,flags:r,client:i}=t;if(!r.remoteConfig)return{flags:r,runtime:t.runtime};let a=l(r.stateDir).baseDir,o=v({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...V(o.profile),...r,remoteConfig:o.resolvedPath},c=k({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new e(`INVALID_ARGS`,`A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.`,{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:o.resolvedPath});let u=c??Ye(s,o.resolvedPath,o.profile),d={...s,session:u.session},f=Je(u.runtime,d.platform)??t.runtime,p=u,m=!c,h,g=Pe(p);if(g.shouldAllocate(n)){let e=await je({command:n,client:i,state:u,nextState:p,nextFlags:d,policy:g});p=e.state,m||=e.changed,h=e.acquiredLeaseForCleanup}let _=await De({command:n,flags:d,client:i,state:u,nextState:p,runtime:f,positionals:t.positionals,batchSteps:t.batchSteps,forceRuntimePrepare:t.forceRuntimePrepare});return p=_.state,f=_.runtime,m||=_.changed,await Ae({changed:m,stateDir:a,state:p,client:i,acquiredLeaseForCleanup:h,preparedMetroCleanupOnFailure:_.preparedMetroCleanupOnFailure,metroCleanupToStop:_.metroCleanupToStop}),{flags:{...d,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??d.platform,target:p.target??d.target},runtime:f,connection:ue(p)}}async function De(t){let{command:n,flags:r,state:i,client:a}=t,o=Oe(t.nextState,r),s=t.runtime;if(!Ke(n,r,t.batchSteps,t.positionals)||!Z(r)||!ke(t.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new e(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Re(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!qe(o.metro,c.cleanup);return o={...o,runtime:c.runtime,metro:c.cleanup,updatedAt:new Date().toISOString()},{state:o,runtime:c.runtime,changed:!0,metroCleanupToStop:l?t.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function Oe(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function ke(e,t,n){return e===!0||!t||!Q(t,n)}async function Ae(e){if(e.changed)try{A({stateDir:e.stateDir,state:e.state})}catch(t){throw await q(e.preparedMetroCleanupOnFailure),await We(e.client,e.state,e.acquiredLeaseForCleanup),t}await q(e.metroCleanupToStop)}async function je(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??X(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&$(i,c.device);let l=s.leaseBackend??o??Ge(i,t);tt(r,i,l);let u=await Xe(n,s,l,a,i),d=u.lease;return i.leaseId=d.leaseId,i.leaseBackend=l,i.platform=s.platform??i.platform,i.target=s.target??i.target,Me(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Ne(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function Me(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Ne(e,t,n,r){return{...e,leaseId:t.leaseId,leaseBackend:n,leaseProvider:t.leaseProvider??e.leaseProvider,clientId:t.clientId??e.clientId,deviceKey:t.deviceKey??e.deviceKey,platform:e.platform??r.platform,target:e.target??r.target,updatedAt:new Date().toISOString()}}function Pe(e){return e.leaseProvider===`proxy`?Ie:y(e.leaseProvider)?Le:Fe}const Fe={shouldAllocate:e=>!G.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Ie={shouldAllocate:e=>e!==`devices`&&!G.has(e),ttlMs:()=>3e5,resolveLeaseState:Ze},Le={shouldAllocate:e=>!G.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Re(t,n,r,i,a){if(!t.metroProjectRoot&&!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)return{};if(t.platform!==`ios`&&t.platform!==`android`)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:t.metroProjectRoot,kind:c(t.metroKind),publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:a,launchUrl:t.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:t.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:t.metroNoInstallDeps?!1:void 0,runtimeFilePath:t.metroRuntimeFile});return{runtime:t.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:t.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function q(e){if(e)try{await ee(e)}catch{}}async function ze(e){try{await E({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function J(e,t,n){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:n,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}function Be(e){let t=Ve(e.previous,e.cwd,e.env);return t?{canAuthenticate:!0,daemonAuthToken:t}:e.previous.daemon?.baseUrl===e.nextDaemonBaseUrl?{canAuthenticate:!0,daemonAuthToken:e.ambientDaemonAuthToken}:{canAuthenticate:!1}}function Ve(e,t,n){try{let{profile:r}=ne({configPath:e.remoteConfigPath,cwd:t,env:n});return r.daemonAuthToken&&He(e,r.daemonBaseUrl)?r.daemonAuthToken:void 0}catch{return}}function He(e,t){let n=j({daemonBaseUrl:t})?.baseUrl;return n!==void 0&&n===e.daemon?.baseUrl}async function Ue(e,t,n){if(!t.leaseId)return;let r=Be({previous:t,nextDaemonBaseUrl:n.nextDaemonBaseUrl,ambientDaemonAuthToken:n.ambientDaemonAuthToken,cwd:n.cwd,env:n.env});if(!r.canAuthenticate)return Y(t,`no credential known to belong to that endpoint was available`);try{await J(e,t,r.daemonAuthToken);return}catch{return Y(t,`the release request failed`)}}function Y(e,t){return{status:`unreleased`,message:`Could not release the previous lease ${e.leaseId} (tenant ${e.tenant}, run ${e.runId}) at ${e.daemon?.baseUrl??`its daemon`}: ${t}. It was left in place — release it manually if it is still active.`}}async function We(e,t,n){if(n)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:n.leaseId,leaseBackend:t.leaseBackend??n.backend,leaseProvider:t.leaseProvider??n.leaseProvider,clientId:t.clientId??n.clientId,deviceKey:t.deviceKey??n.deviceKey})}catch{}}function X(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Ge(t,n){let r=X(t);if(r)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Ke(e,t,n,r=[]){return e===`cdp`?O(r)&&!!t.metroPublicBaseUrl:K.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return K.has(t)&&e.runtime===void 0})}function Z(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function Q(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function qe(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function Je(e,t){if(e)return Q(e,t)?e:void 0}function Ye(t,n,r={}){if(!t.tenant)throw new e(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!t.runId)throw new e(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!t.daemonBaseUrl&&U(r.leaseProvider))throw new e(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:t.session??`default`,remoteConfigPath:n,remoteConfigHash:N(n),daemon:j(t),tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend??X(t),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:t.platform,target:t.target,connectedAt:i,updatedAt:i}}async function Xe(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await nt(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t)});if(i)return{lease:i,acquired:!1}}return{lease:await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t),platform:t.platform??i.platform,target:t.target??i.target,device:i.device,udid:i.udid,serial:i.serial,providerApp:i.providerApp,providerOsVersion:i.providerOsVersion,providerProject:i.providerProject,providerBuild:i.providerBuild,providerSessionName:i.providerSessionName,...W(i),awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function Ze(t){if(!Te.has(t.command)){if(t.state.leaseId&&t.state.deviceKey)return{state:t.state};throw new e(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await Qe(t.client,t.flags),r=$e(n);return{state:{...t.state,deviceKey:r,leaseBackend:t.state.leaseBackend??t.leaseBackend??et(n),platform:t.state.platform??n.platform,target:t.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function $(e,t){if(e.platform=t.platform,e.target=t.target??e.target,i(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function Qe(e,t){return await r((await e.devices.list({platform:t.platform,target:t.target,device:t.device,udid:t.udid,serial:t.serial,iosSimulatorDeviceSet:t.iosSimulatorDeviceSet,androidDeviceAllowlist:t.androidDeviceAllowlist})).map(e=>({...n(e.platform),id:e.id,name:e.name,kind:e.kind,target:e.target,booted:e.booted})),{platform:t.platform,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial})}function $e(e){return`${t(e)}:${e.target??`mobile`}:${e.id}`}function et(e){if(i(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function tt(t,n,r){if(t.leaseBackend&&t.leaseBackend!==r)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:t.session,leaseBackend:t.leaseBackend});if(t.platform&&n.platform&&t.platform!==n.platform)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:t.session,platform:t.platform});if(t.target&&n.target&&t.target!==n.target)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:t.session,target:t.target})}async function nt(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend,leaseProvider:n.leaseProvider,clientId:n.clientId,deviceKey:n.deviceKey,ttlMs:n.ttlMs})}catch(e){if(rt(e))return;throw e}}function rt(t){return!(t instanceof e)||t.code!==`UNAUTHORIZED`?!1:t.details?.reason===`LEASE_NOT_FOUND`||t.details?.reason===`LEASE_EXPIRED`||t.details?.reason===`LEASE_REVOKED`}export{A as C,E as D,T as E,le as S,D as T,de as _,X as a,k as b,W as c,Ce as d,U as f,j as g,be as h,J as i,we as l,V as m,Ee as n,q as o,xe as p,Ue as r,ze as s,Z as t,Se as u,N as v,ce as w,M as x,I as y};
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{_ as t,a as n,b as r,c as i}from"./sdk-device.js";import{Dn as a,On as o,s,wn as c}from"./script-source-bundle.js";import{_ as l}from"./screenshot-result.js";import{n as u,t as d}from"./command-catalog.js";import{t as f}from"./sdk-remote-config.js";import{A as p,x as m}from"./sdk-android-adb.js";import{v as h}from"./url.js";import{a as g,i as _}from"./client-metro.js";import{n as ee}from"./metro2.js";import{n as te,r as v,t as ne}from"./remote-config2.js";import{a as y,i as b}from"./src2.js";import x from"node:path";import S from"node:crypto";import C from"node:fs";const w={slug:`react-devtools-companion`,runArg:h,displayName:`React DevTools companion`};async function T(e){return await _({...e,definition:w,localBaseUrl:e.localBaseUrl??`http://127.0.0.1:8097`,registerPath:`/api/react-devtools/companion/register`,unregisterPath:`/api/react-devtools/companion/unregister`,devicePort:e.devicePort??8097})}async function E(e){return await g({...e,definition:w})}function D(e){return e===`android-instance`||e===`ios-instance`}function re(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function ie(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function O(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!ie(e)}function ae(e){let t=new URL(e);t.search=``,t.hash=``;let n=t.pathname.replace(/\/+$/,``);return t.pathname=n.endsWith(`/index.bundle`)?n.slice(0,-13)||`/`:n||`/`,t.toString().replace(/\/+$/,``)}function oe(e){let t=e?.metroPublicBaseUrl?.trim();return t?ae(t):null}function se(t,n={}){if(!O(t)||!n.flags?.metroProxyBaseUrl||!D(n.flags.leaseBackend))return t;let r=oe(n.flags);if(!r)throw new e(`INVALID_ARGS`,`cdp remote bridge target discovery requires a React Native dev-server public base URL.`,{hint:`Include metroPublicBaseUrl in the remote config so cdp can reach the local or tunneled Metro/Re.Pack CDP endpoint without bridge proxy authentication.`});return[...t,`--url`,r]}async function ce(e,t={}){return(await m(`npm`,re(se(e,t)),{cwd:t.cwd??process.cwd(),env:t.env??process.env,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode}function k(e){let t=P(e);if(!C.existsSync(t))return null;let n;try{n=JSON.parse(C.readFileSync(t,`utf8`))}catch(t){return z(e,t),null}return me(n)?n:(z(e),null)}function A(e){let t=P({stateDir:e.stateDir,session:e.state.session});C.mkdirSync(x.dirname(t),{recursive:!0}),R(t,e.state),R(F(e.stateDir),{session:e.state.session})}function j(e){return{baseUrl:pe(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function M(e){C.rmSync(P(e),{force:!0});let t=F(e.stateDir);L(e.stateDir)===e.session&&C.rmSync(t,{force:!0})}function le(t){let n=t.validateRemoteConfigHash??!0,r=t.remoteConfig?te({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}):void 0,i=k(t)??(t.allowActiveFallback?I({stateDir:t.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&N(i.remoteConfigPath)!==i.remoteConfigHash)throw new e(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let s=fe(i,t),l=c(i);return{runtime:i.runtime,connection:o(l),flags:{...s,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??s.daemonBaseUrl,daemonAuthToken:s.daemonAuthToken,daemonTransport:i.daemon?.transport??s.daemonTransport,daemonServerMode:i.daemon?.serverMode??s.daemonServerMode,...a(l),sessionIsolation:`tenant`,session:i.session,platform:i.platform??s.platform,target:i.target??s.target}}}function ue(e){return o(c(e))}function N(t){try{return S.createHash(`sha256`).update(C.readFileSync(t)).digest(`hex`)}catch(n){throw new e(`INVALID_ARGS`,`Remote config file not found: ${t}`,{cause:n instanceof Error?n.message:String(n)})}}function P(e){return x.join(e.stateDir,`remote-connections`,`${B(e.session)}.json`)}function F(e){return x.join(e,`remote-connections`,`.active-session.json`)}function I(e){let t=L(e.stateDir);return t?k({stateDir:e.stateDir,session:t}):null}function L(e){let t=F(e);if(C.existsSync(t))try{let e=JSON.parse(C.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function de(e){if(e)return S.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function fe(e,t){try{return v({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function R(e,t){let n=`${e}.${process.pid}.${S.randomUUID()}.tmp`;try{C.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),C.renameSync(n,e)}catch(e){throw C.rmSync(n,{force:!0}),e}}function pe(e){if(!e)return;let t=new URL(e);t.username=``,t.password=``;for(let e of[...t.searchParams.keys()])/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,``)}function z(e,t){p({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),M(e)}function B(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${S.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function me(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&he(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&ge(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&_e(t.daemon)}function he(e,t){return t.every(t=>typeof e[t]==`string`)}function ge(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function _e(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:ve(e)}function ve(e){let t=e;return(t.baseUrl===void 0||typeof t.baseUrl==`string`)&&(t.authToken===void 0||typeof t.authToken==`string`)&&(t.transport===void 0||typeof t.transport==`string`)&&(t.serverMode===void 0||typeof t.serverMode==`string`)}const ye=f.map(e=>e.key);function V(e){let t={};for(let n of ye){let r=e[n];r!==void 0&&(t[n]=r)}return t}function be(e){return e.remoteConfig?{...V(v({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function xe(e){return e===`cloud`||e===`proxy`||H(e)}function H(e){return e===`limrun`||y(e)}function Se(){return[`cloud`,`proxy`,b.browserStack,b.awsDeviceFarm,`limrun`].join(`, `)}function U(e){return!H(e)}function Ce(e){return e===`proxy`?`proxy`:H(e)?`direct-device-provider`:`remote-provider`}function W(e){return{providerDeviceOrientation:e.providerDeviceOrientation,providerGeoLocation:e.providerGeoLocation,providerTimezone:e.providerTimezone,providerLanguage:e.providerLanguage,providerLocale:e.providerLocale,providerNetworkProfile:e.providerNetworkProfile,providerCustomNetwork:e.providerCustomNetwork,providerNoResignApp:e.providerNoResignApp}}function we(e){return{metroProjectRoot:e.metroProjectRoot,metroKind:e.metroKind,metroPublicBaseUrl:e.metroPublicBaseUrl,metroProxyBaseUrl:e.metroProxyBaseUrl,metroPreparePort:e.metroPreparePort,metroListenHost:e.metroListenHost,metroStatusHost:e.metroStatusHost,metroStartupTimeoutMs:e.metroStartupTimeoutMs,metroProbeTimeoutMs:e.metroProbeTimeoutMs,metroRuntimeFile:e.metroRuntimeFile,metroNoReuseExisting:e.metroNoReuseExisting,metroNoInstallDeps:e.metroNoInstallDeps,launchUrl:e.launchUrl}}const G=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),K=new Set([`open`]),Te=new Set([u.open,u.install,u.reinstall,d.installSource]);async function Ee(t){let{command:n,flags:r,client:i}=t;if(!r.remoteConfig)return{flags:r,runtime:t.runtime};let a=l(r.stateDir).baseDir,o=v({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...V(o.profile),...r,remoteConfig:o.resolvedPath},c=k({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new e(`INVALID_ARGS`,`A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.`,{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:o.resolvedPath});let u=c??Ye(s,o.resolvedPath,o.profile),d={...s,session:u.session},f=Je(u.runtime,d.platform)??t.runtime,p=u,m=!c,h,g=Pe(p);if(g.shouldAllocate(n)){let e=await je({command:n,client:i,state:u,nextState:p,nextFlags:d,policy:g});p=e.state,m||=e.changed,h=e.acquiredLeaseForCleanup}let _=await De({command:n,flags:d,client:i,state:u,nextState:p,runtime:f,positionals:t.positionals,batchSteps:t.batchSteps,forceRuntimePrepare:t.forceRuntimePrepare});return p=_.state,f=_.runtime,m||=_.changed,await Ae({changed:m,stateDir:a,state:p,client:i,acquiredLeaseForCleanup:h,preparedMetroCleanupOnFailure:_.preparedMetroCleanupOnFailure,metroCleanupToStop:_.metroCleanupToStop}),{flags:{...d,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??d.platform,target:p.target??d.target},runtime:f,connection:ue(p)}}async function De(t){let{command:n,flags:r,state:i,client:a}=t,o=Oe(t.nextState,r),s=t.runtime;if(!Ke(n,r,t.batchSteps,t.positionals)||!Z(r)||!ke(t.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new e(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Re(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!qe(o.metro,c.cleanup);return o={...o,runtime:c.runtime,metro:c.cleanup,updatedAt:new Date().toISOString()},{state:o,runtime:c.runtime,changed:!0,metroCleanupToStop:l?t.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function Oe(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function ke(e,t,n){return e===!0||!t||!Q(t,n)}async function Ae(e){if(e.changed)try{A({stateDir:e.stateDir,state:e.state})}catch(t){throw await q(e.preparedMetroCleanupOnFailure),await We(e.client,e.state,e.acquiredLeaseForCleanup),t}await q(e.metroCleanupToStop)}async function je(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??X(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&$(i,c.device);let l=s.leaseBackend??o??Ge(i,t);tt(r,i,l);let u=await Xe(n,s,l,a,i),d=u.lease;return i.leaseId=d.leaseId,i.leaseBackend=l,i.platform=s.platform??i.platform,i.target=s.target??i.target,Me(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Ne(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function Me(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Ne(e,t,n,r){return{...e,leaseId:t.leaseId,leaseBackend:n,leaseProvider:t.leaseProvider??e.leaseProvider,clientId:t.clientId??e.clientId,deviceKey:t.deviceKey??e.deviceKey,platform:e.platform??r.platform,target:e.target??r.target,updatedAt:new Date().toISOString()}}function Pe(e){return e.leaseProvider===`proxy`?Ie:y(e.leaseProvider)?Le:Fe}const Fe={shouldAllocate:e=>!G.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Ie={shouldAllocate:e=>e!==`devices`&&!G.has(e),ttlMs:()=>3e5,resolveLeaseState:Ze},Le={shouldAllocate:e=>!G.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Re(t,n,r,i,a){if(!t.metroProjectRoot&&!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)return{};if(t.platform!==`ios`&&t.platform!==`android`)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new e(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:t.metroProjectRoot,kind:s(t.metroKind),publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:a,launchUrl:t.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:t.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:t.metroNoInstallDeps?!1:void 0,runtimeFilePath:t.metroRuntimeFile});return{runtime:t.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:t.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function q(e){if(e)try{await ee(e)}catch{}}async function ze(e){try{await E({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function J(e,t,n){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:n,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}function Be(e){let t=Ve(e.previous,e.cwd,e.env);return t?{canAuthenticate:!0,daemonAuthToken:t}:e.previous.daemon?.baseUrl===e.nextDaemonBaseUrl?{canAuthenticate:!0,daemonAuthToken:e.ambientDaemonAuthToken}:{canAuthenticate:!1}}function Ve(e,t,n){try{let{profile:r}=ne({configPath:e.remoteConfigPath,cwd:t,env:n});return r.daemonAuthToken&&He(e,r.daemonBaseUrl)?r.daemonAuthToken:void 0}catch{return}}function He(e,t){let n=j({daemonBaseUrl:t})?.baseUrl;return n!==void 0&&n===e.daemon?.baseUrl}async function Ue(e,t,n){if(!t.leaseId)return;let r=Be({previous:t,nextDaemonBaseUrl:n.nextDaemonBaseUrl,ambientDaemonAuthToken:n.ambientDaemonAuthToken,cwd:n.cwd,env:n.env});if(!r.canAuthenticate)return Y(t,`no credential known to belong to that endpoint was available`);try{await J(e,t,r.daemonAuthToken);return}catch{return Y(t,`the release request failed`)}}function Y(e,t){return{status:`unreleased`,message:`Could not release the previous lease ${e.leaseId} (tenant ${e.tenant}, run ${e.runId}) at ${e.daemon?.baseUrl??`its daemon`}: ${t}. It was left in place — release it manually if it is still active.`}}async function We(e,t,n){if(n)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:n.leaseId,leaseBackend:t.leaseBackend??n.backend,leaseProvider:t.leaseProvider??n.leaseProvider,clientId:t.clientId??n.clientId,deviceKey:t.deviceKey??n.deviceKey})}catch{}}function X(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Ge(t,n){let r=X(t);if(r)return r;throw new e(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Ke(e,t,n,r=[]){return e===`cdp`?O(r)&&!!t.metroPublicBaseUrl:K.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return K.has(t)&&e.runtime===void 0})}function Z(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function Q(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function qe(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function Je(e,t){if(e)return Q(e,t)?e:void 0}function Ye(t,n,r={}){if(!t.tenant)throw new e(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!t.runId)throw new e(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!t.daemonBaseUrl&&U(r.leaseProvider))throw new e(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:t.session??`default`,remoteConfigPath:n,remoteConfigHash:N(n),daemon:j(t),tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend??X(t),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:t.platform,target:t.target,connectedAt:i,updatedAt:i}}async function Xe(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await nt(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t)});if(i)return{lease:i,acquired:!1}}return{lease:await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey,ttlMs:r.ttlMs(t),platform:t.platform??i.platform,target:t.target??i.target,device:i.device,udid:i.udid,serial:i.serial,providerApp:i.providerApp,providerOsVersion:i.providerOsVersion,providerProject:i.providerProject,providerBuild:i.providerBuild,providerSessionName:i.providerSessionName,...W(i),awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function Ze(t){if(!Te.has(t.command)){if(t.state.leaseId&&t.state.deviceKey)return{state:t.state};throw new e(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await Qe(t.client,t.flags),r=$e(n);return{state:{...t.state,deviceKey:r,leaseBackend:t.state.leaseBackend??t.leaseBackend??et(n),platform:t.state.platform??n.platform,target:t.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function $(e,t){if(e.platform=t.platform,e.target=t.target??e.target,i(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function Qe(e,t){return await r((await e.devices.list({platform:t.platform,target:t.target,device:t.device,udid:t.udid,serial:t.serial,iosSimulatorDeviceSet:t.iosSimulatorDeviceSet,androidDeviceAllowlist:t.androidDeviceAllowlist})).map(e=>({...n(e.platform),id:e.id,name:e.name,kind:e.kind,target:e.target,booted:e.booted})),{platform:t.platform,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial})}function $e(e){return`${t(e)}:${e.target??`mobile`}:${e.id}`}function et(e){if(i(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function tt(t,n,r){if(t.leaseBackend&&t.leaseBackend!==r)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:t.session,leaseBackend:t.leaseBackend});if(t.platform&&n.platform&&t.platform!==n.platform)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:t.session,platform:t.platform});if(t.target&&n.target&&t.target!==n.target)throw new e(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:t.session,target:t.target})}async function nt(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend,leaseProvider:n.leaseProvider,clientId:n.clientId,deviceKey:n.deviceKey,ttlMs:n.ttlMs})}catch(e){if(rt(e))return;throw e}}function rt(t){return!(t instanceof e)||t.code!==`UNAUTHORIZED`?!1:t.details?.reason===`LEASE_NOT_FOUND`||t.details?.reason===`LEASE_EXPIRED`||t.details?.reason===`LEASE_REVOKED`}export{A as C,E as D,T as E,le as S,D as T,de as _,X as a,k as b,W as c,Ce as d,U as f,j as g,be as h,J as i,we as l,V as m,Ee as n,q as o,xe as p,Ue as r,ze as s,Z as t,Se as u,N as v,ce as w,M as x,I as y};
|
package/dist/src/contracts.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { I as
|
|
1
|
+
import { I as normalizeError, N as defaultHintForCode, _ as SessionRuntimeHints, a as DaemonRequest, d as JsonRpcRequestEnvelope, f as LeaseBackend, j as DaemonError, k as centerOfRect, o as DaemonResponse, r as DaemonInstallSource, s as DaemonResponseData, u as JsonRpcId } from "./sdk-contracts.js";
|
|
2
2
|
export { type DaemonError, type DaemonInstallSource, type DaemonRequest, type DaemonResponse, type DaemonResponseData, type JsonRpcId, type JsonRpcRequestEnvelope, type LeaseBackend, type SessionRuntimeHints, centerOfRect, defaultHintForCode, normalizeError };
|
package/dist/src/contracts.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E as e,b as t,u as n}from"./sdk-contracts.js";export{n as centerOfRect,t as defaultHintForCode,e as normalizeError};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:path";import t from"node:fs";function n(e,n){let r={providerReleases:{released:n.released.map(o),pending:n.pending.map(o)}},i=a(e),s=`${i}.${process.pid}.${Date.now()}.tmp`;try{t.writeFileSync(s,`${JSON.stringify(r)}\n`,{mode:384}),t.renameSync(s,i),t.chmodSync(i,384)}catch{try{t.rmSync(s,{force:!0})}catch{}}}function r(e){try{let n=JSON.parse(t.readFileSync(a(e),`utf8`));return s(n)?n:null}catch{return null}}function i(e){try{t.rmSync(a(e),{force:!0})}catch{}}function a(t){return e.join(t,`daemon-shutdown.json`)}function o(e){return{leaseId:e.leaseId,...e.leaseProvider?{provider:e.leaseProvider}:{}}}function s(e){if(!e||typeof e!=`object`)return!1;let t=e.providerReleases;if(!t||typeof t!=`object`)return!1;let n=t;return Array.isArray(n.released)&&Array.isArray(n.pending)&&n.released.every(
|
|
1
|
+
import e from"node:path";import t from"node:fs";function n(e,n){let r={providerReleases:{released:n.providerReleases.released.map(o),pending:n.providerReleases.pending.map(o)},claims:{released:[...n.claims.released],orphaned:[...n.claims.orphaned],superseded:[...n.claims.superseded]}},i=a(e),s=`${i}.${process.pid}.${Date.now()}.tmp`;try{t.writeFileSync(s,`${JSON.stringify(r)}\n`,{mode:384}),t.renameSync(s,i),t.chmodSync(i,384)}catch{try{t.rmSync(s,{force:!0})}catch{}}}function r(e){try{let n=JSON.parse(t.readFileSync(a(e),`utf8`));return s(n)?{...n,claims:c(n)}:null}catch{return null}}function i(e){try{t.rmSync(a(e),{force:!0})}catch{}}function a(t){return e.join(t,`daemon-shutdown.json`)}function o(e){return{leaseId:e.leaseId,...e.leaseProvider?{provider:e.leaseProvider}:{}}}function s(e){if(!e||typeof e!=`object`)return!1;let t=e.providerReleases;if(!t||typeof t!=`object`)return!1;let n=t;return Array.isArray(n.released)&&Array.isArray(n.pending)&&n.released.every(d)&&n.pending.every(d)}function c(e){let t=e.claims;if(!t||typeof t!=`object`)return{released:[],orphaned:[],superseded:[]};let n=t;return{released:l(n.released),orphaned:l(n.orphaned),superseded:l(n.superseded)}}function l(e){return Array.isArray(e)?e.filter(u):[]}function u(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.deviceKey==`string`&&typeof t.session==`string`&&typeof t.platform==`string`&&typeof t.deviceId==`string`}function d(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.leaseId==`string`&&t.leaseId.trim().length>0&&(t.provider===void 0||typeof t.provider==`string`)}export{r as n,n as r,i as t};
|
package/dist/src/daemon.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{_ as t,d as n,p as r}from"./screenshot-result.js";import{t as i}from"./timeouts.js";import{d as a,n as o}from"./host-process.js";import{n as s}from"./daemon-shutdown-report.js";import{t as c}from"./shared.js";import l from"node:fs";async function u(t){let r=p(t.paths.infoPath);if(!r)return g();if(!r.processStartTime){if(!o(r.pid))return g();throw new e(`COMMAND_FAILED`,`Refusing to stop a daemon without a verified process start-time identity.`,{pid:r.pid})}if(!n(r.pid,r.processStartTime)){if(!o(r.pid))return g();throw new e(`COMMAND_FAILED`,`Refusing to stop a daemon whose PID or start-time identity could not be verified.`,{pid:r.pid,processStartTime:r.processStartTime})}if(!d(r.pid,`SIGTERM`))return g();if(await a(r.pid,t.graceTimeoutMs??1e4))return await h(t.paths,1e3),{stopped:!0,mode:`graceful`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]};if(n(r.pid,r.processStartTime)&&d(r.pid,`SIGKILL`),!await a(r.pid,t.killTimeoutMs??2e3))throw new e(`COMMAND_FAILED`,`Daemon did not exit after SIGKILL.`,{pid:r.pid});return{stopped:!0,mode:`forced`,cleanupConfidence:`unknown`,claimsReleased:[],claimsOrphaned:[],providerReleases:{status:`unknown`,released:[],pending:null},warnings:[`The daemon was force-killed before provider lease state could be finalized. Provider allocations may remain active.`]}}function d(t,n){if(r(t,n))return!0;if(!o(t))return!1;throw new e(`COMMAND_FAILED`,`Daemon could not be signaled with ${n}.`,{pid:t,signal:n})}function f(e){let t=p(e);return t?.processStartTime?{pid:t.pid,processStartTime:t.processStartTime}:null}function p(e){try{let t=JSON.parse(l.readFileSync(e,`utf8`)),n=t.pid;return typeof n!=`number`||!Number.isInteger(n)||n<=0?null:{pid:n,...m(t.processStartTime)?{processStartTime:t.processStartTime}:{}}}catch{return null}}function m(e){return typeof e==`string`&&e.trim().length>0}async function h(e,t){let n=Date.now();for(;Date.now()-n<t;){if(!l.existsSync(e.infoPath)&&!l.existsSync(e.lockPath))return;await i(25)}}function g(){return{stopped:!1,mode:`not-running`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]}}const _=async({positionals:n,flags:r})=>{if(n[0]!==`stop`||n.length!==1)throw new e(`INVALID_ARGS`,`daemon accepts only: stop`);let i=t(r.stateDir),a=f(i.infoPath),o=await u({paths:i}),l=v(o,o.mode===`graceful`?s(i.baseDir):null),d=r.clean===!0&&a!==null&&l.stopped;if(d){let[{cleanupRunnerLeasesForOwner:e},{runnerLeaseCleanupAdapter:t}]=await Promise.all([import(`./runner-lease.js`).then(e=>e.c),import(`./runner-disposal.js`).then(e=>e.s)]);await e({pid:a.pid,startTime:a.processStartTime},t)}let p={...l,clean:d};return c(r,p,()=>
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{_ as t,d as n,p as r}from"./screenshot-result.js";import{t as i}from"./timeouts.js";import{d as a,n as o}from"./host-process.js";import{n as s}from"./daemon-shutdown-report.js";import{t as c}from"./shared.js";import l from"node:fs";async function u(t){let r=p(t.paths.infoPath);if(!r)return g();if(!r.processStartTime){if(!o(r.pid))return g();throw new e(`COMMAND_FAILED`,`Refusing to stop a daemon without a verified process start-time identity.`,{pid:r.pid})}if(!n(r.pid,r.processStartTime)){if(!o(r.pid))return g();throw new e(`COMMAND_FAILED`,`Refusing to stop a daemon whose PID or start-time identity could not be verified.`,{pid:r.pid,processStartTime:r.processStartTime})}if(!d(r.pid,`SIGTERM`))return g();if(await a(r.pid,t.graceTimeoutMs??1e4))return await h(t.paths,1e3),{stopped:!0,mode:`graceful`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],claimsSuperseded:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]};if(n(r.pid,r.processStartTime)&&d(r.pid,`SIGKILL`),!await a(r.pid,t.killTimeoutMs??2e3))throw new e(`COMMAND_FAILED`,`Daemon did not exit after SIGKILL.`,{pid:r.pid});return{stopped:!0,mode:`forced`,cleanupConfidence:`unknown`,claimsReleased:[],claimsOrphaned:[],claimsSuperseded:[],providerReleases:{status:`unknown`,released:[],pending:null},warnings:[`The daemon was force-killed before provider lease state could be finalized. Provider allocations may remain active.`]}}function d(t,n){if(r(t,n))return!0;if(!o(t))return!1;throw new e(`COMMAND_FAILED`,`Daemon could not be signaled with ${n}.`,{pid:t,signal:n})}function f(e){let t=p(e);return t?.processStartTime?{pid:t.pid,processStartTime:t.processStartTime}:null}function p(e){try{let t=JSON.parse(l.readFileSync(e,`utf8`)),n=t.pid;return typeof n!=`number`||!Number.isInteger(n)||n<=0?null:{pid:n,...m(t.processStartTime)?{processStartTime:t.processStartTime}:{}}}catch{return null}}function m(e){return typeof e==`string`&&e.trim().length>0}async function h(e,t){let n=Date.now();for(;Date.now()-n<t;){if(!l.existsSync(e.infoPath)&&!l.existsSync(e.lockPath))return;await i(25)}}function g(){return{stopped:!1,mode:`not-running`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],claimsSuperseded:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]}}const _=async({positionals:n,flags:r})=>{if(n[0]!==`stop`||n.length!==1)throw new e(`INVALID_ARGS`,`daemon accepts only: stop`);let i=t(r.stateDir),a=f(i.infoPath),o=await u({paths:i}),l=v(o,o.mode===`graceful`?s(i.baseDir):null),d=r.clean===!0&&a!==null&&l.stopped;if(d){let[{cleanupRunnerLeasesForOwner:e},{runnerLeaseCleanupAdapter:t}]=await Promise.all([import(`./runner-lease.js`).then(e=>e.c),import(`./runner-disposal.js`).then(e=>e.s)]);await e({pid:a.pid,startTime:a.processStartTime},t)}let p={...l,clean:d};return c(r,p,()=>b(p)),!0};function v(e,t){return e.mode!==`graceful`||t?t?{...e,providerReleases:{status:`completed`,...t.providerReleases},claimsReleased:t.claims.released,claimsOrphaned:t.claims.orphaned,claimsSuperseded:t.claims.superseded,warnings:[...e.warnings,...y(t.claims.superseded)]}:e:{...e,cleanupConfidence:`unknown`,providerReleases:{status:`unknown`,released:[],pending:null},warnings:[...e.warnings,`The graceful shutdown report is unavailable, so provider cleanup state is unknown. Provider allocations may remain active.`]}}function y(e){return e.length===0?[]:[`Another owner had already claimed ${e.map(e=>e.deviceId).join(`, `)} before this daemon released it, so those devices are now owned elsewhere.`]}function b(e){return[e.stopped?`Daemon stopped (${e.mode}).`:`No running daemon found.`,e.clean?`Retained runner cleanup completed.`:null,...e.warnings].filter(e=>!!e).join(`
|
|
2
2
|
`)}export{_ as daemonCommand};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{Lr as t}from"./sdk-batch-runner.js";import{_ as n,h as r}from"./sdk-android-adb.js";import i from"node:path";import a from"node:fs/promises";const o=/^[0-9a-fA-F-]{32,36}$/;function s(e){if(!(!e||!o.test(e)))return e.replaceAll(`-`,``).toUpperCase()}function c(e,t){return`${e.uuid}:${l(t)}`}function l(e){return`0x${e.toString(16)}`}function u(e){return typeof e==`string`&&e.length>0?e:void 0}function d(...e){for(let t of e){let e=u(t);if(e)return e}}function f(e){let t=e.filter(e=>!!e);return t.length>0?t.join(` `):void 0}function p(e){try{let n=JSON.parse(e);return t(n)?n:null}catch{return null}}function m(e){if(typeof e==`number`&&Number.isSafeInteger(e))return e;if(typeof e==`string`){let t=e.startsWith(`0x`)?Number.parseInt(e,16):Number(e);return Number.isSafeInteger(t)?t:void 0}}function h(e,t,n){if(!Object.hasOwn(e,t))return;let r=m(e[t]);if(r!==void 0)return r;v(n,t)}function g(e,t,n){if(!Object.hasOwn(e,t))return;let r=_(e[t]);if(r!==void 0)return r;v(n,t)}function _(e){if(typeof e==`bigint`)return e;if(typeof e==`number`&&Number.isSafeInteger(e)||typeof e==`string`&&/^(?:0x[0-9a-fA-F]+|\d+)$/.test(e))return BigInt(e)}function v(t,n){throw new e(`INVALID_ARGS`,`Invalid ${t} numeric field: ${n}`,{hint:`Crash artifact numeric fields must be integer numbers or integer numeric strings.`})}function y(e){return e.length===1?e[0]:void 0}function b(e){return[...new Set(e)]}function x(e){let t=e.match(/^(.*) \+ (\d+)$/);return t?{symbol:t[1],location:Number(t[2])}:{symbol:e}}const S=/^(?:arm64e?|arm64_32|x86_64|armv7[sk]?|i386)$/;function ee(e){return te(e)??w(e)}function te(e){let t=ne(e);if(!t)return null;let n=(Array.isArray(t.payload.usedImages)?t.payload.usedImages:[]).flatMap((e,t)=>C(e,t));if(n.length===0)return null;let r=re(Array.isArray(t.payload.threads)?t.payload.threads:[],n);return{format:`ips`,images:n,addresses:r.map(({frame:e,...t})=>t),document:t,frameMatches:r,write:e=>oe(t,r,e)}}function ne(e){let t=p(e);if(t)return{payload:t};let n=e.indexOf(`
|
|
2
2
|
`);if(n===-1)return null;let r=e.slice(0,n),i=p(e.slice(n+1));return i?{header:r,payload:i}:null}function re(e,t){let n=new Map(t.map(e=>[e.index,e]));return e.flatMap((e,t)=>ie(e).flatMap((e,r)=>ae(e,n,t,r)))}function ie(e){return!t(e)||!Array.isArray(e.frames)?[]:e.frames.filter(t)}function ae(e,t,n,r){let i=h(e,`imageIndex`,`IPS frame`),a=g(e,`imageOffset`,`IPS frame`);if(i===void 0||a===void 0)return[];let o=t.get(i);return o?[{frame:e,frameIndex:r,threadIndex:n,image:o,address:o.base+a}]:[]}function oe(e,t,n){for(let e of t){let t=n.get(c(e.image,e.address))?.text;t&&se(e.frame,t)}e.payload.agentDeviceSymbolication={tool:`agent-device debug symbols`,symbolicatedFrames:[...n.values()].filter(e=>e.text).length};let r=`${JSON.stringify(e.payload,null,2)}\n`;return e.header?`${e.header}\n${r}`:r}function se(e,t){let n=x(t);e.symbol=n.symbol,n.location!==void 0&&(e.symbolLocation=n.location)}function C(e,n){if(!t(e))return[];let r=s(u(e.uuid)),a=g(e,`base`,`IPS usedImages`);if(!r||a===void 0)return[];let o=u(e.path);return[{index:n,name:u(e.name)??(o?i.basename(o):`image-${n}`),uuid:r,arch:u(e.arch),base:a,path:o}]}function w(e){let t=e.split(`
|
|
3
3
|
`),n=T(t);if(n.length===0)return null;let r=O(t,n);return{format:`text`,images:n,addresses:r,lines:t,frameMatches:r,write(e){let n=new Map(r.map(e=>[e.lineIndex,e]));return t.map((t,r)=>{let i=n.get(r);if(!i)return t;let a=e.get(c(i.image,i.address))?.text;return!a||t.includes(a)?t:`${t} // ${a}`}).join(`
|
|
4
4
|
`)}}}function T(e){let t=[],n=e.findIndex(e=>/^Binary Images:/i.test(e.trim()));if(n===-1)return t;for(let r of e.slice(n+1)){let e=E(r);e&&t.push(e)}return t}function E(e){let t=e.match(/^\s*(0x[0-9a-fA-F]+)\s*-\s*(0x[0-9a-fA-F]+)\s+\+?(.+?)\s+<([0-9a-fA-F-]{32,36})>\s+(.+)$/);if(!t)return null;let n=s(t[4]);if(!n)return null;let r=D(t[3].trim(),t[5].trim());return{name:r.name,arch:r.arch,uuid:n,base:BigInt(t[1]),end:BigInt(t[2]),path:t[5].trim()}}function D(e,t){let n=e.split(/\s+/),r=n.at(-1);if(r&&S.test(r))return{name:n.slice(0,-1).join(` `).trim(),arch:r};let a=i.basename(t);return{name:e.startsWith(a)?a:e}}function O(e,t){let n=[],r;for(let[i,a]of e.entries()){let e=a.match(/^Thread\s+(\d+)\s+Crashed:/);e?r=Number(e[1]):(a.trim().length===0||/^Thread\s+\d+/.test(a))&&(r=void 0);let o=k(a,t),s=a.match(/^\s*(\d+)/);o&&s&&n.push({...o,frameIndex:Number(s[1]),lineIndex:i,threadIndex:r})}return n}function k(e,t){let n=e.match(/^\s*\d+\s+(.+?)\s+(0x[0-9a-fA-F]+)\b/);if(!n)return null;let r=n[1].trim(),i=BigInt(n[2]),a=A(t,r,i);return a?{image:a,address:i}:null}function A(e,t,n){let r=e.filter(e=>e.name===t);return r.find(e=>j(e,n))??y(r)}function j(e,t){return e.end!==void 0&&e.base<=t&&t<=e.end}const M=1e4;async function N(e){return e.dsym&&e.searchPath?[H(e.cwd,e.dsym),...await P(H(e.cwd,e.searchPath))]:e.dsym?[H(e.cwd,e.dsym)]:e.searchPath?await P(H(e.cwd,e.searchPath)):[]}async function P(t){let n=[],r=0;async function o(s){if(n.length>=200)return;if(r+=1,r>M)throw new e(`COMMAND_FAILED`,`debug symbols search-path scan exceeded bounds.`,{searchPath:t,maxEntries:M,hint:`Pass --dsym <App.dSYM> directly or narrow --search-path to the build products directory.`});if(!(await F(s,t)).isDirectory()){s===t&&I(t);return}if(s.endsWith(`.dSYM`)){n.push(s);return}let c=await a.readdir(s,{withFileTypes:!0});for(let e of c)e.isDirectory()&&await o(i.join(s,e.name))}return await o(t),n}async function F(t,n){try{return await a.stat(t)}catch{throw new e(`INVALID_ARGS`,`debug symbols search path does not exist: ${n}`,{hint:`Pass an existing build products directory to --search-path, or pass --dsym <App.dSYM> directly.`})}}function I(t){throw new e(`INVALID_ARGS`,`debug symbols search path is not a directory: ${t}`,{hint:`Pass an existing build products directory to --search-path, or pass --dsym <App.dSYM> directly.`})}async function L(t,n){let r=(await Promise.all(b(t).map(e=>R(e,n)))).flat();if(r.length===0)throw new e(`COMMAND_FAILED`,`No UUIDs found in dSYM bundle.`,{hint:`Verify the path points to a built .dSYM bundle with DWARF contents.`});return r}async function R(e,t){return await z(e),B(e,r(await n(t,[`--uuid`,e],{timeoutMs:15e3,allowFailure:!0}),`Failed to inspect dSYM UUIDs: ${e}`,{hint:`Verify the dSYM bundle is valid and readable.`}).stdout)}async function z(t){if(!((await a.stat(t).catch(()=>null))?.isDirectory()&&t.endsWith(`.dSYM`)))throw new e(`INVALID_ARGS`,`Not a .dSYM bundle: ${t}`,{hint:`Pass the .dSYM bundle path, not the DWARF executable inside it.`})}function B(e,t){return t.split(`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{
|
|
1
|
+
import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{Gt as n,Ht as r,Kt as i,qt as a}from"./sdk-batch-runner.js";import{A as o,n as s,o as c}from"./sdk-android-adb.js";import{n as l}from"./shell-quote.js";import{t as u}from"./timeouts.js";import{h as d}from"./app-lifecycle.js";var f=e({dismissAndroidKeyboard:()=>y,dismissAndroidKeyboardWithAdb:()=>b,getAndroidKeyboardState:()=>_,getAndroidKeyboardStatusWithAdb:()=>v,readAndroidClipboardText:()=>j,readAndroidClipboardWithAdb:()=>M,writeAndroidClipboardText:()=>N,writeAndroidClipboardWithAdb:()=>P});const p=[`mInputShown`,`mIsInputViewShown`,`isInputViewShown`,`mDecorViewVisible`,`mWindowVisible`,`mInShowWindow`],m=new Map([[2,`number`],[3,`phone`],[4,`datetime`]]),h=new Set([32,208]),g=new Set([128,224,144]);async function _(e){return await v(c(e))}async function v(e){let t=await e([`shell`,`dumpsys`,`input_method`],{allowFailure:!0});if(t.exitCode!==0)throw s(`Failed to query Android keyboard state`,t);return x(t.stdout)}async function y(e){return await b(c(e))}async function b(e){let n=await v(e),r=n,i=0;for(;r.visible&&i<2;)await e([`shell`,`input`,`keyevent`,`111`]),i+=1,await u(120),r=await v(e);if(n.visible&&r.visible)throw new t(`UNSUPPORTED_OPERATION`,`Android keyboard dismiss is unavailable for the current IME without back navigation.`,{attempts:i,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,inputOwner:r.inputOwner});return{attempts:i,wasVisible:n.visible,dismissed:n.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,inputOwner:r.inputOwner}}function x(e){let t=E(e)??S(e),n=C(e),i=w(e,/\bpackageName=([A-Za-z0-9_.]+)\b/g),o=w(e,/\b(?:resourceId|resource-id)=([^\s,}]+)/g),s=a(e),c=r(i,o,s);return T(i,o,s),{visible:t??!1,inputType:n,type:n?A(n):void 0,inputMethodPackage:s,focusedPackage:i,focusedResourceId:o,inputOwner:c}}function S(e){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/)?.[1];if(!t)return null;let n=Number.parseInt(t,16);return Number.isNaN(n)?null:(n&1)!=0}function C(e){let t=w(e,/\binputType=0x([0-9a-fA-F]+)\b/gi);return t?`0x${t.toLowerCase()}`:void 0}function w(e,t){let n;for(let r of e.matchAll(t))n=r[1];return n}function T(e,t,r){r||!n(e)&&!i(t)||o({level:`warn`,phase:`android_input_ownership_fallback`,data:{focusedPackage:e,focusedResourceId:t}})}function E(e){return O(D(e,p))}function D(e,t){let n=new Map,r=RegExp(`\\b(${t.join(`|`)})=([a-zA-Z]+)\\b`,`g`);for(let t of e.matchAll(r)){let e=t[1],r=t[2]?.toLowerCase();!e||r!==`true`&&r!==`false`||n.set(e,r===`true`)}return n}function O(e){if(e.size===0)return null;let t=k(e,[`mWindowVisible`,`mDecorViewVisible`,`mInShowWindow`]);if(t!==void 0)return t;let n=e.get(`mInputShown`);return n===void 0?k(e,[`mIsInputViewShown`,`isInputViewShown`])??null:n}function k(e,t){for(let n of t){let t=e.get(n);if(t!==void 0)return t}}function A(e){let t=Number.parseInt(e.replace(/^0x/i,``),16);if(Number.isNaN(t))return`unknown`;let n=t&15,r=m.get(n);if(r)return r;if(n!==1)return`unknown`;let i=t&4080;return h.has(i)?`email`:g.has(i)?`password`:`text`}async function j(e){return await M(c(e))}async function M(e){return I(await F(e,[`shell`,`cmd`,`clipboard`,`get`,`text`],`read`))}async function N(e,t){await P(c(e),t)}async function P(e,t){await F(e,[`shell`,`cmd`,`clipboard`,`set`,`text`,l(t)],`write`)}async function F(e,n,r){let i=await e(n,{allowFailure:!0});if(d(i.stdout,i.stderr))throw new t(`UNSUPPORTED_OPERATION`,`Android shell clipboard ${r} is not supported on this device.`);if(i.exitCode!==0)throw s(`Failed to ${r} Android clipboard text`,i);return i.stdout}function I(e){let t=e.replace(/\r\n/g,`
|
|
2
2
|
`).replace(/\n$/,``),n=t.match(/^clipboard text:\s*(.*)$/i);return n?n[1]??``:t.trim().toLowerCase()===`null`?``:t}export{j as a,P as c,v as i,b as n,M as o,_ as r,N as s,f as t};
|
package/dist/src/dispatch.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{D as t,t as n}from"./location-coordinates.js";import{a as r,f as i,kt as a}from"./sdk-batch-runner.js";import{_ as o,b as s,c,h as l,l as u,m as d,s as f,y as ee}from"./sdk-device.js";import{Ht as p,Vt as m,at as te,it as h,n as g,ot as ne,st as re}from"./prepare-kind.js";import{G as _,V as ie,W as v,d as y,f as ae,i as oe,m as se,p as ce,u as le}from"./interaction.js";import{A as ue}from"./screenshot-result.js";import{a as de}from"./device.js";import{s as fe}from"./runtime.js";import{A as b,F as x}from"./sdk-android-adb.js";import{t as pe}from"./timeouts.js";import{i as S,r as me,t as C}from"./interactors.js";import{o as he,s as ge}from"./simctl.js";import{c as _e,o as ve,s as ye}from"./verified-file.js";import be from"node:path";import{AsyncLocalStorage as xe}from"node:async_hooks";import{promises as Se}from"node:fs";const w=new xe;async function Ce(t,n,r){let i=await we(t,n,r);if(i)return i;let a=await E(t,n,r);if(r.allowLocalSimulatorFallback!==!1&&O(n,a)){let e;try{[e]=await ve({platform:n.platform??`ios`,target:n.target,iosSimulatorSetPath:r.simulatorSetPath,kind:`simulator`})}catch(e){if(_e(e))throw e}if(e)return e}if(a)return a;throw new e(`DEVICE_NOT_FOUND`,`No devices found`,{selector:n})}async function we(t,n,r){let i=r.appleSimulatorAppTarget?.trim();if(!i||k(n)||r.allowLocalSimulatorFallback===!1)return;let a=t.filter(e=>l(e,n)&&c(e)&&e.kind===`simulator`&&e.booted===!0);if(a.length<2)return;let{findIosSimulatorInstalledApp:o}=await import(`./apps.js`).then(e=>e.t),s=(await Promise.all(a.map(async e=>await o(e,i)?e:void 0))).filter(e=>e!==void 0);if(s.length===1)return s[0];throw s.length===0?new e(`APP_NOT_INSTALLED`,`No booted iOS simulator has ${i} installed`,{appTarget:i,...T(a),hint:`Install the app on a booted simulator, or pass --udid to select the intended device explicitly.`}):new e(`AMBIGUOUS_MATCH`,`Multiple booted iOS simulators have ${i} installed`,{appTarget:i,...T(s),hint:`Pass --udid to select the intended simulator explicitly.`})}function T(e){return{devices:e.map(e=>({id:e.id,name:e.name}))}}async function E(e,t,n){try{return await s(e,t,n)}catch(e){if(D(e,t))return;throw e}}function D(t,n){return!k(n)&&t instanceof e&&t.code===`DEVICE_NOT_FOUND`}function O(e,t){return!k(e)&&(!e.platform||e.platform===`apple`||e.platform===`ios`)&&e.target!==`desktop`&&(!t||t.kind===`device`)}function k(e){return!!(e.udid||e.serial||e.deviceName)}async function Te(e,t={}){let n={...A(e),androidAvdSelection:t.androidAvdSelection??`running-only`},{iosSimulatorSetPath:r,...i}=n,a=Ae(n,t),o={simulatorSetPath:r},c={platform:n.platform,target:e.target,cacheHit:!1};return await x(`resolve_target_device`,async()=>{let e=ke(a);if(e)return c.cacheHit=!0,e;let l=await ye(n),u=[...l.devices];return Oe(i)?j(a,await Ce(u,i,{simulatorSetPath:r,allowLocalSimulatorFallback:l.source===`local`||n.leaseProvider===void 0,appleSimulatorAppTarget:t.appleSimulatorAppTarget})):j(a,await s(u,i,o))},c)}function A(t){let n=t.platform;if(t.target&&!n)throw new e(`INVALID_ARGS`,`Device target selector requires --platform. Use --platform ios|macos|android|vega|linux|apple with --target mobile|tv|desktop.`);let r=ee({simulatorSetPath:ge(t.iosSimulatorDeviceSet),platform:n,target:t.target}),i=he(t.androidDeviceAllowlist);return{platform:n,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial,leaseId:t.leaseId,leaseProvider:t.leaseProvider,deviceKey:t.deviceKey,clientId:t.clientId,iosSimulatorSetPath:r,androidSerialAllowlist:i?Array.from(i).sort():void 0}}async function Ee(e){return w.getStore()?await e():await w.run(new Map,e)}function De(e){return f(e.platform)}function Oe(e){return De(e)}function ke(e){let t=w.getStore()?.get(e);if(t)return{...t}}function j(e,t){return w.getStore()?.set(e,{...t}),t}function Ae(e,t){let{appleSimulatorAppTarget:n,...r}=t;return JSON.stringify({request:e,options:r})}me();const je={device:!0},Me={emulator:!0,device:!0},Ne=new Set([`perf`,`back`,`app-switcher`,`click`,`fill`,`find`,`focus`,`get`,`home`,`gesture`,`keyboard`,`is`,`longpress`,`press`,`screenshot`,`scroll`,`settings`,`snapshot`,`swipe`,`type`,`wait`]),Pe=[`audio`,`find`,`get`,`is`,`screenshot`,`snapshot`,`wait`],Fe=[`click`,`fill`,`focus`,`press`,`scroll`,`type`],Ie=[`viewport`],M=new Set([...Pe,...Fe,...Ie]),N=Le(r(i));function Le(e){let t={};for(let[n,r]of Object.entries(e))t[n]=Ne.has(n)?{...r,harmonyos:Me}:r;return Re(t)}function Re(e){let t={};for(let[n,r]of Object.entries(e))t[n]=M.has(n)?{...r,web:je}:r;for(let t of M)if(!(t in e))throw Error(`Web command "${t}" missing from capability matrix`);return t}function P(e,t){let n=N[e];if(!n)return!0;let r=S(t.platform);if(!r)return!1;let i=n[r.capability.bucket];if(!i)return!1;let a=r.capability.supportsByDefault?.[e];return a&&!a(t)?!1:i[t.kind??`unknown`]===!0}function ze(e,t){return S(t.platform)?.capability.unsupportedHintByDefault?.[e]?.(t)}function Be(){return i.filter(e=>e.catalog.group===`public`&&(`capability`in e&&e.capability!==void 0||e.platformExecution.kind===`device-runtime`)).map(e=>e.name).sort()}function Ve(e){let t=N[e];if(!t)return[];let n=[`apple`,`android`,`harmonyos`,`vega`,`linux`,`web`],r=[];for(let e of n){let n=t[e];n&&Object.values(n).some(e=>e===!0)&&r.push(e)}return r}function He(e,t){if(e.intent===`drag`){Ue(e,t);return}if(t.platform===`web`||t.appleOs===`watchos`)throw I(e,F(e,t));if(Ge(e)){Ke(e,t);return}if(t.appleOs===`visionos`)throw I(e,F(e,t));if(e.intent===`fling`&&`direction`in e&&t.platform===`linux`)throw I(e,`gesture fling is not supported on Linux`)}function Ue(e,t){if(!We(t))throw I(e,F(e,t),`Target-authored drag requires an adapter that preserves source hold, timed movement, and destination hold; it is supported on Android touch devices and iOS/iPadOS.`)}function We(e){return e.platform===`android`?e.target!==`tv`:e.platform===`apple`?e.appleOs===void 0?e.target!==`desktop`&&e.target!==`tv`:e.appleOs===`ios`||e.appleOs===`ipados`:!1}function Ge(e){return e.intent===`pan`?(`pointerCount`in e?e.pointerCount:1)===2:e.intent===`pinch`||e.intent===`rotate`||e.intent===`transform`}function Ke(e,t){if(t.platform===`android`){if(t.target!==`tv`)return;throw I(e,`gesture ${e.intent} is not supported on Android TV`,`Android TV has no touch input — this gesture is supported on Android phones, tablets, and the iOS simulator only.`)}if(t.platform!==`apple`)throw I(e,F(e,t));a(t,e.intent)}function F(e,t){return`gesture ${e.intent} is not supported on ${t.appleOs??t.platform}`}function I(t,n,r){return new e(`UNSUPPORTED_OPERATION`,n,{gesture:t.intent,...r?{hint:r}:{}})}const L=`No active session. Run open first.`;function R(e,t,n,r){return{ok:!1,error:{code:e,message:t,...r?.hint?{hint:r.hint}:{},...r?.retriable===void 0?{}:{retriable:r.retriable},...n?{details:n}:{}}}}function qe(){return R(`SESSION_NOT_FOUND`,L)}function Je(e,t,n){if(P(e,t))return null;let r=n?.hint?ze(e,t):void 0;return{ok:!1,error:{code:`UNSUPPORTED_OPERATION`,message:n?.message??`${e} is not supported on this device`,...r?{hint:r}:{}}}}const Ye=/^[A-Za-z0-9_.:-]{1,64}$/,z=8*1024,B=4*1024;function Xe(t){let n=t[0]?.trim(),r=t[1]?.trim();if(!n)throw new e(`INVALID_ARGS`,`trigger-app-event requires <event> [payloadJson]`);if(!Ye.test(n))throw new e(`INVALID_ARGS`,`Invalid trigger-app-event event name: ${n}`,{hint:`Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash.`});if(t.length>2)throw new e(`INVALID_ARGS`,`trigger-app-event accepts at most two arguments: <event> [payloadJson]`);return{eventName:n,payload:Qe(r,n)}}function Ze(t,n,r){let i=o(t),a=$e(t);if(!a)throw new e(`UNSUPPORTED_OPERATION`,`No app event URL template configured for ${i}.`,{hint:`Set AGENT_DEVICE_${i.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let s=r?JSON.stringify(r):``,c=a.replaceAll(`{event}`,encodeURIComponent(n)).replaceAll(`{payload}`,encodeURIComponent(s)).replaceAll(`{platform}`,encodeURIComponent(i));if(c.length>B)throw new e(`INVALID_ARGS`,`trigger-app-event URL exceeds maximum supported length`,{hint:`Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.`,length:c.length,maxLength:B});return c}function Qe(t,n){if(t)try{let r=JSON.parse(t);if(!r||typeof r!=`object`||Array.isArray(r))throw new e(`INVALID_ARGS`,`trigger-app-event payload for "${n}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,`utf8`)>z)throw new e(`INVALID_ARGS`,`trigger-app-event payload for "${n}" exceeds ${z} bytes`);return r}catch(n){throw n instanceof e?n:new e(`INVALID_ARGS`,`Invalid trigger-app-event payload JSON: ${t}`)}}function $e(e){return((c(e)?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:u(e)?process.env.AGENT_DEVICE_MACOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE)?.trim()||void 0}function et(e){let t=e?e.textEntryReadiness:void 0,n=at(t)?{textEntryReadiness:t}:{},r=tt(e);return r?{...n,...r}:n}function tt(e){if(!nt(e))return null;let t=rt(e.target);return t?{verification:`unconfirmed`,requested:e.requested,before:e.before,after:e.after,target:t}:null}function nt(e){return!!(e&&e.verification===`unconfirmed`&&typeof e.requested==`string`&&V(e.before)&&V(e.after))}function rt(e){if(!H(e)||!it(e))return null;let t=ot(e.rect);return t?{resourceId:e.resourceId,className:e.className,packageName:e.packageName,rect:t}:null}function it(e){return V(e.resourceId)&&V(e.className)&&V(e.packageName)}function at(e){return typeof e==`string`&&ce.includes(e)}function V(e){return e===null||typeof e==`string`}function ot(e){return!H(e)||![e.x,e.y,e.width,e.height].every(e=>typeof e==`number`)?null:e}function H(e){return!!e&&typeof e==`object`}const U=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function st(e,t){return f(e.platform)&&t>1}function ct(e,t,n=2e4){if(e.length===0)return[];let r=t>0?t:e.length,i=[],a=[],o=0;for(let t of e){let e=(t.durationMs??0)+(t.pauseMs??0)+250,s=a.length>0&&o+e>n,c=a.length>=r;(s||c)&&(i.push(a),a=[],o=0),a.push(t),o+=e}return a.length>0&&i.push(a),i}function W(e,t){if(t<=0)return[0,0];let[n,r]=U[e%U.length];return[n*t,r*t]}async function lt(e,t,n){for(let r=0;r<e;r+=1)await n(r),r<e-1&&t>0&&await pe(t)}async function ut(e,t){let{x:n,y:r}=G(t,`longpress requires x y [durationMs]`,{hint:`Direct platform longpress requires coordinates. In an open daemon session, use agent-device longpress @ref|selector [durationMs]; otherwise run snapshot -i, use the target rect center as x y, then retry longpress x y durationMs.`}),i=t[2]?Number(t[2]):void 0;return await e.longPress(n,r,i),{x:n,y:r,durationMs:i,...m(`Long pressed (${n}, ${r})`)}}async function dt(e,t){let{x:n,y:r}=G(t,`focus requires x y`);return await e.focus(n,r),{x:n,y:r,...m(`Focused (${n}, ${r})`)}}async function ft(t,n,r){let i=It(n);if(i)throw new e(`INVALID_ARGS`,`type does not accept a target ref like "${i}"`,{hint:`Use fill ${i} "text" to target that field, or press ${i} then type "text" to append.`});let a=n.join(` `);if(!a)throw new e(`INVALID_ARGS`,`type requires text`);let o=h(r?.delayMs??0,`delay-ms`,0,1e4),s=(await t.type(a,o))?.textEntryRoute;return{...s===void 0?{}:{textEntryRoute:s},text:a,delayMs:o,...m(Y(`Typed`,a))}}async function pt(t,n,r){if(r?.directElementSelector)return await mt(t,r.directElementSelector,n,r);let i=Number(n[0]),a=Number(n[1]),o=n.slice(2).join(` `);if(Number.isNaN(i)||Number.isNaN(a)||!o)throw new e(`INVALID_ARGS`,`fill requires x y text`);let s=h(r?.delayMs??0,`delay-ms`,0,1e4),c=await t.fill(i,a,o,s,{allowNonHittableCoordinateFallback:r?.allowNonHittableCoordinateFallback===!0});return{x:i,y:a,text:o,delayMs:s,...c?.maestroNonHittableCoordinateFallbackUsed===!0?{maestroNonHittableCoordinateFallbackUsed:!0}:{},...et(c),...m(Y(`Filled`,o))}}async function mt(t,n,r,i){if(!t.fillElementSelector)throw new e(`UNSUPPORTED_OPERATION`,`direct element selector fill is not supported`);let a=r.join(` `);if(!a)throw new e(`INVALID_ARGS`,`fill requires text`);let o=h(i.delayMs??0,`delay-ms`,0,1e4),s=await t.fillElementSelector(n,a,o);return{selector:n.raw,text:a,delayMs:o,...s??{},...m(Y(`Filled`,a))}}async function ht(e,t,n,r){if(r?.directElementSelector&&c(e))return await gt(t,r.directElementSelector);let{x:i,y:a}=G(n,`press requires x y`);if(u(e)&&r?.surface&&r.surface!==`app`)return await _t(i,a,r);let o=_(r);if(o!==`primary`)return await vt(e,i,a,o,r);let s=xt(r);return St(s),st(e,s.count)?await wt(e,i,a,s,r):await Dt(t,i,a,s)}async function gt(t,n){if(!t.tapElementSelector)throw new e(`UNSUPPORTED_OPERATION`,`direct element selector tap is not supported`);let r=await t.tapElementSelector(n),i=r?.maestroNonHittableCoordinateFallbackUsed===!0;return{selector:n.raw,...r??{},...m(i?se:`Tapped ${n.raw}`)}}function G(t,n,r){let i=Number(t[0]),a=Number(t[1]);if(Number.isNaN(i)||Number.isNaN(a))throw new e(`INVALID_ARGS`,n,r);return{x:i,y:a}}async function _t(t,n,r){let i=_(r);if(i!==`primary`)throw new e(`UNSUPPORTED_OPERATION`,`${i} click is not supported on macOS ${r.surface} sessions.`);let{runMacOsPressAction:a}=await import(`./helper.js`).then(e=>e.t);return await a(t,n,{bundleId:r.appBundleId,surface:r.surface}),{x:t,y:n,...m(J({x:t,y:n}))}}async function vt(e,t,n,r,i){if(yt(e,r,i),e.platform===`linux`)return await bt(t,n,r);let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r);return await a(e,{command:`mouseClick`,x:t,y:n,button:r,appBundleId:i?.appBundleId},q(i)),{x:t,y:n,button:r,...m(J({x:t,y:n,button:r}))}}function yt(e,t,n){let r=v({commandLabel:`click`,platform:o(e),button:t,count:n?.count,intervalMs:n?.intervalMs,holdMs:n?.holdMs,jitterPx:n?.jitterPx,doubleTap:n?.doubleTap});if(r)throw r}async function bt(e,t,n){if(n===`secondary`){let{rightClickLinux:n}=await import(`./input-actions3.js`);await n(e,t)}else{let{middleClickLinux:n}=await import(`./input-actions3.js`);await n(e,t)}return{x:e,y:t,button:n,...m(J({x:e,y:t,button:n}))}}function xt(e){return{count:K(e?.count,1,`count`,1,200),intervalMs:K(e?.intervalMs,0,`interval-ms`,0,1e4),holdMs:K(e?.holdMs,0,`hold-ms`,0,1e4),jitterPx:K(e?.jitterPx,0,`jitter-px`,0,100),doubleTap:!!e?.doubleTap}}function K(e,t,n,r,i){return h(e===void 0?t:e,n,r,i)}function St({doubleTap:t,holdMs:n,jitterPx:r}){if(t&&n>0)throw new e(`INVALID_ARGS`,`double-tap cannot be combined with hold-ms`);if(t&&r>0)throw new e(`INVALID_ARGS`,`double-tap cannot be combined with jitter-px`)}async function Ct(e,t,n){let{runAppleRunnerCommand:r}=await import(`./runner-client.js`).then(e=>e.r),{MAX_RUNNER_SEQUENCE_STEPS:i,buildRunnerSequenceCommand:a,parseRunnerSequenceResult:o}=await import(`./runner-sequence.js`).then(e=>e.r),s=ct(t,i),c,l,u=0,d=[],f=0;for(let t of s){let i=await r(e,a(t,n?.appBundleId),q(n));c??=i,l=i;let s;try{s=o(i)}catch(e){throw Et(e,f)}u+=s.completedSteps,d.push(...s.results),f+=t.length}return{...c??{},completedSteps:u,sequenceResults:d,...l?.gestureEndUptimeMs===void 0?{}:{gestureEndUptimeMs:l.gestureEndUptimeMs}}}async function wt(e,t,n,r,i){let a=await Ct(e,Tt(e,t,n,r),i);return{x:t,y:n,count:r.count,intervalMs:r.intervalMs,holdMs:r.holdMs,jitterPx:r.jitterPx,doubleTap:r.doubleTap,timingMode:`runner-sequence`,...a,...m(J({x:t,y:n}))}}function Tt(e,t,n,r){let i=r.doubleTap?`doubleTap`:r.holdMs>0?`longPress`:`tap`,a=i===`tap`&&c(e)&&!d(e);return Array.from({length:r.count},(e,o)=>{let[s,c]=W(o,r.jitterPx),l=o===r.count-1;return{kind:i,x:t+s,y:n+c,...a?{synthesized:!0}:{},...r.holdMs>0?{durationMs:r.holdMs}:{},...!l&&r.intervalMs>0?{pauseMs:r.intervalMs}:{}}})}function Et(t,n){if(n===0||!(t instanceof e)||!t.details)return t;let r=t.details.failedStepIndex;if(typeof r!=`number`)return t;let i=t.details.completedSteps;return new e(t.code,t.message,{...t.details,failedStepIndex:r+n,chunkStepIndex:r,...typeof i==`number`?{completedSteps:n+i}:{}},t.cause)}async function Dt(e,t,n,r){let i;return await lt(r.count,r.intervalMs,async a=>{let[o,s]=W(a,r.jitterPx),c=t+o,l=n+s;if(r.doubleTap){let t=await e.doubleTap(c,l);i??=t??void 0;return}if(r.holdMs>0){let t=await e.longPress(c,l,r.holdMs);i??=t??void 0}else{let t=await e.tap(c,l);i??=t??void 0}}),p({x:t,y:n,count:r.count,intervalMs:r.intervalMs,holdMs:r.holdMs,jitterPx:r.jitterPx,doubleTap:r.doubleTap,...i},J({x:t,y:n}))}function q(e){return{verbose:e?.verbose,logPath:e?.logPath,traceLogPath:e?.traceLogPath,requestId:e?.requestId,iosXctestrunFile:e?.iosXctestrunFile,iosXctestDerivedDataPath:e?.iosXctestDerivedDataPath,iosXctestEnvDir:e?.iosXctestEnvDir}}async function Ot(t,n,r){let i=n[0],a=n[1]?Number(n[1]):void 0,o=r?.pixels,s=r?.durationMs;if(!i)throw new e(`INVALID_ARGS`,`scroll requires direction`);kt(a,o,s);let c=Pt(i),l={amount:a,pixels:o,durationMs:s},{interactionResult:u,completedPasses:d}=await jt(t,r,c,l);return p(Mt(c,l,d,u),ne(c.direction,c.edge,d,a,o))}function kt(e,t,n){At(e),ae(n),le({amount:e,pixels:t})}function At(t){if(t!==void 0&&!Number.isFinite(t))throw new e(`INVALID_ARGS`,`scroll amount must be a number`)}async function jt(e,t,n,r){if(n.edge){let i=n.edge,a=await re({edge:i,captureState:async n=>await Nt(e,t,i,n),scroll:async()=>await e.scroll(n.direction,r)});return{interactionResult:a.result??{},completedPasses:a.passes}}return{interactionResult:await e.scroll(n.direction,r)??{},completedPasses:1}}function Mt(e,t,n,r){let i=y(r);return{direction:e.direction,...e.edge?{edge:e.edge,passes:n}:{},...t.amount===void 0?{}:{amount:t.amount},...t.pixels===void 0?{}:{pixels:t.pixels},...i===void 0?{}:{durationMs:i},...r}}async function Nt(t,n,r,i){if(typeof t.snapshot!=`function`)throw new e(`UNSUPPORTED_OPERATION`,`scroll ${r} requires snapshot support to verify hidden content before scrolling`);let a=t.snapshot;return await te({edge:r,scope:i,captureNodes:async e=>(await a({appBundleId:n?.appBundleId,scope:e})).nodes??[]})}function Pt(e){return e===`bottom`?{direction:`down`,edge:`bottom`}:e===`top`?{direction:`up`,edge:`top`}:{direction:ie(e)}}async function Ft(e,t,n){let{x:r,y:i}=G(t,`read requires x y`);if(e.platform===`android`){let{readAndroidTextAtPoint:t}=await import(`./input-actions.js`).then(e=>e.s);return{action:`read`,text:await t(e,r,i)??``}}if(e.platform===`linux`){let{readLinuxTextAtPoint:e}=await import(`./snapshot2.js`).then(e=>e.n);return{action:`read`,text:await e(r,i,n?.surface)}}if(u(e)&&n?.surface&&n.surface!==`app`){let{runMacOsReadTextAction:e}=await import(`./helper.js`).then(e=>e.t);return{action:`read`,text:(await e(r,i,{bundleId:n.appBundleId,surface:n.surface})).text}}let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r),o=await a(e,{command:`readText`,x:r,y:i,appBundleId:n?.appBundleId},{verbose:n?.verbose,logPath:n?.logPath,traceLogPath:n?.traceLogPath,requestId:n?.requestId,iosXctestrunFile:n?.iosXctestrunFile,iosXctestDerivedDataPath:n?.iosXctestDerivedDataPath,iosXctestEnvDir:n?.iosXctestEnvDir});return{action:`read`,text:typeof o.text==`string`?o.text:typeof o.message==`string`?o.message:``}}function It(e){return fe(e[0])}function J(e){return e.button&&e.button!==`primary`?`Clicked ${e.button} (${e.x}, ${e.y})`:`Tapped (${e.x}, ${e.y})`}function Y(e,t){return`${e} ${Array.from(t).length} chars`}async function Lt(e,t,n,r,i){let a=X(i);return await Rt(e,await C(e,a),t,n,r,i,a)}async function Rt(e,t,n,r,i,a,o){return b({level:`debug`,phase:`platform_command_prepare`,data:{command:n,platform:e.platform,kind:e.kind}}),await x(`platform_command`,async()=>await Vt(e,t,n,r,i,a,o),{command:n,platform:e.platform})}async function zt(t,n,r){let i=await C(t,X(r));if(!i.performGesture)throw new e(`UNSUPPORTED_OPERATION`,`Gesture execution is unavailable`);return await i.performGesture(n)}async function Bt(e,t){return await(await C(e,X(t))).gestureViewport?.()}function X(e){return{requestId:e?.requestId,signal:e?.signal,appBundleId:e?.appBundleId,verbose:e?.verbose,logPath:e?.logPath,traceLogPath:e?.traceLogPath,iosXctestrunFile:e?.iosXctestrunFile,iosXctestDerivedDataPath:e?.iosXctestDerivedDataPath,iosXctestEnvDir:e?.iosXctestEnvDir,runnerLeaseContext:e?.runnerLeaseContext}}const Z={press:({device:e,interactor:t,positionals:n,context:r})=>ht(e,t,n,r),longpress:({interactor:e,positionals:t})=>ut(e,t),focus:({interactor:e,positionals:t})=>dt(e,t),type:({interactor:e,positionals:t,context:n})=>ft(e,t,n),fill:({interactor:e,positionals:t,context:n})=>pt(e,t,n),scroll:({interactor:e,positionals:t,context:n})=>Ot(e,t,n),"trigger-app-event":({device:e,interactor:t,positionals:n,context:r})=>Ht(e,t,n,r),screenshot:({interactor:e,positionals:t,outPath:n,context:r})=>Ut(e,t,n,r),viewport:({interactor:e,positionals:t})=>Wt(e,t),back:async({interactor:e,context:t})=>(await e.back(t?.backMode),{action:`back`,mode:t?.backMode??`in-app`,...m(`Back`)}),home:async({interactor:e})=>(await e.home(),{action:`home`,...m(`Home`)}),orientation:async({interactor:e,positionals:t})=>{let n=de(t[0]),r=(await e.setOrientation(n))?.orientation??n;return{action:`orientation`,orientation:r,...m(`Rotated to ${r}`)}},"app-switcher":async({interactor:e})=>(await e.appSwitcher(),{action:`app-switcher`,...m(`Opened app switcher`)}),clipboard:({interactor:e,positionals:t})=>Gt(e,t),keyboard:({device:e,positionals:t,context:n,runnerCtx:r})=>qt(e,t,n,r),"tv-remote":({device:e,interactor:t,positionals:n,context:r})=>Kt(e,t,n,r),settings:({device:e,interactor:t,positionals:n,context:r})=>Zt(e,t,n,r),snapshot:({interactor:e,context:t})=>nn(e,t),read:({device:e,positionals:t,context:n})=>Ft(e,t,n)};async function Vt(t,n,r,i,a,o,s){let c=Object.hasOwn(Z,r)?Z[r]:void 0;if(!c)throw new e(`INVALID_ARGS`,`Unknown command: ${r}`);return await c({device:t,interactor:n,positionals:i,outPath:a,context:o,runnerCtx:s})}async function Ht(e,t,n,r){let{eventName:i,payload:a}=Xe(n),o=Ze(e,i,a);return await t.open(o,{appBundleId:r?.appBundleId}),{event:i,eventUrl:o,transport:`deep-link`,...m(`Triggered app event: ${i}`)}}async function Ut(e,n,r,i){let a=n[0]??r??`./screenshot-${Date.now()}.png`;await Se.mkdir(be.dirname(a),{recursive:!0});let o=t(i);return await e.screenshot(a,{appBundleId:i?.appBundleId,pixelDensity:o.pixelDensity,fullscreen:o.fullscreen,normalizeStatusBar:o.normalizeStatusBar,stabilize:o.stabilize,surface:i?.surface,skipIosSimulatorBootCheck:i?.skipIosSimulatorBootCheck,captureBackend:i?.screenshotCaptureBackend}),{path:a,...m(`Saved screenshot: ${a}`)}}async function Wt(t,n){if(n.length!==2)throw new e(`INVALID_ARGS`,`viewport requires exactly two arguments: <width> <height>`);let r=g(n[0],`width`),i=g(n[1],`height`);if(!t.setViewport)throw new e(`UNSUPPORTED_OPERATION`,`viewport is not supported by this backend`);return await t.setViewport(r,i),{width:r,height:i,...m(`Viewport set: ${r}x${i}`)}}async function Gt(t,n){let r=(n[0]??``).toLowerCase();if(r!==`read`&&r!==`write`)throw new e(`INVALID_ARGS`,`clipboard requires a subcommand: read or write`);if(r===`read`){if(n.length!==1)throw new e(`INVALID_ARGS`,`clipboard read does not accept additional arguments`);return{action:r,text:await t.readClipboard()}}if(n.length<2)throw new e(`INVALID_ARGS`,`clipboard write requires text (use "" to clear clipboard)`);let i=n.slice(1).join(` `);return await t.writeClipboard(i),{action:r,textLength:Array.from(i).length,...m(`Clipboard updated`)}}async function Kt(t,n,r,i){if(t.target!==`tv`)throw new e(`UNSUPPORTED_OPERATION`,`tv-remote is supported only on TV targets`,{hint:`Select an Android TV, tvOS, or Vega OS target with --target tv.`});if(r.length!==1)throw new e(`INVALID_ARGS`,`tv-remote requires exactly one button`);let a=oe(r[0]),o=i?.durationMs===void 0?void 0:h(i.durationMs,`durationMs`,0,1e4);return await n.tvRemote(a,o),{action:`tv-remote`,button:a,...o===void 0?{}:{durationMs:o},...m(`Pressed TV remote ${a}`)}}async function qt(t,n,r,i){let a=(n[0]??`status`).toLowerCase();if(!ue(a))throw new e(`INVALID_ARGS`,`keyboard requires a subcommand: status, get, dismiss, enter, or return`);if(n.length>1)throw new e(`INVALID_ARGS`,`keyboard accepts at most one subcommand argument`);if(t.platform===`android`)return await Jt(t,a);if(t.platform===`harmonyos`)return await Q(t,a);if(c(t))return await Yt(t,a,r,i);throw new e(`UNSUPPORTED_OPERATION`,`keyboard is supported only on Android, HarmonyOS, and iOS`)}async function Q(t,n){if(n!==`dismiss`&&n!==`enter`&&n!==`return`)throw new e(`UNSUPPORTED_OPERATION`,`keyboard status/get is not available through the public HarmonyOS HDC API; use keyboard dismiss or enter`);let{pressHarmonyKeyboardKey:r}=await import(`./input-actions2.js`);return await r(t,n===`dismiss`?`Back`:`Enter`),{platform:`harmonyos`,action:n===`dismiss`?`dismiss`:`enter`,...m(n===`dismiss`?`Keyboard dismissed`:`Keyboard enter pressed`)}}async function Jt(e,t){if(t===`enter`||t===`return`){let{pressAndroidEnter:t}=await import(`./input-actions.js`).then(e=>e.s);return await t(e),{platform:`android`,action:`enter`,...m(`Keyboard enter pressed`)}}if(t===`dismiss`){let{dismissAndroidKeyboard:t}=await import(`./device-input-state.js`).then(e=>e.t),n=await t(e);return{platform:`android`,action:`dismiss`,attempts:n.attempts,wasVisible:n.wasVisible,dismissed:n.dismissed,visible:n.visible,inputType:n.inputType,type:n.type,inputMethodPackage:n.inputMethodPackage,focusedPackage:n.focusedPackage,focusedResourceId:n.focusedResourceId,inputOwner:n.inputOwner}}let{getAndroidKeyboardState:n}=await import(`./device-input-state.js`).then(e=>e.t),r=await n(e);return{platform:`android`,action:`status`,visible:r.visible,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,inputOwner:r.inputOwner}}async function Yt(t,n,r,i){if(n!==`dismiss`&&n!==`enter`&&n!==`return`)throw new e(`UNSUPPORTED_OPERATION`,`keyboard status/get is currently supported only on Android; use keyboard dismiss or enter on iOS`);if(n===`enter`||n===`return`){let{runAppleRunnerCommand:e}=await import(`./runner-client.js`).then(e=>e.r),n=await e(t,{command:`keyboardReturn`,appBundleId:r?.appBundleId},i);return{platform:`ios`,action:`enter`,visible:n.visible,wasVisible:n.wasVisible,...m(`Keyboard enter pressed`)}}let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r),o=await a(t,{command:`keyboardDismiss`,appBundleId:r?.appBundleId},i),s=typeof o.keyboardDismissMechanism==`string`?o.keyboardDismissMechanism:void 0;return{platform:`ios`,action:`dismiss`,wasVisible:o.wasVisible,dismissed:o.dismissed,visible:o.visible,mechanism:s,...m(Xt(o.dismissed===!0,s))}}function Xt(e,t){return e?t===`dismissKey`?`Keyboard dismissed via its dismiss key`:`Keyboard dismissed`:`Keyboard already hidden`}async function Zt(t,n,r,i){let[a,o,s,c]=r;if(!a||!o&&a!==`clear-app-state`)throw new e(`INVALID_ARGS`,`settings requires setting state`);if(a===`clear-app-state`)return await Qt(t,n,o,s,i);if(!o)throw new e(`INVALID_ARGS`,`settings requires setting state`);return await $t(t,n,a,o,s,c,r,i)}async function Qt(t,n,r,i,a){let o=(r===`clear`?i:r)??a?.appBundleId;if(!o)throw new e(`INVALID_ARGS`,`settings clear-app-state requires an app id or an active app session.`);b({level:`debug`,phase:`settings_apply`,data:{setting:`clear-app-state`,state:`clear`,appBundleId:o,platform:t.platform}});let s=await n.setSetting(`clear-app-state`,`clear`,o);return s&&typeof s==`object`?p({setting:`clear-app-state`,state:`clear`,...s},$(s)??`Cleared user data for ${o}`):{setting:`clear-app-state`,state:`clear`,...m(`Cleared user data for ${o}`)}}async function $t(e,t,n,r,i,a,o,s){let c=n===`location`&&r===`set`,l=(n===`permission`||c?o[4]:o[2])??s?.appBundleId;b({level:`debug`,phase:`settings_apply`,data:tn(e,n,r,i,a,l,c)});let u=await t.setSetting(n,r,l,en(n,i,a,c));return u&&typeof u==`object`?p({setting:n,state:r,...u},$(u)??`Updated setting: ${n}`):{setting:n,state:r,...m(`Updated setting: ${n}`)}}function en(e,t,r,i){if(e===`permission`)return{permissionTarget:t,permissionMode:r};if(i)return{latitude:n(t,`latitude`),longitude:n(r,`longitude`)}}function tn(e,t,n,r,i,a,o){return o?{setting:t,state:n,latitude:r,longitude:i,platform:e.platform}:t===`permission`?{setting:t,state:n,permissionTarget:r,permissionMode:i,platform:e.platform}:{setting:t,state:n,appBundleId:a,platform:e.platform}}async function nn(e,t){let n=t??{};return await e.snapshot({appBundleId:n.appBundleId,signal:n.signal,interactiveOnly:n.snapshotInteractiveOnly,preferredBackend:n.snapshotPreferredBackend,depth:n.snapshotDepth,scope:n.snapshotScope,raw:n.snapshotRaw,customActions:n.snapshotCustomActions,includeRects:n.snapshotIncludeRects,includeHiddenContentHints:n.snapshotIncludeHiddenContentHints,surface:n.surface})}function $(e){return typeof e.message==`string`&&e.message.length>0?e.message:void 0}export{R as a,P as c,Ve as d,A as f,L as i,Be as l,Ee as m,zt as n,qe as o,Te as p,Bt as r,Je as s,Lt as t,He as u};
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{D as t,t as n}from"./location-coordinates.js";import{Ft as r,a as i,f as a}from"./sdk-batch-runner.js";import{_ as o,b as s,c,h as l,l as u,m as d,s as f,y as ee}from"./sdk-device.js";import{bn as p,c as m,ft as h,ht as te,mt as ne,pt as re,yn as g}from"./script-source-bundle.js";import{G as _,V as ie,W as v,d as y,f as ae,i as oe,m as se,p as ce,u as le}from"./interaction.js";import{M as ue}from"./screenshot-result.js";import{a as de}from"./device.js";import{s as fe}from"./runtime.js";import{A as b,F as x}from"./sdk-android-adb.js";import{t as pe}from"./timeouts.js";import{i as S,r as me,t as C}from"./interactors.js";import{o as he,s as ge}from"./simctl.js";import{d as _e,f as ve,u as ye}from"./verified-file.js";import be from"node:path";import{promises as xe}from"node:fs";import{AsyncLocalStorage as Se}from"node:async_hooks";const w=new Se;async function Ce(t,n,r){let i=await we(t,n,r);if(i)return i;let a=await E(t,n,r);if(r.allowLocalSimulatorFallback!==!1&&O(n,a)){let e;try{[e]=await ye({platform:n.platform??`ios`,target:n.target,iosSimulatorSetPath:r.simulatorSetPath,kind:`simulator`})}catch(e){if(ve(e))throw e}if(e)return e}if(a)return a;throw new e(`DEVICE_NOT_FOUND`,`No devices found`,{selector:n})}async function we(t,n,r){let i=r.appleSimulatorAppTarget?.trim();if(!i||k(n)||r.allowLocalSimulatorFallback===!1)return;let a=t.filter(e=>l(e,n)&&c(e)&&e.kind===`simulator`&&e.booted===!0);if(a.length<2)return;let{findIosSimulatorInstalledApp:o}=await import(`./apps.js`).then(e=>e.t),s=(await Promise.all(a.map(async e=>await o(e,i)?e:void 0))).filter(e=>e!==void 0);if(s.length===1)return s[0];throw s.length===0?new e(`APP_NOT_INSTALLED`,`No booted iOS simulator has ${i} installed`,{appTarget:i,...T(a),hint:`Install the app on a booted simulator, or pass --udid to select the intended device explicitly.`}):new e(`AMBIGUOUS_MATCH`,`Multiple booted iOS simulators have ${i} installed`,{appTarget:i,...T(s),hint:`Pass --udid to select the intended simulator explicitly.`})}function T(e){return{devices:e.map(e=>({id:e.id,name:e.name}))}}async function E(e,t,n){try{return await s(e,t,n)}catch(e){if(D(e,t))return;throw e}}function D(t,n){return!k(n)&&t instanceof e&&t.code===`DEVICE_NOT_FOUND`}function O(e,t){return!k(e)&&(!e.platform||e.platform===`apple`||e.platform===`ios`)&&e.target!==`desktop`&&(!t||t.kind===`device`)}function k(e){return!!(e.udid||e.serial||e.deviceName)}async function Te(e,t={}){let n={...A(e),androidAvdSelection:t.androidAvdSelection??`running-only`},{iosSimulatorSetPath:r,...i}=n,a=Ae(n,t),o={simulatorSetPath:r},c={platform:n.platform,target:e.target,cacheHit:!1};return await x(`resolve_target_device`,async()=>{let e=ke(a);if(e)return c.cacheHit=!0,e;let l=await _e(n),u=[...l.devices];return Oe(i)?j(a,await Ce(u,i,{simulatorSetPath:r,allowLocalSimulatorFallback:l.source===`local`||n.leaseProvider===void 0,appleSimulatorAppTarget:t.appleSimulatorAppTarget})):j(a,await s(u,i,o))},c)}function A(t){let n=t.platform;if(t.target&&!n)throw new e(`INVALID_ARGS`,`Device target selector requires --platform. Use --platform ios|macos|android|vega|linux|apple with --target mobile|tv|desktop.`);let r=ee({simulatorSetPath:ge(t.iosSimulatorDeviceSet),platform:n,target:t.target}),i=he(t.androidDeviceAllowlist);return{platform:n,target:t.target,deviceName:t.device,udid:t.udid,serial:t.serial,leaseId:t.leaseId,leaseProvider:t.leaseProvider,deviceKey:t.deviceKey,clientId:t.clientId,iosSimulatorSetPath:r,androidSerialAllowlist:i?Array.from(i).sort():void 0}}async function Ee(e){return w.getStore()?await e():await w.run(new Map,e)}function De(e){return f(e.platform)}function Oe(e){return De(e)}function ke(e){let t=w.getStore()?.get(e);if(t)return{...t}}function j(e,t){return w.getStore()?.set(e,{...t}),t}function Ae(e,t){let{appleSimulatorAppTarget:n,...r}=t;return JSON.stringify({request:e,options:r})}me();const je={device:!0},Me={emulator:!0,device:!0},Ne=new Set([`perf`,`back`,`app-switcher`,`click`,`fill`,`find`,`focus`,`get`,`home`,`gesture`,`keyboard`,`is`,`longpress`,`press`,`screenshot`,`scroll`,`settings`,`swipe`,`type`,`wait`]),Pe=[`audio`,`find`,`get`,`is`,`screenshot`,`wait`],Fe=[`click`,`fill`,`focus`,`hover`,`press`,`scroll`,`type`],Ie=[`viewport`],M=new Set([...Pe,...Fe,...Ie]),N=Le(i(a));function Le(e){let t={};for(let[n,r]of Object.entries(e))t[n]=Ne.has(n)?{...r,harmonyos:Me}:r;return Re(t)}function Re(e){let t={};for(let[n,r]of Object.entries(e))t[n]=M.has(n)?{...r,web:je}:r;for(let t of M)if(!(t in e))throw Error(`Web command "${t}" missing from capability matrix`);return t}function P(e,t){let n=N[e];if(!n)return!0;let r=S(t.platform);if(!r)return!1;let i=n[r.capability.bucket];if(!i)return!1;let a=r.capability.supportsByDefault?.[e];return a&&!a(t)?!1:i[t.kind??`unknown`]===!0}function ze(e,t){return S(t.platform)?.capability.unsupportedHintByDefault?.[e]?.(t)}function Be(){return a.filter(e=>e.catalog.group===`public`&&(`capability`in e&&e.capability!==void 0||e.platformExecution.kind===`device-runtime`)).map(e=>e.name).sort()}function Ve(e){let t=N[e];if(!t)return[];let n=[`apple`,`android`,`harmonyos`,`vega`,`linux`,`web`],r=[];for(let e of n){let n=t[e];n&&Object.values(n).some(e=>e===!0)&&r.push(e)}return r}function He(e,t){if(e.intent===`drag`){Ue(e,t);return}if(t.platform===`web`||t.appleOs===`watchos`)throw I(e,F(e,t));if(Ge(e)){Ke(e,t);return}if(t.appleOs===`visionos`)throw I(e,F(e,t));if(e.intent===`fling`&&`direction`in e&&t.platform===`linux`)throw I(e,`gesture fling is not supported on Linux`)}function Ue(e,t){if(!We(t))throw I(e,F(e,t),`Target-authored drag requires an adapter that preserves source hold, timed movement, and destination hold; it is supported on Android touch devices and iOS/iPadOS.`)}function We(e){return e.platform===`android`?e.target!==`tv`:e.platform===`apple`?e.appleOs===void 0?e.target!==`desktop`&&e.target!==`tv`:e.appleOs===`ios`||e.appleOs===`ipados`:!1}function Ge(e){return e.intent===`pan`?(`pointerCount`in e?e.pointerCount:1)===2:e.intent===`pinch`||e.intent===`rotate`||e.intent===`transform`}function Ke(e,t){if(t.platform===`android`){if(t.target!==`tv`)return;throw I(e,`gesture ${e.intent} is not supported on Android TV`,`Android TV has no touch input — this gesture is supported on Android phones, tablets, and the iOS simulator only.`)}if(t.platform!==`apple`)throw I(e,F(e,t));r(t,e.intent)}function F(e,t){return`gesture ${e.intent} is not supported on ${t.appleOs??t.platform}`}function I(t,n,r){return new e(`UNSUPPORTED_OPERATION`,n,{gesture:t.intent,...r?{hint:r}:{}})}const L=`No active session. Run open first.`;function R(e,t,n,r){return{ok:!1,error:{code:e,message:t,...r?.hint?{hint:r.hint}:{},...r?.retriable===void 0?{}:{retriable:r.retriable},...n?{details:n}:{}}}}function qe(){return R(`SESSION_NOT_FOUND`,L)}function Je(e,t,n){if(P(e,t))return null;let r=n?.hint?ze(e,t):void 0;return{ok:!1,error:{code:`UNSUPPORTED_OPERATION`,message:n?.message??`${e} is not supported on this device`,...r?{hint:r}:{}}}}const Ye=/^[A-Za-z0-9_.:-]{1,64}$/,z=8*1024,B=4*1024;function Xe(t){let n=t[0]?.trim(),r=t[1]?.trim();if(!n)throw new e(`INVALID_ARGS`,`trigger-app-event requires <event> [payloadJson]`);if(!Ye.test(n))throw new e(`INVALID_ARGS`,`Invalid trigger-app-event event name: ${n}`,{hint:`Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash.`});if(t.length>2)throw new e(`INVALID_ARGS`,`trigger-app-event accepts at most two arguments: <event> [payloadJson]`);return{eventName:n,payload:Qe(r,n)}}function Ze(t,n,r){let i=o(t),a=$e(t);if(!a)throw new e(`UNSUPPORTED_OPERATION`,`No app event URL template configured for ${i}.`,{hint:`Set AGENT_DEVICE_${i.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let s=r?JSON.stringify(r):``,c=a.replaceAll(`{event}`,encodeURIComponent(n)).replaceAll(`{payload}`,encodeURIComponent(s)).replaceAll(`{platform}`,encodeURIComponent(i));if(c.length>B)throw new e(`INVALID_ARGS`,`trigger-app-event URL exceeds maximum supported length`,{hint:`Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.`,length:c.length,maxLength:B});return c}function Qe(t,n){if(t)try{let r=JSON.parse(t);if(!r||typeof r!=`object`||Array.isArray(r))throw new e(`INVALID_ARGS`,`trigger-app-event payload for "${n}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,`utf8`)>z)throw new e(`INVALID_ARGS`,`trigger-app-event payload for "${n}" exceeds ${z} bytes`);return r}catch(n){throw n instanceof e?n:new e(`INVALID_ARGS`,`Invalid trigger-app-event payload JSON: ${t}`)}}function $e(e){return((c(e)?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:u(e)?process.env.AGENT_DEVICE_MACOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE)?.trim()||void 0}function et(e){let t=e?e.textEntryReadiness:void 0,n=at(t)?{textEntryReadiness:t}:{},r=tt(e);return r?{...n,...r}:n}function tt(e){if(!nt(e))return null;let t=rt(e.target);return t?{verification:`unconfirmed`,requested:e.requested,before:e.before,after:e.after,target:t}:null}function nt(e){return!!(e&&e.verification===`unconfirmed`&&typeof e.requested==`string`&&V(e.before)&&V(e.after))}function rt(e){if(!H(e)||!it(e))return null;let t=ot(e.rect);return t?{resourceId:e.resourceId,className:e.className,packageName:e.packageName,rect:t}:null}function it(e){return V(e.resourceId)&&V(e.className)&&V(e.packageName)}function at(e){return typeof e==`string`&&ce.includes(e)}function V(e){return e===null||typeof e==`string`}function ot(e){return!H(e)||![e.x,e.y,e.width,e.height].every(e=>typeof e==`number`)?null:e}function H(e){return!!e&&typeof e==`object`}const U=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function st(e,t){return f(e.platform)&&t>1}function ct(e,t,n=2e4){if(e.length===0)return[];let r=t>0?t:e.length,i=[],a=[],o=0;for(let t of e){let e=(t.durationMs??0)+(t.pauseMs??0)+250,s=a.length>0&&o+e>n,c=a.length>=r;(s||c)&&(i.push(a),a=[],o=0),a.push(t),o+=e}return a.length>0&&i.push(a),i}function W(e,t){if(t<=0)return[0,0];let[n,r]=U[e%U.length];return[n*t,r*t]}async function lt(e,t,n){for(let r=0;r<e;r+=1)await n(r),r<e-1&&t>0&&await pe(t)}async function ut(e,t){let{x:n,y:r}=G(t,`longpress requires x y [durationMs]`,{hint:`Direct platform longpress requires coordinates. In an open daemon session, use agent-device longpress @ref|selector [durationMs]; otherwise run snapshot -i, use the target rect center as x y, then retry longpress x y durationMs.`}),i=t[2]?Number(t[2]):void 0;return await e.longPress(n,r,i),{x:n,y:r,durationMs:i,...g(`Long pressed (${n}, ${r})`)}}async function dt(t,n){let{x:r,y:i}=G(n,`hover requires x y`,{hint:`Direct platform hover requires coordinates. In an open daemon session, use agent-device hover @ref|selector; otherwise run snapshot -i, use the target rect center as x y, then retry hover x y.`});if(!t.hover)throw new e(`UNSUPPORTED_OPERATION`,`hover is not supported on this platform`,{hint:`hover raises pointer hover state and is available on web targets only. On touch platforms use longpress for hold gestures.`});return await t.hover(r,i),{x:r,y:i,...g(`Hovered (${r}, ${i})`)}}async function ft(e,t){let{x:n,y:r}=G(t,`focus requires x y`);return await e.focus(n,r),{x:n,y:r,...g(`Focused (${n}, ${r})`)}}async function pt(t,n,r){let i=Lt(n);if(i)throw new e(`INVALID_ARGS`,`type does not accept a target ref like "${i}"`,{hint:`Use fill ${i} "text" to target that field, or press ${i} then type "text" to append.`});let a=n.join(` `);if(!a)throw new e(`INVALID_ARGS`,`type requires text`);let o=h(r?.delayMs??0,`delay-ms`,0,1e4),s=(await t.type(a,o))?.textEntryRoute;return{...s===void 0?{}:{textEntryRoute:s},text:a,delayMs:o,...g(Y(`Typed`,a))}}async function mt(t,n,r){if(r?.directElementSelector)return await ht(t,r.directElementSelector,n,r);let i=Number(n[0]),a=Number(n[1]),o=n.slice(2).join(` `);if(Number.isNaN(i)||Number.isNaN(a)||!o)throw new e(`INVALID_ARGS`,`fill requires x y text`);let s=h(r?.delayMs??0,`delay-ms`,0,1e4),c=await t.fill(i,a,o,s,{allowNonHittableCoordinateFallback:r?.allowNonHittableCoordinateFallback===!0});return{x:i,y:a,text:o,delayMs:s,...c?.maestroNonHittableCoordinateFallbackUsed===!0?{maestroNonHittableCoordinateFallbackUsed:!0}:{},...et(c),...g(Y(`Filled`,o))}}async function ht(t,n,r,i){if(!t.fillElementSelector)throw new e(`UNSUPPORTED_OPERATION`,`direct element selector fill is not supported`);let a=r.join(` `);if(!a)throw new e(`INVALID_ARGS`,`fill requires text`);let o=h(i.delayMs??0,`delay-ms`,0,1e4),s=await t.fillElementSelector(n,a,o);return{selector:n.raw,text:a,delayMs:o,...s??{},...g(Y(`Filled`,a))}}async function gt(e,t,n,r){if(r?.directElementSelector&&c(e))return await _t(t,r.directElementSelector);let{x:i,y:a}=G(n,`press requires x y`);if(u(e)&&r?.surface&&r.surface!==`app`)return await vt(i,a,r);let o=_(r);if(o!==`primary`)return await yt(e,i,a,o,r);let s=St(r);return Ct(s),st(e,s.count)?await Tt(e,i,a,s,r):await Ot(t,i,a,s)}async function _t(t,n){if(!t.tapElementSelector)throw new e(`UNSUPPORTED_OPERATION`,`direct element selector tap is not supported`);let r=await t.tapElementSelector(n),i=r?.maestroNonHittableCoordinateFallbackUsed===!0;return{selector:n.raw,...r??{},...g(i?se:`Tapped ${n.raw}`)}}function G(t,n,r){let i=Number(t[0]),a=Number(t[1]);if(Number.isNaN(i)||Number.isNaN(a))throw new e(`INVALID_ARGS`,n,r);return{x:i,y:a}}async function vt(t,n,r){let i=_(r);if(i!==`primary`)throw new e(`UNSUPPORTED_OPERATION`,`${i} click is not supported on macOS ${r.surface} sessions.`);let{runMacOsPressAction:a}=await import(`./helper.js`).then(e=>e.t);return await a(t,n,{bundleId:r.appBundleId,surface:r.surface}),{x:t,y:n,...g(J({x:t,y:n}))}}async function yt(e,t,n,r,i){if(bt(e,r,i),e.platform===`linux`)return await xt(t,n,r);let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r);return await a(e,{command:`mouseClick`,x:t,y:n,button:r,appBundleId:i?.appBundleId},q(i)),{x:t,y:n,button:r,...g(J({x:t,y:n,button:r}))}}function bt(e,t,n){let r=v({commandLabel:`click`,platform:o(e),button:t,count:n?.count,intervalMs:n?.intervalMs,holdMs:n?.holdMs,jitterPx:n?.jitterPx,doubleTap:n?.doubleTap});if(r)throw r}async function xt(e,t,n){if(n===`secondary`){let{rightClickLinux:n}=await import(`./input-actions3.js`);await n(e,t)}else{let{middleClickLinux:n}=await import(`./input-actions3.js`);await n(e,t)}return{x:e,y:t,button:n,...g(J({x:e,y:t,button:n}))}}function St(e){return{count:K(e?.count,1,`count`,1,200),intervalMs:K(e?.intervalMs,0,`interval-ms`,0,1e4),holdMs:K(e?.holdMs,0,`hold-ms`,0,1e4),jitterPx:K(e?.jitterPx,0,`jitter-px`,0,100),doubleTap:!!e?.doubleTap}}function K(e,t,n,r,i){return h(e===void 0?t:e,n,r,i)}function Ct({doubleTap:t,holdMs:n,jitterPx:r}){if(t&&n>0)throw new e(`INVALID_ARGS`,`double-tap cannot be combined with hold-ms`);if(t&&r>0)throw new e(`INVALID_ARGS`,`double-tap cannot be combined with jitter-px`)}async function wt(e,t,n){let{runAppleRunnerCommand:r}=await import(`./runner-client.js`).then(e=>e.r),{MAX_RUNNER_SEQUENCE_STEPS:i,buildRunnerSequenceCommand:a,parseRunnerSequenceResult:o}=await import(`./runner-sequence.js`).then(e=>e.r),s=ct(t,i),c,l,u=0,d=[],f=0;for(let t of s){let i=await r(e,a(t,n?.appBundleId),q(n));c??=i,l=i;let s;try{s=o(i)}catch(e){throw Dt(e,f)}u+=s.completedSteps,d.push(...s.results),f+=t.length}return{...c??{},completedSteps:u,sequenceResults:d,...l?.gestureEndUptimeMs===void 0?{}:{gestureEndUptimeMs:l.gestureEndUptimeMs}}}async function Tt(e,t,n,r,i){let a=await wt(e,Et(e,t,n,r),i);return{x:t,y:n,count:r.count,intervalMs:r.intervalMs,holdMs:r.holdMs,jitterPx:r.jitterPx,doubleTap:r.doubleTap,timingMode:`runner-sequence`,...a,...g(J({x:t,y:n}))}}function Et(e,t,n,r){let i=r.doubleTap?`doubleTap`:r.holdMs>0?`longPress`:`tap`,a=i===`tap`&&c(e)&&!d(e);return Array.from({length:r.count},(e,o)=>{let[s,c]=W(o,r.jitterPx),l=o===r.count-1;return{kind:i,x:t+s,y:n+c,...a?{synthesized:!0}:{},...r.holdMs>0?{durationMs:r.holdMs}:{},...!l&&r.intervalMs>0?{pauseMs:r.intervalMs}:{}}})}function Dt(t,n){if(n===0||!(t instanceof e)||!t.details)return t;let r=t.details.failedStepIndex;if(typeof r!=`number`)return t;let i=t.details.completedSteps;return new e(t.code,t.message,{...t.details,failedStepIndex:r+n,chunkStepIndex:r,...typeof i==`number`?{completedSteps:n+i}:{}},t.cause)}async function Ot(e,t,n,r){let i;return await lt(r.count,r.intervalMs,async a=>{let[o,s]=W(a,r.jitterPx),c=t+o,l=n+s;if(r.doubleTap){let t=await e.doubleTap(c,l);i??=t??void 0;return}if(r.holdMs>0){let t=await e.longPress(c,l,r.holdMs);i??=t??void 0}else{let t=await e.tap(c,l);i??=t??void 0}}),p({x:t,y:n,count:r.count,intervalMs:r.intervalMs,holdMs:r.holdMs,jitterPx:r.jitterPx,doubleTap:r.doubleTap,...i},J({x:t,y:n}))}function q(e){return{verbose:e?.verbose,logPath:e?.logPath,traceLogPath:e?.traceLogPath,requestId:e?.requestId,iosXctestrunFile:e?.iosXctestrunFile,iosXctestDerivedDataPath:e?.iosXctestDerivedDataPath,iosXctestEnvDir:e?.iosXctestEnvDir}}async function kt(t,n,r){let i=n[0],a=n[1]?Number(n[1]):void 0,o=r?.pixels,s=r?.durationMs;if(!i)throw new e(`INVALID_ARGS`,`scroll requires direction`);At(a,o,s);let c=Ft(i),l={amount:a,pixels:o,durationMs:s},{interactionResult:u,completedPasses:d}=await Mt(t,r,c,l);return p(Nt(c,l,d,u),ne(c.direction,c.edge,d,a,o))}function At(e,t,n){jt(e),ae(n),le({amount:e,pixels:t})}function jt(t){if(t!==void 0&&!Number.isFinite(t))throw new e(`INVALID_ARGS`,`scroll amount must be a number`)}async function Mt(e,t,n,r){if(n.edge){let i=n.edge,a=await te({edge:i,captureState:async n=>await Pt(e,t,i,n),scroll:async()=>await e.scroll(n.direction,r)});return{interactionResult:a.result??{},completedPasses:a.passes}}return{interactionResult:await e.scroll(n.direction,r)??{},completedPasses:1}}function Nt(e,t,n,r){let i=y(r);return{direction:e.direction,...e.edge?{edge:e.edge,passes:n}:{},...t.amount===void 0?{}:{amount:t.amount},...t.pixels===void 0?{}:{pixels:t.pixels},...i===void 0?{}:{durationMs:i},...r}}async function Pt(t,n,r,i){if(typeof t.snapshot!=`function`)throw new e(`UNSUPPORTED_OPERATION`,`scroll ${r} requires snapshot support to verify hidden content before scrolling`);let a=t.snapshot;return await re({edge:r,scope:i,captureNodes:async e=>(await a({appBundleId:n?.appBundleId,scope:e})).nodes??[]})}function Ft(e){return e===`bottom`?{direction:`down`,edge:`bottom`}:e===`top`?{direction:`up`,edge:`top`}:{direction:ie(e)}}async function It(e,t,n){let{x:r,y:i}=G(t,`read requires x y`);if(e.platform===`android`){let{readAndroidTextAtPoint:t}=await import(`./input-actions.js`).then(e=>e.s);return{action:`read`,text:await t(e,r,i)??``}}if(e.platform===`linux`){let{readLinuxTextAtPoint:e}=await import(`./snapshot3.js`);return{action:`read`,text:await e(r,i,n?.surface)}}if(u(e)&&n?.surface&&n.surface!==`app`){let{runMacOsReadTextAction:e}=await import(`./helper.js`).then(e=>e.t);return{action:`read`,text:(await e(r,i,{bundleId:n.appBundleId,surface:n.surface})).text}}let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r),o=await a(e,{command:`readText`,x:r,y:i,appBundleId:n?.appBundleId},{verbose:n?.verbose,logPath:n?.logPath,traceLogPath:n?.traceLogPath,requestId:n?.requestId,iosXctestrunFile:n?.iosXctestrunFile,iosXctestDerivedDataPath:n?.iosXctestDerivedDataPath,iosXctestEnvDir:n?.iosXctestEnvDir});return{action:`read`,text:typeof o.text==`string`?o.text:typeof o.message==`string`?o.message:``}}function Lt(e){return fe(e[0])}function J(e){return e.button&&e.button!==`primary`?`Clicked ${e.button} (${e.x}, ${e.y})`:`Tapped (${e.x}, ${e.y})`}function Y(e,t){return`${e} ${Array.from(t).length} chars`}async function Rt(e,t,n,r,i){let a=X(i);return await zt(e,await C(e,a),t,n,r,i,a)}async function zt(e,t,n,r,i,a,o){return b({level:`debug`,phase:`platform_command_prepare`,data:{command:n,platform:e.platform,kind:e.kind}}),await x(`platform_command`,async()=>await Ht(e,t,n,r,i,a,o),{command:n,platform:e.platform})}async function Bt(t,n,r){let i=await C(t,X(r));if(!i.performGesture)throw new e(`UNSUPPORTED_OPERATION`,`Gesture execution is unavailable`);return await i.performGesture(n)}async function Vt(e,t){return await(await C(e,X(t))).gestureViewport?.()}function X(e){return{requestId:e?.requestId,signal:e?.signal,appBundleId:e?.appBundleId,verbose:e?.verbose,logPath:e?.logPath,traceLogPath:e?.traceLogPath,iosXctestrunFile:e?.iosXctestrunFile,iosXctestDerivedDataPath:e?.iosXctestDerivedDataPath,iosXctestEnvDir:e?.iosXctestEnvDir,runnerLeaseContext:e?.runnerLeaseContext}}const Z={press:({device:e,interactor:t,positionals:n,context:r})=>gt(e,t,n,r),longpress:({interactor:e,positionals:t})=>ut(e,t),hover:({interactor:e,positionals:t})=>dt(e,t),focus:({interactor:e,positionals:t})=>ft(e,t),type:({interactor:e,positionals:t,context:n})=>pt(e,t,n),fill:({interactor:e,positionals:t,context:n})=>mt(e,t,n),scroll:({interactor:e,positionals:t,context:n})=>kt(e,t,n),"trigger-app-event":({device:e,interactor:t,positionals:n,context:r})=>Ut(e,t,n,r),screenshot:({interactor:e,positionals:t,outPath:n,context:r})=>Wt(e,t,n,r),viewport:({interactor:e,positionals:t})=>Gt(e,t),back:async({interactor:e,context:t})=>(await e.back(t?.backMode),{action:`back`,mode:t?.backMode??`in-app`,...g(`Back`)}),home:async({interactor:e})=>(await e.home(),{action:`home`,...g(`Home`)}),orientation:async({interactor:e,positionals:t})=>{let n=de(t[0]),r=(await e.setOrientation(n))?.orientation??n;return{action:`orientation`,orientation:r,...g(`Rotated to ${r}`)}},"app-switcher":async({interactor:e})=>(await e.appSwitcher(),{action:`app-switcher`,...g(`Opened app switcher`)}),clipboard:({interactor:e,positionals:t})=>Kt(e,t),keyboard:({device:e,positionals:t,context:n,runnerCtx:r})=>Q(e,t,n,r),"tv-remote":({device:e,interactor:t,positionals:n,context:r})=>qt(e,t,n,r),settings:({device:e,interactor:t,positionals:n,context:r})=>Qt(e,t,n,r),read:({device:e,positionals:t,context:n})=>It(e,t,n)};async function Ht(t,n,r,i,a,o,s){let c=Object.hasOwn(Z,r)?Z[r]:void 0;if(!c)throw new e(`INVALID_ARGS`,`Unknown command: ${r}`);return await c({device:t,interactor:n,positionals:i,outPath:a,context:o,runnerCtx:s})}async function Ut(e,t,n,r){let{eventName:i,payload:a}=Xe(n),o=Ze(e,i,a);return await t.open(o,{appBundleId:r?.appBundleId}),{event:i,eventUrl:o,transport:`deep-link`,...g(`Triggered app event: ${i}`)}}async function Wt(e,n,r,i){let a=n[0]??r??`./screenshot-${Date.now()}.png`;await xe.mkdir(be.dirname(a),{recursive:!0});let o=t(i);return await e.screenshot(a,{appBundleId:i?.appBundleId,pixelDensity:o.pixelDensity,fullscreen:o.fullscreen,normalizeStatusBar:o.normalizeStatusBar,stabilize:o.stabilize,surface:i?.surface,skipIosSimulatorBootCheck:i?.skipIosSimulatorBootCheck,captureBackend:i?.screenshotCaptureBackend}),{path:a,...g(`Saved screenshot: ${a}`)}}async function Gt(t,n){if(n.length!==2)throw new e(`INVALID_ARGS`,`viewport requires exactly two arguments: <width> <height>`);let r=m(n[0],`width`),i=m(n[1],`height`);if(!t.setViewport)throw new e(`UNSUPPORTED_OPERATION`,`viewport is not supported by this backend`);return await t.setViewport(r,i),{width:r,height:i,...g(`Viewport set: ${r}x${i}`)}}async function Kt(t,n){let r=(n[0]??``).toLowerCase();if(r!==`read`&&r!==`write`)throw new e(`INVALID_ARGS`,`clipboard requires a subcommand: read or write`);if(r===`read`){if(n.length!==1)throw new e(`INVALID_ARGS`,`clipboard read does not accept additional arguments`);return{action:r,text:await t.readClipboard()}}if(n.length<2)throw new e(`INVALID_ARGS`,`clipboard write requires text (use "" to clear clipboard)`);let i=n.slice(1).join(` `);return await t.writeClipboard(i),{action:r,textLength:Array.from(i).length,...g(`Clipboard updated`)}}async function qt(t,n,r,i){if(t.target!==`tv`)throw new e(`UNSUPPORTED_OPERATION`,`tv-remote is supported only on TV targets`,{hint:`Select an Android TV, tvOS, or Vega OS target with --target tv.`});if(r.length!==1)throw new e(`INVALID_ARGS`,`tv-remote requires exactly one button`);let a=oe(r[0]),o=i?.durationMs===void 0?void 0:h(i.durationMs,`durationMs`,0,1e4);return await n.tvRemote(a,o),{action:`tv-remote`,button:a,...o===void 0?{}:{durationMs:o},...g(`Pressed TV remote ${a}`)}}async function Q(t,n,r,i){let a=(n[0]??`status`).toLowerCase();if(!ue(a))throw new e(`INVALID_ARGS`,`keyboard requires a subcommand: status, get, dismiss, enter, or return`);if(n.length>1)throw new e(`INVALID_ARGS`,`keyboard accepts at most one subcommand argument`);if(t.platform===`android`)return await Yt(t,a);if(t.platform===`harmonyos`)return await Jt(t,a);if(c(t))return await Xt(t,a,r,i);throw new e(`UNSUPPORTED_OPERATION`,`keyboard is supported only on Android, HarmonyOS, and iOS`)}async function Jt(t,n){if(n!==`dismiss`&&n!==`enter`&&n!==`return`)throw new e(`UNSUPPORTED_OPERATION`,`keyboard status/get is not available through the public HarmonyOS HDC API; use keyboard dismiss or enter`);let{pressHarmonyKeyboardKey:r}=await import(`./input-actions2.js`);return await r(t,n===`dismiss`?`Back`:`Enter`),{platform:`harmonyos`,action:n===`dismiss`?`dismiss`:`enter`,...g(n===`dismiss`?`Keyboard dismissed`:`Keyboard enter pressed`)}}async function Yt(e,t){if(t===`enter`||t===`return`){let{pressAndroidEnter:t}=await import(`./input-actions.js`).then(e=>e.s);return await t(e),{platform:`android`,action:`enter`,...g(`Keyboard enter pressed`)}}if(t===`dismiss`){let{dismissAndroidKeyboard:t}=await import(`./device-input-state.js`).then(e=>e.t),n=await t(e);return{platform:`android`,action:`dismiss`,attempts:n.attempts,wasVisible:n.wasVisible,dismissed:n.dismissed,visible:n.visible,inputType:n.inputType,type:n.type,inputMethodPackage:n.inputMethodPackage,focusedPackage:n.focusedPackage,focusedResourceId:n.focusedResourceId,inputOwner:n.inputOwner}}let{getAndroidKeyboardState:n}=await import(`./device-input-state.js`).then(e=>e.t),r=await n(e);return{platform:`android`,action:`status`,visible:r.visible,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,inputOwner:r.inputOwner}}async function Xt(t,n,r,i){if(n!==`dismiss`&&n!==`enter`&&n!==`return`)throw new e(`UNSUPPORTED_OPERATION`,`keyboard status/get is currently supported only on Android; use keyboard dismiss or enter on iOS`);if(n===`enter`||n===`return`){let{runAppleRunnerCommand:e}=await import(`./runner-client.js`).then(e=>e.r),n=await e(t,{command:`keyboardReturn`,appBundleId:r?.appBundleId},i);return{platform:`ios`,action:`enter`,visible:n.visible,wasVisible:n.wasVisible,...g(`Keyboard enter pressed`)}}let{runAppleRunnerCommand:a}=await import(`./runner-client.js`).then(e=>e.r),o=await a(t,{command:`keyboardDismiss`,appBundleId:r?.appBundleId},i),s=typeof o.keyboardDismissMechanism==`string`?o.keyboardDismissMechanism:void 0;return{platform:`ios`,action:`dismiss`,wasVisible:o.wasVisible,dismissed:o.dismissed,visible:o.visible,mechanism:s,...g(Zt(o.dismissed===!0,s))}}function Zt(e,t){return e?t===`dismissKey`?`Keyboard dismissed via its dismiss key`:`Keyboard dismissed`:`Keyboard already hidden`}async function Qt(t,n,r,i){let[a,o,s,c]=r;if(!a||!o&&a!==`clear-app-state`)throw new e(`INVALID_ARGS`,`settings requires setting state`);if(a===`clear-app-state`)return await $t(t,n,o,s,i);if(!o)throw new e(`INVALID_ARGS`,`settings requires setting state`);return await en(t,n,a,o,s,c,r,i)}async function $t(t,n,r,i,a){let o=(r===`clear`?i:r)??a?.appBundleId;if(!o)throw new e(`INVALID_ARGS`,`settings clear-app-state requires an app id or an active app session.`);b({level:`debug`,phase:`settings_apply`,data:{setting:`clear-app-state`,state:`clear`,appBundleId:o,platform:t.platform}});let s=await n.setSetting(`clear-app-state`,`clear`,o);return s&&typeof s==`object`?p({setting:`clear-app-state`,state:`clear`,...s},$(s)??`Cleared user data for ${o}`):{setting:`clear-app-state`,state:`clear`,...g(`Cleared user data for ${o}`)}}async function en(e,t,n,r,i,a,o,s){let c=n===`location`&&r===`set`,l=(n===`permission`||c?o[4]:o[2])??s?.appBundleId;b({level:`debug`,phase:`settings_apply`,data:nn(e,n,r,i,a,l,c)});let u=await t.setSetting(n,r,l,tn(n,i,a,c));return u&&typeof u==`object`?p({setting:n,state:r,...u},$(u)??`Updated setting: ${n}`):{setting:n,state:r,...g(`Updated setting: ${n}`)}}function tn(e,t,r,i){if(e===`permission`)return{permissionTarget:t,permissionMode:r};if(i)return{latitude:n(t,`latitude`),longitude:n(r,`longitude`)}}function nn(e,t,n,r,i,a,o){return o?{setting:t,state:n,latitude:r,longitude:i,platform:e.platform}:t===`permission`?{setting:t,state:n,permissionTarget:r,permissionMode:i,platform:e.platform}:{setting:t,state:n,appBundleId:a,platform:e.platform}}function $(e){return typeof e.message==`string`&&e.message.length>0?e.message:void 0}export{R as a,P as c,Ve as d,A as f,L as i,Be as l,Ee as m,Bt as n,qe as o,Te as p,Vt as r,Je as s,Rt as t,He as u};
|
package/dist/src/find.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{u as e}from"./sdk-contracts.js";import{Sn as t,Tn as n,bn as r,xn as i}from"./sdk-batch-runner.js";import{$ as a,Et as o,Y as s,Z as c,et as l,gt as u,vn as d,yn as f}from"./script-source-bundle.js";import"./screenshot-result.js";import{t as p}from"./verdict.js";import{a as m,o as h,t as g}from"./dispatch.js";import{At as _,bt as v,jt as y}from"./internal/daemon.js";import{o as b,s as x,t as S}from"./selector-runtime.js";import{t as C}from"./handler-utils.js";function w(e){if(e.ambiguity!==`reject-candidates`)throw Error(`find's resolution policy must reject candidates, got "${e.ambiguity}"`)}async function T(e){let{req:i,sessionName:a,logPath:o,sessionStore:s,invoke:l}=e,d=i.command;if(d!==`find`)return null;let f=r(i.positionals??[],i.flags);if(!f.ok)return m(f.code,f.message);let{locator:g,query:_,action:v,value:y}=f.parsed;if(i.flags?.record&&!t(v))return m(`INVALID_ARGS`,`find ${v} is a mutating action and is always recorded; --record only applies to a read-only find (exists, wait, list, get text, get attrs).`);let b=await S({req:i,sessionName:a,logPath:o,sessionStore:s});if(b)return b;let C=s.get(a);if(!C)return h();let w=C.device,T=n(g,_),A=D({device:w,session:C,req:i,logPath:o,locator:g,query:_,sessionStore:s,sessionName:a}),j={req:i,sessionName:a,logPath:o,sessionStore:s,invoke:l,session:C,device:w,command:d,locator:g,query:_,publicFlags:W(i.flags)},M=await A();if(p(M.snapshotQuality))return O(M.snapshotQuality);let{nodes:N}=M,P=k({nodes:N,locator:g,query:_,selectorExpression:T,flags:i.flags,platform:w.platform});if(!P.ok)return x(P.response,M);let F=P.node,I=await c(u.findAct,N,F),L=I.node,R=await E(j,{node:F,resolvedNode:L,ref:`@${L.ref}`,nodes:N,actionFlags:{...i.flags??{},noRecord:!0},...I.kind===`occluded`?{occludedNode:I.node}:{}},v,y);return R&&x(R,M)}async function E(e,t,n,r){let i={click:()=>L(e,t),fill:()=>R(e,t,r),focus:()=>z(e,t),type:()=>B(e,t,r)}[n];return i?await i():null}function D(e){let{device:t,session:n,req:r,logPath:i,locator:a,query:o}=e,{sessionStore:s,sessionName:c}=e,l=b({device:t,session:n,sessionStore:s,sessionName:c,req:r,logPath:i});return async()=>{let{snapshot:e}=await l.capture({flags:{...r.flags,snapshotInteractiveOnly:!0},recovery:{legacyIosSparse:{query:o,shouldScope:K(a)},sparseVerdictQueryScope:{query:o,shouldScope:K(a)}}});return{nodes:e.nodes,snapshotQuality:e.snapshotQuality,systemSurfaceOnly:e.systemSurfaceOnly}}}function O(e){return m(`COMMAND_FAILED`,`find could not read the current accessibility tree`,{reason:e.reason,hint:`The snapshot quality verdict is sparse. Use screenshot as visual truth, navigate with coordinates if needed, then retry find after reaching a readable screen.`})}function k(e){let{nodes:t,locator:n,query:r,selectorExpression:o,flags:c,platform:l}=e,d=u.findAct,f=t.filter(e=>!a(e,t[0])),p=d.resolution,h;if(h=o?s(d,f,o,{platform:l}).list?.matchedNodes??[]:i(f,n,r,{requireRect:p.requireRect}).matches,h=j(h,t),h.length>1){w(p);let e=A(h,c);if(!e)return{ok:!1,response:G(h,n,r)};h=e}let g=h[0]??null;return g?{ok:!0,node:g}:{ok:!1,response:m(`COMMAND_FAILED`,`find did not match any element`)}}function A(e,t){return t?.findFirst?[e[0]]:t?.findLast?[e[e.length-1]]:null}function j(t,n){let r=n[0]?.rect;if(!r)return t;let i=t.filter(t=>{if(!t.rect)return!1;let n=e(t.rect);return n.x>=r.x&&n.x<=r.x+r.width&&n.y>=r.y&&n.y<=r.y+r.height});return M(i.length>0?i:t,n)}function M(e,t){return e.length<2?e:e.map((e,n)=>({node:e,index:n,score:N(e,t)})).sort((e,t)=>t.score===e.score?F(e.node)-F(t.node)||e.index-t.index:t.score-e.score).map(e=>e.node)}function N(e,t){let n=l(t,e);if(n.reason===`covered`)return 0;let r=P(n,t[0]);return r>0?r:e.hittable&&e.rect&&!a(e,t[0])?3:+!!e.rect}function P(e,t){return e.node.rect?e.reason===`semantic-target`||e.reason===`same-rect-descendant`?4:e.reason===`hittable-ancestor`&&!a(e.node,t)?2:0:0}function F(e){return e.rect?e.rect.width*e.rect.height:1/0}function I(e){return{ref:e.ref,node:e.resolvedNode,nodes:e.nodes}}async function L(t,n){let{req:r,sessionName:i,sessionStore:a,session:o,invoke:s,command:c,locator:l,query:u,publicFlags:p}=t,m=await s({token:r.token,session:i,command:`click`,positionals:[n.ref],flags:n.actionFlags,internal:{findResolvedTarget:I(n)}});if(!m.ok)return m;let h=n.resolvedNode.rect?e(n.resolvedNode.rect):n.node.rect?e(n.node.rect):null,g={ref:n.ref,locator:l,query:u};h&&(g.x=h.x,g.y=h.y);let _=d(m.data)??`Tapped ${n.ref}${h?` (${h.x}, ${h.y})`:``}`;return Object.assign(g,f(_)),C(a,o,r,c,{ref:n.ref,action:`click`,locator:l,query:u},{flags:p}),{ok:!0,data:g}}async function R(e,t,n){let{req:r,sessionName:i,sessionStore:a,session:o,invoke:s,command:c,publicFlags:l}=e;if(!n)return m(`INVALID_ARGS`,`find fill requires text`);let u=await s({token:r.token,session:i,command:`fill`,positionals:[t.ref,n],flags:t.actionFlags,internal:{findResolvedTarget:I(t)}});return u.ok&&C(a,o,r,c,{ref:t.ref,action:`fill`},{flags:l}),u}async function z(e,t){let n=await V(e,t);return n.ok&&U(e,t,`focus`),n}async function B(e,t,n){let{req:r,device:i,logPath:a,session:o}=e;if(!n)return m(`INVALID_ARGS`,`find type requires text`);let s=await V(e,t);if(!s.ok)return s;v(o);let c=await g(i,`type`,[n],r.flags?.out,{...y(a,r.flags,o.appBundleId,o.trace?.outPath)});return U(e,t,`type`),{ok:!0,data:c??{ref:t.ref}}}async function V(t,n){let{req:r,device:i,logPath:a,session:o}=t,s=H(n,`be focused`);if(s)return s;let c=n.resolvedNode.rect?e(n.resolvedNode.rect):null;return c?(v(o),{ok:!0,data:await g(i,`focus`,[String(c.x),String(c.y)],r.flags?.out,{...y(a,r.flags,o.appBundleId,o.trace?.outPath)})??{ref:n.ref}}):m(`COMMAND_FAILED`,`matched element has no bounds`)}function H(e,t){let n=e.occludedNode;return n?m(`COMMAND_FAILED`,`Matched element ${e.ref} is covered by another visible element and cannot ${t} safely`,{ref:`@${n.ref}`,interactionBlocked:n.interactionBlocked,hint:`Use a different visible target, scroll it clear of the overlay, or inspect with snapshot/screenshot before retrying.`}):null}function U(e,t,n){let{req:r,sessionStore:i,session:a,command:o,publicFlags:s}=e;C(i,a,r,o,{ref:t.ref,action:n},{flags:s})}function W(e){return{..._(e)??{}}}function G(e,t,n){let r={matches:e.length,candidates:e.slice(0,5).map(e=>o(e,0,!1))};return m(`AMBIGUOUS_MATCH`,`find matched ${e.length} elements for ${t} "${n}". Use a more specific locator or selector.`,{locator:t,query:n,...r})}function K(e){return e!==`role`}export{G as buildAmbiguousMatchError,T as handleFindCommands};
|
package/dist/src/finders.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{wn as e}from"./sdk-batch-runner.js";import{t}from"./sdk-finders.js";export{t as findBestMatchesByLocator,e as parseFindArgs};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{p as e}from"./sdk-batch-runner.js";import{
|
|
1
|
+
import{p as e}from"./sdk-batch-runner.js";import{pt as t}from"./internal/daemon.js";import{C as n,x as r}from"./selector-runtime.js";import{t as i}from"./interaction-runtime.js";import{t as a}from"./interaction-snapshot.js";function o(t){if(!e(t.command))return{};let i=n(t.command,t.flags);if(i)return{response:i};let a=r(t.flags);if(!a)return{};let o=t.session.snapshot?.nodes??[];return{observe:async()=>await s(t,a,o)}}async function s(e,n,r){let i=c(e);if(!i)return;let a=await i.interactions.settleObservation({...n,baselineNodes:r,session:e.sessionName,requestId:e.req.meta?.requestId}),o=t(e.session,a);return o===void 0?a:{...a,refsGeneration:o}}function c(e){try{return i({req:e.req,sessionName:e.sessionName,logPath:e.logPath,sessionStore:e.sessionStore,contextFromFlags:e.contextFromFlags,captureSnapshotForSession:a})}catch{return}}export{o as planGenericSettleObservation};
|
package/dist/src/generic.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{a as e}from"./sdk-contracts.js";import{vn as t}from"./script-source-bundle.js";import{t as n}from"./shared.js";import{n as r}from"./cli-runner.js";async function i({command:t,positionals:i,flags:s,client:c,debug:l,replayTestReporterRuntime:u}){let{result:d,cliOutput:f}=await r({client:c,command:t,positionals:i,flags:s});if(e(s.responseLevel))return n(s,d,()=>JSON.stringify(d,null,2)),!0;if(f)o(s,f);else{let e=await a(t,s,d,{debug:l,replayTestReporterRuntime:u});e!==0&&process.exit(e)}return!0}function a(e,r,i,a={}){return e===`test`?import(`./reporting.js`).then(({renderReplayTestResponse:e})=>e({suite:i,debug:a.debug,verbose:r.verbose,json:r.json,reporter:r.reporter,reportJunit:r.reportJunit,reporterRuntime:a.replayTestReporterRuntime})):(n(r,i,()=>t(i)),0)}function o(e,t){!e.json&&t.stderr&&process.stderr.write(t.stderr),n(e,e.json?t.jsonData??t.data:t.data,()=>t.text)}export{i as runGenericClientBackedCommand};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E as e,_ as t}from"./sdk-contracts.js";import{a as n,i as r,n as i}from"./sdk-android-adb.js";import{n as a,t as o}from"./version.js";import s from"node:path";import c from"node:crypto";import l from"node:os";import u from"node:fs/promises";function d(e){let t={status:[],results:[],currentStatus:null,currentResult:null};for(let n of e.split(/\r?\n/))f(n,t);return p(t),{status:t.status,results:t.results}}function f(e,t){if(e.startsWith(`INSTRUMENTATION_STATUS: `)){t.currentStatus??={},g(e.slice(24),t.currentStatus);return}if(e.startsWith(`INSTRUMENTATION_STATUS_CODE: `)){m(t);return}if(e.startsWith(`INSTRUMENTATION_RESULT: `)){t.currentResult??={},g(e.slice(24),t.currentResult);return}e.startsWith(`INSTRUMENTATION_CODE: `)&&h(t)}function p(e){m(e),h(e)}function m(e){e.currentStatus&&=(e.status.push(e.currentStatus),null)}function h(e){e.currentResult&&=(e.results.push(e.currentResult),null)}function g(e,t){let n=e.indexOf(`=`);n<0||(t[e.slice(0,n)]=e.slice(n+1))}function _(e){if(e===void 0)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function v(e){if(e===`true`)return!0;if(e===`false`)return!1}function y(e,n,r){if(typeof e!=`number`||!Number.isInteger(e))throw new t(`INVALID_ARGS`,`Android ${r} manifest ${n} must be an integer.`);return e}function b(e,n,r,i){if(e!==r)throw new t(`INVALID_ARGS`,`Android ${i} manifest ${n} must be "${r}".`);return r}function x(e,n,r){if(typeof e!=`string`||e.length===0)throw new t(`INVALID_ARGS`,`Android ${r} manifest ${n} is required.`);return e}function S(e,n){let r=x(e,`sha256`,n).trim().toLowerCase();if(r.length!==64||!/^[0-9a-f]+$/.test(r))throw new t(`INVALID_ARGS`,`Android ${n} manifest sha256 must be a 64-character hex string.`);return r}const C=1e4;async function w(e){let{adb:t,adbProvider:n,packageName:a,versionCode:o,apkPath:s,sha256:c,cache:l,deviceKey:u,installTimeoutMs:d,helperLabel:f}=e,p=`${u}\0${a}\0${o}\0${c}`;if(l.has(p))return{packageName:a,versionCode:o,installedSha256:c,installed:!1,reason:`current`};await j(s,c,f);let m=await T({adb:t,adbProvider:n,packageName:a,versionCode:o,sha256:c});if(m.reason===`current`)return l.add(p),{packageName:a,versionCode:o,...m,installed:!1};let h=await r(s,{provider:n,replace:!0,allowTestPackages:!0,allowFailure:!0,timeoutMs:d});if(h.exitCode!==0)throw i(`Failed to install ${f}`,h,{packageName:a,versionCode:o,reason:m.reason});return l.add(p),{packageName:a,versionCode:o,...m,installed:!0}}async function T(e){let{adb:t,adbProvider:n,packageName:r,versionCode:i,sha256:a,signal:o}=e,s=await O(t,r,o);if(s===void 0)return{reason:`missing`};if(s<i)return{installedVersionCode:s,reason:`outdated`};if(s>i)return{installedVersionCode:s,reason:`current`};try{let e=await k(t,n,r,o);return{installedVersionCode:s,installedSha256:e,reason:e===a?`current`:`mismatched`}}catch{return o?.throwIfAborted(),{installedVersionCode:s,reason:`unverifiable`}}}async function E(n){let r=a(),i=s.join(o(),`android`,n.helperDirName,`dist`),c=s.join(i,n.manifestFileName(r));try{let e=n.parseManifest(JSON.parse(await u.readFile(c,`utf8`))),t=s.join(i,e.assetName);return await u.access(t),{apkPath:t,manifest:e}}catch(r){throw new t(`UNSUPPORTED_OPERATION`,n.unavailableMessage,{manifestPath:c,error:e(r).message},r)}}function D(e){return async t=>await w({adb:t.adb,adbProvider:t.adbProvider,packageName:t.artifact.manifest.packageName,versionCode:t.artifact.manifest.versionCode,apkPath:t.artifact.apkPath,sha256:t.artifact.manifest.sha256,cache:e.cache,deviceKey:t.deviceKey,installTimeoutMs:e.installTimeoutMs,helperLabel:e.helperLabel})}async function O(e,t,n){let r=await e([`shell`,`cmd`,`package`,`list`,`packages`,`--show-versioncode`,t],{allowFailure:!0,timeoutMs:5e3,signal:n});if(r.exitCode!==0)return;let i=RegExp(`package:${N(t)}(?:\\s|$).*versionCode:(\\d+)`).exec(`${r.stdout}\n${r.stderr}`);return i?Number(i[1]):void 0}async function k(e,r,a,o){let c=await e([`shell`,`pm`,`path`,a],{allowFailure:!0,timeoutMs:C,signal:o}),d=A(`${c.stdout}\n${c.stderr}`);if(c.exitCode!==0||!d)throw new t(`COMMAND_FAILED`,`Could not resolve installed Android helper APK`);let f=await u.mkdtemp(s.join(l.tmpdir(),`agent-device-helper-`)),p=s.join(f,`base.apk`);try{let e=await n(d,p,{provider:r,allowFailure:!0,timeoutMs:C,signal:o});if(e.exitCode!==0)throw i(`Could not read installed Android helper APK`,e,{packageName:a,remotePath:d});return await M(p)}finally{await u.rm(f,{recursive:!0,force:!0})}}function A(e){return e.split(/\r?\n/).map(e=>e.startsWith(`package:`)?e.slice(8).trim():``).find(e=>e.endsWith(`/base.apk`))}async function j(e,n,r){let i=await M(e);if(i!==n)throw new t(`COMMAND_FAILED`,`${r} APK checksum mismatch`,{apkPath:e,expectedSha256:n,actualSha256:i})}async function M(e){let t=c.createHash(`sha256`);return t.update(await u.readFile(e)),t.digest(`hex`)}function N(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}export{d as a,S as c,_ as d,j as i,x as l,D as n,y as o,E as r,b as s,T as t,v as u};
|
package/dist/src/helper.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{g as n,v as r}from"./sdk-android-adb.js";import{i,r as a,t as o}from"./tool-provider.js";import s from"node:path";import{createHash as c}from"node:crypto";import{existsSync as l,promises as u}from"node:fs";import d from"node:os";import{fileURLToPath as f}from"node:url";var p=e({quitMacOsApp:()=>N,resolveFrontmostMacOsApp:()=>M,resolveMacOsHelperPackageRootFrom:()=>x,runMacOsAlertAction:()=>F,runMacOsPermissionAction:()=>P,runMacOsPressAction:()=>R,runMacOsReadTextAction:()=>L,runMacOsScreenshotAction:()=>z,runMacOsSnapshotAction:()=>I,startMacOsAudioProbeProcess:()=>A});const m=`agent-device-macos-helper`,h=`AGENT_DEVICE_MACOS_HELPER_BIN`,g=s.join(d.homedir(),`.agent-device`,`macos-helper`,`current`),_=s.join(g,`manifest.json`),v=/^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+$/;function y(e){let n=e.trim();if(!v.test(n))throw new t(`INVALID_ARGS`,`macOS bundle id must use reverse-DNS form like com.example.App`,{bundleId:e});return n}function b(e,t){t.bundleId&&e.push(`--bundle-id`,y(t.bundleId)),t.surface&&e.push(`--surface`,t.surface)}function x(e){let n=s.dirname(e);for(;;){let e=s.join(n,`apple`,`macos-helper`);if(l(s.join(e,`Package.swift`)))return e;let t=s.dirname(n);if(t===n)break;n=t}throw new t(`COMMAND_FAILED`,`Unable to locate macOS helper package root`,{modulePath:e})}function S(){return x(f(import.meta.url))}function C(){return s.join(S(),`.build`,`release`,m)}function w(){return s.join(g,m)}async function T(e){let t=await u.readdir(e,{withFileTypes:!0});return(await Promise.all(t.map(async t=>{let n=s.join(e,t.name);return t.isDirectory()?t.name===`.build`?[]:await T(n):!t.isFile()||!t.name.endsWith(`.swift`)&&t.name!==`Package.swift`?[]:[n]}))).flat().sort()}async function E(e){let t=await T(e),n=c(`sha256`);for(let r of t)n.update(s.relative(e,r)),n.update(`\0`),n.update(await u.readFile(r)),n.update(`\0`);let r=await i(`swift`,[`--version`],{allowFailure:!0,cwd:e,timeoutMs:1e4});return n.update(`swift-version`),n.update(`\0`),n.update(r.stdout||r.stderr||`exit:${r.exitCode}`),n.update(`\0`),n.digest(`hex`)}async function D(){try{let e=JSON.parse(await u.readFile(_,`utf8`));return typeof e.fingerprint==`string`?e.fingerprint:null}catch{return null}}async function O(){let e=await n(process.env[h],h);if(e)return e;let t=S(),r=await E(t),a=w();try{if(await D()===r)return await u.access(a),a}catch{}let o=C();process.stderr.write(`agent-device: building macOS helper (first run or helper update)
|
|
2
|
-
`),await i(`swift`,[`build`,`-c`,`release`,`--package-path`,t],{cwd:t,timeoutMs:12e4}),await u.mkdir(g,{recursive:!0});let s=`${a}.tmp`;return await u.copyFile(o,s),await u.rename(s,a),await u.chmod(a,493),await u.writeFile(_,`${JSON.stringify({fingerprint:r},null,2)}\n`,`utf8`),a}async function k(){let e=process.env[h]?.trim();if(e){let t=await n(e,h);if(t)return t}if(o())return m;if(process.platform!==`darwin`)throw new t(`UNSUPPORTED_PLATFORM`,`macOS helper is only available on macOS`);return await O()}async function A(e){return r(await k(),[`audio-probe`,`--duration-ms`,String(e.durationMs),`--bucket-ms`,String(e.bucketMs),`--out`,e.statusPath],{allowFailure:!0,captureOutput:!0})}async function j(e,n={}){let r={allowFailure:!0,timeoutMs:3e4,signal:n.signal},o=a().macosHelper,s=o?m:await k(),c=o?await o.run(e,r):await i(s,e,r),l=c.stdout.trim(),u=null;if(l)try{u=JSON.parse(l)}catch{u=null}if(c.exitCode===0&&u?.ok)return u.data;throw new t(`COMMAND_FAILED`,u&&!u.ok?u.error?.message??`macOS helper exited with code ${c.exitCode}`:l||c.stderr.trim()||`macOS helper exited with code ${c.exitCode}`,{helperPath:s,args:e,stdout:c.stdout,stderr:c.stderr,exitCode:c.exitCode,...u&&!u.ok?u.error?.details:{}})}async function M(){return await j([`app`,`frontmost`])}async function N(e){return await j([`app`,`quit`,`--bundle-id`,y(e)])}async function P(e,t){return await j([`permission`,e,t])}async function F(e,t={}){let n=[`alert`,e];return b(n,t),await j(n)}async function I(e,t={}){let n=[`snapshot`,`--surface`,e];return b(n,t),await j(n,{signal:t.signal})}async function L(e,t,n={}){let r=[`read`,`--x`,String(e),`--y`,String(t)];return b(r,n),await j(r)}async function R(e,t,n={}){let r=[`press`,`--x`,String(e),`--y`,String(t)];return b(r,n),await j(r)}async function z(e,t={}){let n=[`screenshot`,`--out`,e];return b(n,t),t.fullscreen&&n.push(`--fullscreen`),await j(n)}export{z as a,P as i,N as n,
|
|
2
|
+
`),await i(`swift`,[`build`,`-c`,`release`,`--package-path`,t],{cwd:t,timeoutMs:12e4}),await u.mkdir(g,{recursive:!0});let s=`${a}.tmp`;return await u.copyFile(o,s),await u.rename(s,a),await u.chmod(a,493),await u.writeFile(_,`${JSON.stringify({fingerprint:r},null,2)}\n`,`utf8`),a}async function k(){let e=process.env[h]?.trim();if(e){let t=await n(e,h);if(t)return t}if(o())return m;if(process.platform!==`darwin`)throw new t(`UNSUPPORTED_PLATFORM`,`macOS helper is only available on macOS`);return await O()}async function A(e){return r(await k(),[`audio-probe`,`--duration-ms`,String(e.durationMs),`--bucket-ms`,String(e.bucketMs),`--out`,e.statusPath],{allowFailure:!0,captureOutput:!0})}async function j(e,n={}){let r={allowFailure:!0,timeoutMs:3e4,signal:n.signal},o=a().macosHelper,s=o?m:await k(),c=o?await o.run(e,r):await i(s,e,r),l=c.stdout.trim(),u=null;if(l)try{u=JSON.parse(l)}catch{u=null}if(c.exitCode===0&&u?.ok)return u.data;throw new t(`COMMAND_FAILED`,u&&!u.ok?u.error?.message??`macOS helper exited with code ${c.exitCode}`:l||c.stderr.trim()||`macOS helper exited with code ${c.exitCode}`,{helperPath:s,args:e,stdout:c.stdout,stderr:c.stderr,exitCode:c.exitCode,...u&&!u.ok?u.error?.details:{}})}async function M(){return await j([`app`,`frontmost`])}async function N(e){return await j([`app`,`quit`,`--bundle-id`,y(e)])}async function P(e,t){return await j([`permission`,e,t])}async function F(e,t={}){let n=[`alert`,e];return b(n,t),await j(n)}async function I(e,t={}){let n=[`snapshot`,`--surface`,e];return b(n,t),await j(n,{signal:t.signal})}async function L(e,t,n={}){let r=[`read`,`--x`,String(e),`--y`,String(t)];return b(r,n),await j(r)}async function R(e,t,n={}){let r=[`press`,`--x`,String(e),`--y`,String(t)];return b(r,n),await j(r)}async function z(e,t={}){let n=[`screenshot`,`--out`,e];return b(n,t),t.fullscreen&&n.push(`--fullscreen`),await j(n)}export{z as a,P as i,N as n,A as o,F as r,p as t};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{n as e}from"./rolldown-runtime.js";import{
|
|
1
|
+
import{n as e}from"./rolldown-runtime.js";import{E as t,_ as n}from"./sdk-contracts.js";import{mt as r}from"./sdk-batch-runner.js";import{A as i,_ as a,n as o,o as s,s as c}from"./sdk-android-adb.js";import{c as l,l as u,n as d,o as f,r as p,s as m}from"./helper-package-install.js";import{t as h}from"./keyed-lock.js";import{i as g,r as _,t as v}from"./ime-recovery-marker.js";const y=`IME helper`,b=`android-ime-helper-v1`;async function x(e){return e.imeHelperArtifact??await S()}async function S(){return await p({helperDirName:`ime-helper`,manifestFileName:e=>`agent-device-android-ime-helper-${e}.manifest.json`,parseManifest:C,unavailableMessage:`Android test IME text entry requires the bundled Android IME helper artifact, but it was not found or could not be read`})}function C(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new n(`INVALID_ARGS`,`Android IME helper manifest must be an object.`);let t=e;return{name:m(t.name,`name`,`android-ime-helper`,y),version:u(t.version,`version`,y),assetName:u(t.assetName,`assetName`,y),sha256:l(t.sha256,y),packageName:m(t.packageName,`packageName`,`com.callstack.agentdevice.imehelper`,y),versionCode:f(t.versionCode,`versionCode`,y),serviceComponent:m(t.serviceComponent,`serviceComponent`,`com.callstack.agentdevice.imehelper/.TestInputMethodService`,y),broadcastProtocol:m(t.broadcastProtocol,`broadcastProtocol`,b,y)}}const w=d({cache:new Set,installTimeoutMs:3e4,helperLabel:`Android IME helper`});function T(e){return`${e.platform}:${e.id}`}async function E(e,t,n){await O(e,t,`com.callstack.agentdevice.imehelper.ACTION_INPUT_TEXT_B64`,{text:Buffer.from(n,`utf8`).toString(`base64`)})}async function D(e,t){await O(e,t,`com.callstack.agentdevice.imehelper.ACTION_CLEAR_TEXT`,{})}async function O(e,t,n,r){let i=[`shell`,`am`,`broadcast`,`-p`,t,`-a`,n];i.push(`--es`,`protocol`,b);for(let[e,t]of Object.entries(r))i.push(`--es`,e,t);let a=await e(i,{allowFailure:!0,timeoutMs:1e4});if(a.exitCode!==0)throw o(`Android IME helper broadcast failed`,a,{action:n,packageName:t})}var k=e({ANDROID_TEST_IME_SETTINGS_KEYS:()=>Z,activateAndroidTestIme:()=>I,isAndroidTestImeActive:()=>F,listAndroidAdbSerialsQuick:()=>X,readAndroidDefaultInputMethod:()=>U,restoreAndroidTestIme:()=>R,restoreOrphanedAndroidTestImeOnDaemonStartup:()=>V});const A=`agent_device_ime_helper_previous_ime`,j=`secure`,M=`default_input_method`,N=new Set,P=new Map;function F(e){return N.has(T(e))}async function I(e,t){return await r(t.stateDir),await H(t.stateDir,e.id,async()=>await L(e,t))}async function L(e,n){let r=s(e),a=c(e),o=T(e),l;try{l=await x(a),await w({adb:r,adbProvider:a,artifact:l,deviceKey:o})}catch(e){return{outcome:`helper-unavailable`,reason:t(e).message}}let{manifest:u}=l,d=await U(r);if(d===u.serviceComponent){let t=await g(n.stateDir,e.id),i=await W(r);return t&&N.add(o),{outcome:`settled`,activated:!1,alreadyActive:!0,...t?{}:{persistFailed:!0},previousIme:i,helperServiceComponent:u.serviceComponent,helperPackageName:u.packageName}}let f=await W(r);if(!await G(r,d))return await q(r,f,e.id),i({level:`warn`,phase:`android_test_ime_persist_failed`,data:{device:e.id,previousIme:d}}),{outcome:`settled`,activated:!1,alreadyActive:!1,persistFailed:!0,helperServiceComponent:u.serviceComponent,helperPackageName:u.packageName};let p=(await _(n.stateDir)).includes(e.id);if(!await g(n.stateDir,e.id))return await q(r,f,e.id),i({level:`warn`,phase:`android_test_ime_marker_persist_failed`,data:{device:e.id,previousIme:d}}),{outcome:`settled`,activated:!1,alreadyActive:!1,persistFailed:!0,helperServiceComponent:u.serviceComponent,helperPackageName:u.packageName};await r([`shell`,`ime`,`enable`,u.serviceComponent],{allowFailure:!0,timeoutMs:1e4});let m=await r([`shell`,`ime`,`set`,u.serviceComponent],{allowFailure:!0,timeoutMs:1e4}),h=await U(r);return h===u.serviceComponent?(N.add(o),i({phase:`android_test_ime_activated`,data:{device:e.id,previousIme:d}}),{outcome:`settled`,activated:!0,alreadyActive:!1,previousIme:d,helperServiceComponent:u.serviceComponent,helperPackageName:u.packageName}):(N.delete(o),await q(r,f,e.id),p||await v(n.stateDir,e.id),i({level:`warn`,phase:`android_test_ime_activate_failed`,data:{device:e.id,activeIme:h,stderr:m.stderr.trim()}}),{outcome:`settled`,activated:!1,alreadyActive:!1,helperServiceComponent:u.serviceComponent,helperPackageName:u.packageName})}async function R(e,t){return await H(t.stateDir,e.id,async()=>{let n=T(e);if(!N.has(n))return{restored:!1,reason:`no-record`};N.delete(n);let r=await B(s(e),e);return z(r.reason)&&await v(t.stateDir,e.id),r})}function z(e){return e===`ok`||e===`helper-not-active`||e===`no-record`}async function B(e,t){let n=t.id;if(N.has(T(t)))return{restored:!1,reason:`owned-by-live-session`};let r=await W(e);if(!r)return{restored:!1,reason:`no-record`};let a=await U(e);if(a!==`com.callstack.agentdevice.imehelper/.TestInputMethodService`)return i({level:`debug`,phase:`android_test_ime_restore_skipped`,data:{device:n,currentIme:a,previousIme:r}}),{restored:!1,previousIme:r,reason:`helper-not-active`};await e([`shell`,`ime`,`set`,r],{allowFailure:!0,timeoutMs:1e4});let o=await U(e);return o===r?(await K(e).catch(()=>{}),i({phase:`android_test_ime_restored`,data:{device:n,previousIme:r}}),{restored:!0,previousIme:r,reason:`ok`}):(i({level:`warn`,phase:`android_test_ime_restore_failed`,data:{device:n,previousIme:r,afterIme:o}}),{restored:!1,previousIme:r,reason:`set-failed`})}async function V(e){let n=await _(e.stateDir);if(n.length===0)return;let r;try{r=new Set(await e.listSerials())}catch(e){i({level:`debug`,phase:`android_test_ime_startup_scan_failed`,data:{error:t(e).message}});return}for(let a of n){if(!r.has(a))continue;let n={platform:`android`,id:a,name:a,kind:a.startsWith(`emulator-`)?`emulator`:`device`,booted:!0};try{await H(e.stateDir,a,async()=>{let t=await B(s(n),n);t.restored&&i({level:`warn`,phase:`android_test_ime_orphan_restored`,data:{device:a,previousIme:t.previousIme}}),z(t.reason)&&await v(e.stateDir,a)})}catch(e){i({level:`debug`,phase:`android_test_ime_orphan_restore_failed`,data:{device:a,error:t(e).message}})}}}function H(e,t,n){return h(P,`${e}:${t}`,n)}async function U(e){let t=await e([`shell`,`settings`,`get`,j,M],{allowFailure:!0,timeoutMs:5e3});return Y(t.exitCode===0?t.stdout:``)}async function W(e){let t=await e([`shell`,`settings`,`get`,j,A],{allowFailure:!0,timeoutMs:5e3});return Y(t.exitCode===0?t.stdout:``)||void 0}async function G(e,t){return(await e([`shell`,`settings`,`put`,j,A,t],{allowFailure:!0,timeoutMs:5e3})).exitCode===0?await W(e)===t:!1}async function K(e){await e([`shell`,`settings`,`delete`,j,A],{allowFailure:!0,timeoutMs:5e3})}async function q(e,n,r){try{(n?await G(e,n):await J(e))||i({level:`warn`,phase:`android_test_ime_record_rollback_failed`,data:{device:r,hadPriorRecord:n!==void 0}})}catch(e){i({level:`warn`,phase:`android_test_ime_record_rollback_failed`,data:{device:r,hadPriorRecord:n!==void 0,error:t(e).message}})}}async function J(e){return await K(e),await W(e)===void 0}function Y(e){let t=e.trim();return!t||t===`null`?``:t}async function X(){try{return(await a(`adb`,[`devices`],{timeoutMs:5e3})).stdout.split(`
|
|
2
2
|
`).map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith(`List of devices`)).map(e=>e.split(/\s+/)).filter(e=>e[1]===`device`).map(e=>e[0])}catch{return[]}}const Z={previousIme:A,defaultInputMethod:M};export{D as a,E as c,U as i,k as n,S as o,F as r,x as s,Z as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./rolldown-runtime.js";import{
|
|
1
|
+
import{n as e}from"./rolldown-runtime.js";import{E as t}from"./sdk-contracts.js";import{A as n}from"./sdk-android-adb.js";import r from"node:path";import{randomUUID as i}from"node:crypto";import a from"node:fs/promises";var o=e({clearAndroidTestImeRecoveryMarker:()=>d,readAndroidTestImeRecoveryMarkers:()=>f,writeAndroidTestImeRecoveryMarker:()=>l});function s(e){return r.join(e,`android-test-ime-pending`)}function c(e,t){return r.join(s(e),encodeURIComponent(t))}async function l(e,o){let l,d,f,m=!1;try{let t=s(e);if(f=c(e,o),await a.mkdir(t,{recursive:!0}),(await p(f))?.serial===o)return!0;l=r.join(t,`.${encodeURIComponent(o)}.${i()}.tmp`);let n={version:1,serial:o};if(d=await a.open(l,`wx`,384),await d.writeFile(`${JSON.stringify(n)}\n`,`utf8`),await d.sync(),await d.close(),d=void 0,await a.rename(l,f),l=void 0,m=!0,await u(t),(await p(f))?.serial!==o)throw Error(`Android test IME marker read-back did not match the requested device.`);return!0}catch(r){return d&&await d.close().catch(()=>{}),l&&await a.rm(l,{force:!0}).catch(()=>{}),m&&f&&await a.rm(f,{force:!0}).catch(()=>{}),n({level:`debug`,phase:`android_test_ime_marker_write_failed`,data:{stateDir:e,serial:o,error:t(r).message}}),!1}}async function u(e){let t;try{t=await a.open(e,`r`),await t.sync()}catch{}finally{t&&await t.close().catch(()=>{})}}async function d(e,t){await a.rm(c(e,t),{force:!0}).catch(()=>{})}async function f(e){let t;try{t=await a.readdir(s(e))}catch{return[]}let n=[];for(let i of t)try{let t=r.join(s(e),i),a=await p(t);a&&c(e,a.serial)===t&&n.push(a.serial)}catch{}return[...new Set(n)].sort()}async function p(e){try{return m(await a.readFile(e,`utf8`))}catch{return}}function m(e){try{let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))return;let n=t;return n.version===1&&typeof n.serial==`string`&&n.serial.length>0?{version:1,serial:n.serial}:void 0}catch{return}}export{l as i,o as n,f as r,d as t};
|