agent-device 0.19.3 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -70
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.1.apk +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.1.apk.sha256 +1 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.1.manifest.json +10 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.1.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.1.apk.sha256 +1 -0
- package/{android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.3.manifest.json → android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.1.manifest.json} +6 -6
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +2 -0
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +5 -0
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +5 -10
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +74 -174
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +113 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +82 -0
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +325 -123
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +2 -2
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +149 -105
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +56 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +73 -0
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +51 -26
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +2 -2
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +2 -107
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +130 -13
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +51 -8
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +24 -0
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +1 -1
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +43 -35
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
- package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -1
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +3 -0
- package/dist/src/android-adb.d.ts +1 -1
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-method-overlays.js +1 -0
- package/dist/src/android-input-ownership.js +1 -6
- package/dist/src/android-system-chrome.js +1 -0
- package/dist/src/android.js +1 -1
- package/dist/src/app-lifecycle.js +5 -5
- package/dist/src/app-log-request-scope.js +1 -0
- package/dist/src/app-resolution.js +1 -0
- package/dist/src/apple-multitouch-support.js +1 -0
- package/dist/src/apps.js +5 -5
- package/dist/src/boot-diagnostics.js +2 -0
- package/dist/src/cli-config.js +1 -0
- package/dist/src/cli-help.js +131 -40
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +15 -11
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/compatibility-policy.js +1 -0
- package/dist/src/context.js +1 -0
- package/dist/src/contracts.d.ts +2 -2
- package/dist/src/debug-symbols.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/devices2.js +1 -1
- package/dist/src/devices4.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/helper.js +1 -1
- package/dist/src/index.d.ts +533 -279
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +4 -3
- package/dist/src/install-artifact.js +1 -0
- package/dist/src/install-source.d.ts +5 -1
- package/dist/src/install-source.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.d.ts +230 -0
- package/dist/src/interaction.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -0
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +42 -20
- package/dist/src/internal/png-worker.d.ts +22 -0
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/launch-console.js +1 -0
- package/dist/src/lease-context.js +1 -0
- package/dist/src/lease.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/logcat.js +5 -0
- package/dist/src/method-scope.js +1 -0
- package/dist/src/metro-types.d.ts +52 -0
- package/dist/src/metro.d.ts +3 -3
- package/dist/src/notifications.js +1 -1
- package/dist/src/png-worker-contract.js +1 -1
- package/dist/src/process-lock.js +1 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace.js +1 -1
- package/dist/src/recording-export-quality.js +15 -0
- package/dist/src/register-builtins.js +1 -0
- package/dist/src/registry.js +24 -24
- package/dist/src/remote-config.d.ts +1 -1
- package/dist/src/reporting.js +8 -7
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +2 -0
- package/dist/src/runner-lease.js +1 -0
- package/dist/src/runner-provider.js +1 -1
- package/dist/src/runner-sequence.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +1 -0
- package/dist/src/sdk-android-adb.d.ts +97 -33
- package/dist/src/sdk-android-adb.js +4 -4
- package/dist/src/sdk-batch-runner.d.ts +2 -1
- package/dist/src/sdk-batch-runner.js +3 -2
- package/dist/src/sdk-contracts.d.ts +70 -149
- package/dist/src/sdk-contracts.js +1 -1
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +5 -4
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-io.d.ts +1 -1
- package/dist/src/sdk-remote-config.d.ts +19 -96
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selector-vocabulary.js +1 -0
- package/dist/src/selectors.d.ts +12 -3
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +3 -3
- package/dist/src/session-target-evidence.js +1 -0
- package/dist/src/session.js +8 -10
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.js +5 -2
- package/dist/src/snapshot-quality.js +1 -1
- package/dist/src/snapshot.js +1 -1
- package/dist/src/snapshot2.js +1 -2
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/unsupported-interactor.js +1 -0
- package/dist/src/url.js +1 -1
- package/dist/src/web.js +1 -1
- package/package.json +34 -27
- package/server.json +2 -2
- package/skills/agent-device/SKILL.md +5 -3
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.apk +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.apk.sha256 +0 -1
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.manifest.json +0 -10
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.3.apk +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.3.apk.sha256 +0 -1
- package/dist/src/apple-runner-options.js +0 -1
- package/dist/src/cli-output.js +0 -1
- package/dist/src/client.js +0 -3
- package/dist/src/handler-utils.js +0 -1
- package/dist/src/output-path.js +0 -1
- package/dist/src/points.js +0 -4
- package/dist/src/provider.js +0 -1
- package/dist/src/providers.js +0 -1
- package/dist/src/record-trace-recording.js +0 -23
- package/dist/src/recording-provider.js +0 -1
- package/dist/src/sdk-batch.js +0 -2
- package/dist/src/selectors2.js +0 -1
- package/dist/src/ttl-memo.js +0 -1
- package/dist/src/tv-remote.js +0 -14
- package/dist/src/xml.js +0 -2
- /package/{macos-helper → apple/macos-helper}/Package.swift +0 -0
- /package/{macos-helper → apple/macos-helper}/Sources/AgentDeviceMacOSHelper/AudioProbe.swift +0 -0
- /package/{macos-helper → apple/macos-helper}/Sources/AgentDeviceMacOSHelper/SnapshotTraversal.swift +0 -0
- /package/{macos-helper → apple/macos-helper}/Sources/AgentDeviceMacOSHelper/main.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/xcshareddata/xcschemes/AgentDeviceRunner.xcscheme +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests-Bridging-Header.h +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests.entitlements +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerObjCExceptionCatcher.h +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerObjCExceptionCatcher.m +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/AgentDeviceRunnerUITests.xctestplan +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/RecordingScripts/recording-resize.swift +0 -0
- /package/dist/{apple-runner → apple/runner}/AgentDeviceRunner/RecordingScripts/recording-trim.swift +0 -0
- /package/{src/platforms/linux → linux}/atspi-dump.py +0 -0
package/dist/src/cli.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import{S as e,_ as t,a as n,v as r}from"./sdk-contracts.js";import{A as i,E as a,I as o,M as s,N as c,O as l,S as u,j as d,v as f}from"./sdk-android-adb.js";import{C as p}from"./sdk-batch.js";import{An as m,Bn as h,Dn as g,Gn as _,Qn as v,Un as y,Vn as b,Wn as x,Xn as S,Yn as C,Zn as w,jn as T,zn as E}from"./tv-remote.js";import{a as D,c as ee,i as te,l as ne,n as re,o as ie,r as ae,s as oe}from"./client.js";import{C as O,D as se,c as ce,o as le}from"./snapshot-diagnostics.js";import{n as ue}from"./version.js";import{n as k,t as de}from"./path-resolution.js";import{_ as A,h as fe,l as pe,u as me,v as he}from"./registry.js";import{a as ge,l as j}from"./sdk-batch-runner.js";import{v as _e}from"./url.js";import{i as ve,r as ye}from"./client-metro-companion.js";import{_ as be,i as xe,m as Se,s as Ce}from"./sdk-device.js";import"./selectors2.js";import{n as we}from"./command-metadata.js";import{n as Te}from"./metro2.js";import{n as Ee,r as De,t as M}from"./providers.js";import{n as Oe,r as ke,t as Ae}from"./command-schema.js";import{t as je}from"./update-check.js";import{i as Me,n as Ne,r as Pe,t as Fe}from"./sdk-remote-config.js";import{i as N,r as Ie,t as Le}from"./cli-runner.js";import{_ as Re,t as ze,v as Be,y as Ve}from"./points.js";import P,{randomBytes as He,randomUUID as Ue}from"node:crypto";import F from"node:fs";import I from"node:path";import We from"node:http";import{pipeline as Ge}from"node:stream/promises";import{Readable as Ke}from"node:stream";import{pathToFileURL as qe}from"node:url";function L(e,t){for(let[n,r]of Object.entries(t))r!==void 0&&(e[n]=r);return e}const Je=new Set([`config`,`remoteConfig`,`help`,`version`,`batchSteps`,`githubActionsArtifact`]),Ye=new Set([`appsFilter`,`iosSimulatorDeviceSet`,`sessionLocked`,`sessionLockConflicts`]),Xe=tt(),Ze=new Map(Xe.map(e=>[e.key,e]));function Qe(e){return Ze.get(e)}function $e(e){return Xe.filter(t=>t.config.enabled&&t.supportsCommand(e))}function R(e,t){return Qe(e)?.supportsCommand(t)??!1}function et(e,t,n,r){return l(rt(e),t,n,r)}function tt(){let e=new Map;for(let t of he()){let n=e.get(t.key);n?n.push(t):e.set(t.key,[t])}let t=new Map;for(let e of fe)t.set(e,new Set([`*`]));for(let e of v()){let n=Oe(e);for(let r of[...n.allowedFlags??[],...n.supportedFlags??[]]){let n=t.get(r);n&&n.has(`*`)||(n?n.add(e):t.set(r,new Set([e])))}}return[...e.entries()].map(([e,n])=>({key:e,flagDefinitions:n,config:{enabled:!Je.has(e),key:e},env:{names:Ye.has(e)?[]:[a(e)]},supportsCommand(n){let r=t.get(e);return r?r.has(`*`)?!0:n?r.has(n):!1:!1}})).sort((e,t)=>e.key.localeCompare(t.key))}function nt(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}function rt(e){let t=e.flagDefinitions.find(e=>e.setValue===void 0);if(t)return t;let n=nt(e);if(n.type===`enum`){let t=n.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>e!==void 0);return{...n,setValue:void 0,enumValues:t}}return n}const it=new Map([{alias:`long-press`,command:`longpress`},{alias:`metrics`,command:`perf`},{alias:`tap`,command:`press`},{alias:`launch`,command:`open`},{alias:`relaunch`,command:`open`,impliedFlags:[`relaunch`]}].map(e=>[e.alias,e]));function at(e){return it.get(e.toLowerCase())?.command??e}function ot(e){return it.get(e.toLowerCase())}const z=`open <app> --relaunch`,st={start:{command:`open`,example:z},restart:{command:`open`,example:z},touch:{command:`press`,example:`press`},input:{command:`fill`,example:`fill`},settext:{command:`fill`,example:`fill`},entertext:{command:`fill`,example:`fill`},screencap:{command:`screenshot`,example:`screenshot`},capture:{command:`screenshot`,example:`screenshot`},dismiss:{command:`keyboard`,example:`keyboard dismiss`},"get-text":{command:`get`,example:`get text`},gettext:{command:`get`,example:`get text`},get_text:{command:`get`,example:`get text`},"open-url":{command:`open`,example:`open <url>`},"close-session":{command:`close`,example:`close`}};function ct(e){if(e.length<=2)return[];let t=v(),n=t.filter(t=>t.startsWith(e));if(n.length>0)return n.sort((e,t)=>e.length-t.length||e.localeCompare(t)).slice(0,3);let r=lt(e),i=t.map(t=>({name:t,distance:ut(e,t)})).filter(e=>e.distance<=r);if(i.length===0)return[];let a=Math.min(...i.map(e=>e.distance));return i.filter(e=>e.distance===a).sort((e,t)=>e.name.localeCompare(t.name)).slice(0,3).map(e=>e.name)}function lt(e){return e.length<4?1:e.length<=6?2:3}function ut(e,t){return e===t?0:e.startsWith(t)||t.startsWith(e)?Math.abs(e.length-t.length):dt(e,t)}function dt(e,t){let n=e.length+1,r=t.length+1,i=Array.from({length:n},()=>Array(r).fill(0));for(let e=0;e<n;e+=1)i[e][0]=e;for(let e=0;e<r;e+=1)i[0][e]=e;for(let a=1;a<n;a+=1)for(let n=1;n<r;n+=1){let r=e[a-1]===t[n-1]?0:1;i[a][n]=Math.min(i[a-1][n]+1,i[a][n-1]+1,i[a-1][n-1]+r)}return i[n-1][r-1]}function ft(e){let t=e.toLowerCase(),n=st[t]?.example;if(n)return n;let r=ct(t);if(r.length!==0)return r.length===1?r[0]:`one of: ${r.join(`, `)}`}const pt=new Set([`--bundle-id`,`--bundleid`,`--bundle`,`--package`,`--package-name`,`--packagename`,`--app-id`,`--appid`,`--pkg`]);function mt(e){return pt.has(e.toLowerCase())?`Unknown flag: ${e}. The app or bundle id is a positional argument, e.g. ${z}.`:`Unknown flag: ${e}`}function ht(e){let n={json:!1,help:!1,version:!1},r=null,i=null,a=[],o=[],s=[],c=!0;for(let o=0;o<e.length;o+=1){let l=e[o];if(c&&l===`--`){c=!1;continue}if(!c){r?a.push(l):(i=l,r=V(l));continue}if(yt(r)){a.push(l);continue}let u=l.startsWith(`--`),d=l.startsWith(`-`)&&l.length>1;if(!u&&!d){r?a.push(l):(i=l,r=V(l));continue}let[f,p]=u?Ct(l):[l,void 0];if(_t(r,f))continue;let m=bt(f,r);if(vt(r,m)){a.push(l);continue}if(!m){if(Ot(r,a,l)){r?a.push(l):r=l;continue}throw new t(`INVALID_ARGS`,mt(f))}let h=wt(m,f,p,e[o+1]);h.consumeNext&&(o+=1);let g=n[m.key];if(m.multiple){let e=Array.isArray(g)?[...g,h.value]:g===void 0?[h.value]:[g,h.value];n[m.key]=e}else n[m.key]=h.value;s.push({key:m.key,token:f})}return gt(i,n),{command:r,positionals:a,flags:n,warnings:o,providedFlags:s}}function gt(e,t){if(e)for(let n of ot(e)?.impliedFlags??[])t[n]=!0}function _t(e,t){return t===`-c`&&(e===`snapshot`||e===`diff`)}function vt(e,t){return e===`react-devtools`?t?!R(t.key,e):!0:!1}function yt(e){return e===`cdp`}function bt(e,t){let n=he().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??A(e);if(t){let e=n.find(e=>R(e.key,t));if(e)return e}return A(e)}function xt(e,n){let r=n?.strictFlags??!0,i=[...e.warnings],a=L({json:!1,help:!1,version:!1},n?.defaultFlags??{});if(L(a,e.flags),e.command&&!w(e.command)&&!a.help){let n=ft(e.command);throw new t(`INVALID_ARGS`,n?`Unknown command: ${e.command}. Did you mean ${n}?`:`Unknown command: ${e.command}`)}let o=e.providedFlags.filter(t=>!R(t.key,e.command));if(o.length>0){let n=o.map(e=>e.token),s=jt(e.command,n);if(r)throw new t(`INVALID_ARGS`,s);i.push(s);for(let e of o)delete a[e.key]}for(let t of Object.keys(a))a[t]!==void 0&&(R(t,e.command)||delete a[t]);if(St(e),Ae(e.command,a),e.command===`batch`&&+!!a.steps+ +!!a.stepsFile!=1)throw new t(`INVALID_ARGS`,`batch requires exactly one step source: --steps or --steps-file.`);return At({command:e.command,positionals:e.positionals,flags:a,warnings:i})}function St(e){if(e.command!==`back`)return;let n=e.providedFlags.filter(e=>e.key===`backMode`);if(!(new Set(n.map(e=>e.token)).size<=1))throw new t(`INVALID_ARGS`,`back accepts only one explicit mode flag: use either --in-app or --system.`)}function Ct(e){let t=e.indexOf(`=`);return t===-1?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function wt(e,n,r,i){if(e.setValue!==void 0){if(r!==void 0)throw new t(`INVALID_ARGS`,`Flag ${n} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if(e.type===`boolean`){if(r!==void 0)throw new t(`INVALID_ARGS`,`Flag ${n} does not take a value.`);return{value:!0,consumeNext:!1}}if(e.type===`booleanOrString`){if(r!==void 0){if(r.trim().length===0)throw new t(`INVALID_ARGS`,`Flag ${n} requires a non-empty value when provided.`);return{value:r,consumeNext:!1}}return i===void 0||Et(i)?{value:!0,consumeNext:!1}:Dt(i)?{value:i,consumeNext:!0}:{value:!0,consumeNext:!1}}let a=r??i;if(a===void 0||r===void 0&&Et(a))throw new t(`INVALID_ARGS`,`Flag ${n} requires a value.`);if(e.type===`string`)return{value:a,consumeNext:r===void 0};if(e.type===`enum`){if(!e.enumValues?.includes(a))throw new t(`INVALID_ARGS`,`Invalid ${Tt(n)}: ${a}`);return{value:a,consumeNext:r===void 0}}let o=Number(a);if(!Number.isFinite(o)||typeof e.min==`number`&&o<e.min||typeof e.max==`number`&&o>e.max)throw new t(`INVALID_ARGS`,`Invalid ${Tt(n)}: ${a}`);return{value:Math.floor(o),consumeNext:r===void 0}}function Tt(e){return e.replace(/^-+/,``)}function Et(e){if(!e.startsWith(`-`)||e===`-`)return!1;let[t]=e.startsWith(`--`)?Ct(e):[e,void 0];return A(t)!==void 0}function Dt(e){let t=e.trim();return!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t)?!1:!!(t.startsWith(`./`)||t.startsWith(`../`)||t.startsWith(`~/`)||t.startsWith(`/`)||t.includes(`/`)||t.includes(`\\`))}function Ot(e,t,n){if(!kt(n)||!e)return!1;let r=ke(e);if(!r||r.allowsExtraPositionals)return!0;let i=r.positionalArgs??[];return i.length===0?!1:t.length<i.length?!0:i.some(e=>e.includes(`?`))}function kt(e){return/^-\d+(\.\d+)?$/.test(e)}function At(e){if(e.flags.help)return e;if(e.command===`snapshot`&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:`diff`,positionals:[`snapshot`,...e.positionals],flags:n,warnings:e.warnings}}return e}function jt(e,t){return e?t.length===1?`Flag ${t[0]} is not supported for command ${e}.`:`Flags ${t.join(`, `)} are not supported for command ${e}.`:t.length===1?`Flag ${t[0]} requires a command that supports it.`:`Flags ${t.join(`, `)} require a command that supports them.`}async function B(){let{buildUsageText:e}=await import(`./cli-help.js`);return e()}async function Mt(e){let{buildCommandUsageText:t}=await import(`./cli-help.js`);return t(V(e))}function V(e){return at(e)}const Nt={slug:`react-devtools-companion`,runArg:_e,displayName:`React DevTools companion`};async function Pt(e){return await ye({...e,definition:Nt,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 Ft(e){return await ve({...e,definition:Nt})}function It(e){let n=e.env??process.env,r=zt(e);if(!F.existsSync(r))throw new t(`INVALID_ARGS`,`Remote config file not found: ${r}`);let i;try{i=F.readFileSync(r,`utf8`)}catch(e){throw new t(`INVALID_ARGS`,`Failed to read remote config file: ${r}`,{cause:e instanceof Error?e.message:String(e)})}let a;try{a=JSON.parse(i)}catch(e){throw new t(`INVALID_ARGS`,`Invalid JSON in remote config file: ${r}`,{cause:e instanceof Error?e.message:String(e)})}if(!a||typeof a!=`object`||Array.isArray(a))throw new t(`INVALID_ARGS`,`Remote config file must contain a JSON object: ${r}`);let o={},s=a,c=I.dirname(r);for(let[e,i]of Object.entries(s)){let a=Me(e);if(!a)throw new t(`INVALID_ARGS`,`Unsupported remote config key "${e}" in remote config file ${r}.`);let s=l(a,i,`remote config file ${r}`,e);o[a.key]=typeof s==`string`&&`path`in a&&a.path?k(s,{cwd:c,env:n}):s}return{resolvedPath:r,profile:o}}function Lt(e=process.env){let t={};for(let n of Ne){let r=Pe(n.key).map(t=>({name:t,value:e[t]})).find(e=>typeof e.value==`string`&&e.value.trim().length>0);r&&(t[n.key]=l(n,r.value,`environment variable ${r.name}`,r.name))}return t}function Rt(...e){let t={};for(let n of e)if(n)for(let e of Ne){let r=n[e.key];r!==void 0&&(t[e.key]=r)}return t}function zt(e){let t=e.env??process.env;return k(e.configPath,{cwd:e.cwd,env:t})}function H(e){let t=It(e);return{resolvedPath:t.resolvedPath,profile:Rt(Lt(e.env),t.profile)}}function Bt(e){return e===`android-instance`||e===`ios-instance`}function Vt(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function Ht(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function Ut(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!Ht(e)}function Wt(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 Gt(e){let t=e?.metroPublicBaseUrl?.trim();return t?Wt(t):null}function Kt(e,n={}){if(!Ut(e)||!n.flags?.metroProxyBaseUrl||!Bt(n.flags.leaseBackend))return e;let r=Gt(n.flags);if(!r)throw new t(`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[...e,`--url`,r]}async function qt(e,t={}){return(await u(`npm`,Vt(Kt(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 U(e){let t=$t(e);if(!F.existsSync(t))return null;let n;try{n=JSON.parse(F.readFileSync(t,`utf8`))}catch(t){return cn(e,t),null}return un(n)?n:(cn(e),null)}function Jt(e){let t=$t({stateDir:e.stateDir,session:e.state.session});F.mkdirSync(I.dirname(t),{recursive:!0}),on(t,e.state),on(en(e.stateDir),{session:e.state.session})}function Yt(e){return{baseUrl:sn(e.daemonBaseUrl),authToken:e.daemonAuthToken,transport:e.daemonTransport,serverMode:e.daemonServerMode}}function Xt(e){F.rmSync($t(e),{force:!0});let t=en(e.stateDir);nn(e.stateDir)===e.session&&F.rmSync(t,{force:!0})}function Zt(e){let n=e.validateRemoteConfigHash??!0,r=e.remoteConfig?zt({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,i=U(e)??(e.allowActiveFallback?tn({stateDir:e.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&W(i.remoteConfigPath)!==i.remoteConfigHash)throw new t(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let a=an(i,e),o=g(i);return{runtime:i.runtime,connection:T(o),flags:{...a,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??a.daemonBaseUrl,daemonAuthToken:i.daemon?.authToken??a.daemonAuthToken,daemonTransport:i.daemon?.transport??a.daemonTransport,daemonServerMode:i.daemon?.serverMode??a.daemonServerMode,...m(o),sessionIsolation:`tenant`,session:i.session,platform:i.platform??a.platform,target:i.target??a.target}}}function Qt(e){return T(g(e))}function W(e){try{return P.createHash(`sha256`).update(F.readFileSync(e)).digest(`hex`)}catch(n){throw new t(`INVALID_ARGS`,`Remote config file not found: ${e}`,{cause:n instanceof Error?n.message:String(n)})}}function $t(e){return I.join(e.stateDir,`remote-connections`,`${ln(e.session)}.json`)}function en(e){return I.join(e,`remote-connections`,`.active-session.json`)}function tn(e){let t=nn(e.stateDir);return t?U({stateDir:e.stateDir,session:t}):null}function nn(e){let t=en(e);if(F.existsSync(t))try{let e=JSON.parse(F.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function rn(e){if(e)return P.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function an(e,t){try{return H({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function on(e,t){F.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),F.chmodSync(e,384)}function sn(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 cn(e,t){d({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),Xt(e)}function ln(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${P.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function un(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&dn(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&fn(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&pn(t.daemon)}function dn(e,t){return t.every(t=>typeof e[t]==`string`)}function fn(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function pn(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:mn(e)}function mn(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 hn=Fe.map(e=>e.key);function gn(e){let t={};for(let n of hn){let r=e[n];r!==void 0&&(t[n]=r)}return t}function _n(e){return e.remoteConfig?{...gn(H({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function vn(e){return e===`cloud`||e===`proxy`||Ee(e)}function yn(e){return Ee(e)}function bn(){return[`cloud`,`proxy`,M.browserStack,M.awsDeviceFarm].join(`, `)}function xn(e){return!yn(e)}function Sn(e){return e===`proxy`?`proxy`:yn(e)?`direct-device-provider`:`remote-provider`}const G=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),Cn=new Set([`open`]),wn=new Set([S.open,S.install,S.reinstall,C.installSource]);async function Tn(e){let{command:n,flags:r,client:i}=e;if(!r.remoteConfig)return{flags:r,runtime:e.runtime};let a=O(r.stateDir).baseDir,o=H({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...gn(o.profile),...r,remoteConfig:o.resolvedPath},c=U({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new t(`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 l=c??Jn(s,o.resolvedPath,o.profile),u={...s,session:l.session},d=qn(l.runtime,u.platform)??e.runtime,f=l,p=!c,m,h=Nn(f);if(h.shouldAllocate(n)){let e=await An({command:n,client:i,state:l,nextState:f,nextFlags:u,policy:h});f=e.state,p||=e.changed,m=e.acquiredLeaseForCleanup}let g=await En({command:n,flags:u,client:i,state:l,nextState:f,runtime:d,positionals:e.positionals,batchSteps:e.batchSteps,forceRuntimePrepare:e.forceRuntimePrepare});return f=g.state,d=g.runtime,p||=g.changed,await kn({changed:p,stateDir:a,state:f,client:i,acquiredLeaseForCleanup:m,preparedMetroCleanupOnFailure:g.preparedMetroCleanupOnFailure,metroCleanupToStop:g.metroCleanupToStop}),{flags:{...u,session:f.session,leaseId:f.leaseId,leaseBackend:f.leaseBackend,platform:f.platform??u.platform,target:f.target??u.target},runtime:d,connection:Qt(f)}}async function En(e){let{command:n,flags:r,state:i,client:a}=e,o=Dn(e.nextState,r),s=e.runtime;if(!Un(n,r,e.batchSteps,e.positionals)||!Wn(r)||!On(e.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new t(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Ln(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!Kn(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?e.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function Dn(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function On(e,t,n){return e===!0||!t||!Gn(t,n)}async function kn(e){if(e.changed)try{Jt({stateDir:e.stateDir,state:e.state})}catch(t){throw await K(e.preparedMetroCleanupOnFailure),await Vn(e.client,e.state,e.acquiredLeaseForCleanup),t}await K(e.metroCleanupToStop)}async function An(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??q(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&Zn(i,c.device);let l=s.leaseBackend??o??Hn(i,t);tr(r,i,l);let u=await Yn(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,jn(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Mn(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function jn(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Mn(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 Nn(e){return e.leaseProvider===`proxy`?Fn:Ee(e.leaseProvider)?In:Pn}const Pn={shouldAllocate:e=>!G.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Fn={shouldAllocate:e=>e!==`devices`&&!G.has(e),ttlMs:()=>3e5,resolveLeaseState:Xn},In={shouldAllocate:e=>!G.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Ln(e,n,r,i,a){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if(e.platform!==`ios`&&e.platform!==`android`)throw new t(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new t(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:e.metroProjectRoot,kind:pe(e.metroKind),publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:a,launchUrl:e.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:e.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:e.metroNoInstallDeps?!1:void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:e.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function K(e){if(e)try{await Te(e)}catch{}}async function Rn(e){try{await Ft({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function zn(e,t){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:t.daemon?.authToken,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}async function Bn(e,t){if(t.leaseId)try{await zn(e,t)}catch{}}async function Vn(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 q(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Hn(e,n){let r=q(e);if(r)return r;throw new t(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Un(e,t,n,r=[]){return e===`cdp`?Ut(r)&&!!t.metroPublicBaseUrl:Cn.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return Cn.has(t)&&e.runtime===void 0})}function Wn(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function Gn(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function Kn(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function qn(e,t){if(e)return Gn(e,t)?e:void 0}function Jn(e,n,r={}){if(!e.tenant)throw new t(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!e.runId)throw new t(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!e.daemonBaseUrl&&xn(r.leaseProvider))throw new t(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:e.session??`default`,remoteConfigPath:n,remoteConfigHash:W(n),daemon:Yt(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??q(e),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:e.platform,target:e.target,connectedAt:i,updatedAt:i}}async function Yn(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await nr(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,awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function Xn(e){if(!wn.has(e.command)){if(e.state.leaseId&&e.state.deviceKey)return{state:e.state};throw new t(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await Qn(e.client,e.flags),r=$n(n);return{state:{...e.state,deviceKey:r,leaseBackend:e.state.leaseBackend??e.leaseBackend??er(n),platform:e.state.platform??n.platform,target:e.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function Zn(e,t){if(e.platform=t.platform,e.target=t.target??e.target,Ce(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function Qn(e,t){return await be((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=>({...xe(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 $n(e){return`${Se(e)}:${e.target??`mobile`}:${e.id}`}function er(e){if(Ce(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function tr(e,n,r){if(e.leaseBackend&&e.leaseBackend!==r)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:e.session,leaseBackend:e.leaseBackend});if(e.platform&&n.platform&&e.platform!==n.platform)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:e.session,platform:e.platform});if(e.target&&n.target&&e.target!==n.target)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:e.session,target:e.target})}async function nr(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(rr(e))return;throw e}}function rr(e){return!(e instanceof t)||e.code!==`UNAUTHORIZED`?!1:e.details?.reason===`LEASE_NOT_FOUND`||e.details?.reason===`LEASE_EXPIRED`||e.details?.reason===`LEASE_REVOKED`}function ir(e){return we(e)}async function ar(e,n){let r=await e.text(),i={};if(r.trim().length>0)try{i=JSON.parse(r)}catch(r){throw new t(`COMMAND_FAILED`,n.invalidJsonMessage,{status:e.status},r instanceof Error?r:void 0)}if(!e.ok)throw new t(`UNAUTHORIZED`,n.rejectedMessage,{status:e.status,response:i});return i}const or=1e3;async function sr(e){return await cr({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:e.command===`connect`&&!e.flags.noLogin,env:e.env})}async function cr(e){let n=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:`none`};if(Y(e.flags.daemonAuthToken))return{flags:e.flags,source:`flag`};if(Y(n.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{flags:e.flags,source:`env`};if(!Tr(e.flags.daemonBaseUrl,n))return{flags:e.flags,source:`none`};let r=await gr({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});if(r)return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:`cli-session`};if(!e.allowInteractiveLogin)throw e.flags.noLogin?new t(`UNAUTHORIZED`,`Remote daemon authentication is required.`,{hint:`Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`}):wr(e.command,n);let i=await ur({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});return{flags:{...e.flags,daemonAuthToken:i.accessToken},source:`login`}}async function lr(e){let n=e.env??e.io?.env??process.env;if(Y(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:J(n)};if(Y(n.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:n.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:J(n)};let r=await gr({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});if(r)return{accessToken:r.accessToken,cloudBaseUrl:r.cloudBaseUrl};if(e.flags.noLogin)throw new t(`UNAUTHORIZED`,`Cloud connection profile authentication is required.`,{hint:`Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`});let i=await ur({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io,commandLabel:`agent-device connect`});return{accessToken:i.accessToken,cloudBaseUrl:i.session.cloudBaseUrl}}async function ur(e){let n=e.env??e.io?.env??process.env,r=xr(n,e.io);if(r===`non-interactive`)throw wr(e.commandLabel??`agent-device connect`,n);let i=J(n),a=await yr({baseUrl:i,pathName:`/api/control-plane/device-auth/start`,body:{client:`agent-device`,tenant:e.flags.tenant,runId:e.flags.runId,daemonBaseUrl:e.flags.daemonBaseUrl,session:e.flags.session},fetchImpl:e.io?.fetch});br(a);let o=a.verificationUriComplete??a.verificationUri,s=r===`local-browser`?a.verificationUri:Er(a.verificationUri,a.userCode);r===`local-browser`?(Or(e.io,`Opening ${a.verificationUri}...\n`),await Dr(o,e.io)):Or(e.io,`Open this URL on your machine:\n${s}\n\nWaiting for approval for 10 minutes...\n`);let c=await vr({cloudBaseUrl:i,deviceCode:a.deviceCode,expiresIn:a.expiresIn,interval:a.interval,fetchImpl:e.io?.fetch,now:e.io?.now}),l=c.cliSession?.refreshCredential??c.cliSession?.refreshToken;if(!Y(c.accessToken)||!Y(l))throw new t(`UNAUTHORIZED`,`Device authorization did not return CLI credentials.`);let u=new Date(e.io?.now?.()??Date.now()).toISOString(),d={version:1,id:c.cliSession?.id??`cli-${Date.now().toString(36)}`,cloudBaseUrl:i,workspaceId:c.cliSession?.workspaceId,accountId:c.cliSession?.accountId,name:c.cliSession?.name,refreshCredential:l,createdAt:u,expiresAt:c.cliSession?.expiresAt};return fr({stateDir:e.stateDir,session:d}),{accessToken:c.accessToken,expiresAt:c.expiresAt,session:d}}function dr(e){let t=mr(e.stateDir);if(!F.existsSync(t))return null;try{let e=JSON.parse(F.readFileSync(t,`utf8`));return e.version!==1||!Y(e.id)||!Y(e.cloudBaseUrl)||!Y(e.refreshCredential)||!Y(e.createdAt)?null:e}catch{return null}}function fr(e){let t=mr(e.stateDir);F.mkdirSync(I.dirname(t),{recursive:!0,mode:448}),F.writeFileSync(t,`${JSON.stringify(e.session,null,2)}\n`,{mode:384});try{F.chmodSync(t,384)}catch{}}function pr(e){let t=mr(e.stateDir);return F.existsSync(t)?(F.rmSync(t,{force:!0}),!0):!1}function mr(e){return I.join(e,`auth`,`cli-session.json`)}function hr(e){let t=dr({stateDir:e.stateDir});return t?{authenticated:!0,source:`cli-session`,sessionId:t.id,cloudBaseUrl:t.cloudBaseUrl,workspaceId:t.workspaceId,accountId:t.accountId,name:t.name,createdAt:t.createdAt,expiresAt:t.expiresAt,expired:kr(t.expiresAt,e.now)}:{authenticated:!1,source:`none`}}async function gr(e){let t=dr({stateDir:e.stateDir});return!t||kr(t.expiresAt,e.io?.now)?null:{accessToken:(await _r({session:t,flags:e.flags,env:e.env,io:e.io})).accessToken,cloudBaseUrl:J(e.env,t.cloudBaseUrl)}}async function _r(e){let n=await yr({baseUrl:J(e.env,e.session.cloudBaseUrl),pathName:`/api/control-plane/cli-session/refresh`,body:{refreshCredential:e.session.refreshCredential,tenant:e.flags.tenant,runId:e.flags.runId,daemonBaseUrl:e.flags.daemonBaseUrl,session:e.flags.session},fetchImpl:e.io?.fetch});if(Y(n.accessToken))return{accessToken:n.accessToken,expiresAt:n.expiresAt};throw n.status===`revoked`||n.error===`revoked`?new t(`UNAUTHORIZED`,`Stored cloud CLI session was revoked.`,{hint:`Run agent-device auth login again, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`,status:n.status,error:n.error}):new t(`UNAUTHORIZED`,`Failed to refresh CLI session.`,{hint:`Run agent-device auth login again, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`,status:n.status,error:n.error})}async function vr(e){let n=e.now??Date.now,r=Math.min((e.expiresIn??600)*1e3,6e5),i=n()+r,a=Math.max(or,(e.interval??5e3/1e3)*1e3);for(;n()<i;){let n=await yr({baseUrl:e.cloudBaseUrl,pathName:`/api/control-plane/device-auth/poll`,body:{deviceCode:e.deviceCode},fetchImpl:e.fetchImpl});if(n.status===`approved`||Y(n.accessToken))return n;if(n.status===`slow_down`||n.error===`slow_down`)a+=or;else if(n.status!==`authorization_pending`&&n.error!==`authorization_pending`)throw new t(`UNAUTHORIZED`,`Device authorization was not approved.`,{status:n.status,error:n.error});await Ar(a)}throw new t(`TIMEOUT`,`Device authorization expired before approval.`)}async function yr(e){let t=await(e.fetchImpl??fetch)(new URL(e.pathName,e.baseUrl),{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e.body),signal:AbortSignal.timeout(15e3)});return await ar(t,{invalidJsonMessage:`Cloud auth endpoint returned invalid JSON (${t.status}).`,rejectedMessage:`Cloud auth endpoint rejected the request.`})}function br(e){if(!Y(e.deviceCode)||!Y(e.userCode)||!Y(e.verificationUri))throw new t(`COMMAND_FAILED`,`Cloud auth start returned an unusable response.`)}function xr(e,t){let n=t?.stdinIsTTY??process.stdin.isTTY,r=t?.stdoutIsTTY??process.stdout.isTTY;return Sr(e)||!n||!r?`non-interactive`:Cr(e)?`device-code`:`local-browser`}function Sr(e){return e.CI===`true`||e.GITHUB_ACTIONS===`true`||e.BUILDKITE===`true`}function Cr(e){return!!(e.SSH_TTY||e.SSH_CONNECTION||e.CODESPACES===`true`||e.GITPOD_WORKSPACE_ID||e.REMOTE_CONTAINERS===`true`)}function wr(e,n){let r=J(n);return new t(`UNAUTHORIZED`,`${e} cannot perform interactive login in CI or a non-interactive shell.`,{hint:`Create a service/API token: ${new URL(`/api-keys`,r).toString()} Then set AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_...`})}function J(e,n){let r=e.AGENT_DEVICE_CLOUD_BASE_URL??n??`https://cloud.agent-device.dev`;try{return new URL(r).toString().replace(/\/+$/,``)}catch(e){throw new t(`INVALID_ARGS`,`Invalid AGENT_DEVICE_CLOUD_BASE_URL.`,{cloudBaseUrl:r},e instanceof Error?e:void 0)}}function Tr(e,t){if(t.AGENT_DEVICE_CLOUD_AUTH===`1`||t.AGENT_DEVICE_CLOUD_AUTH===`true`||Y(t.AGENT_DEVICE_CLOUD_BASE_URL))return!0;try{let t=new URL(e).hostname.toLowerCase();return t===`agent-device.dev`||t.endsWith(`.agent-device.dev`)}catch{return!1}}function Er(e,t){let n=new URL(e);return n.searchParams.set(`user_code`,t),n.toString()}async function Dr(e,t){if(t?.openBrowser){await t.openBrowser(e);return}let n=process.platform;try{n===`darwin`?await f(`open`,[e],{allowFailure:!0,timeoutMs:5e3}):n===`win32`?await f(`cmd`,[`/c`,`start`,``,e],{allowFailure:!0,timeoutMs:5e3}):await f(`xdg-open`,[e],{allowFailure:!0,timeoutMs:5e3})}catch{Or(t,`Open this URL on your machine:\n${e}\n`)}}function Or(e,t){(e?.stderr??process.stderr).write(t)}function kr(e,t){if(!e)return!1;let n=Date.parse(e);return Number.isFinite(n)?n<=(t?.()??Date.now()):!0}function Y(e){return typeof e==`string`&&e.trim().length>0}async function Ar(e){await new Promise(t=>setTimeout(t,e))}const jr=new Set([`daemonAuthToken`,`metroBearerToken`]);function Mr(e){let t=Lr(Fr(e.profile)),n=I.join(e.stateDir,`remote-connections`,`generated`);F.mkdirSync(n,{recursive:!0,mode:448});let r=I.join(n,`${Rr(e.provider)}-${Ir(t)}.json`);F.writeFileSync(r,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{F.chmodSync(r,384)}catch{}return r}function Nr(e){try{return H(e)}catch(n){let i=r(n);throw new t(`COMMAND_FAILED`,`${e.provider} connection profile returned invalid remote config.`,{generatedConfigPath:e.configPath,cause:i.message},i)}}function Pr(e){let t=Nr({configPath:Mr({stateDir:e.stateDir,provider:e.provider,profile:e.profile}),cwd:e.cwd,env:e.env,provider:zr(e.provider)});return{flags:{...gn(t.profile),...e.flags,...e.extraFlags??{},remoteConfig:t.resolvedPath},remoteConfigPath:t.resolvedPath}}function Fr(e){return Object.fromEntries(Object.entries(e).filter(([e])=>!jr.has(e)))}function Ir(e){return P.createHash(`sha256`).update(JSON.stringify(e)).digest(`hex`).slice(0,16)}function Lr(e){return Array.isArray(e)?e.map(Lr):e&&typeof e==`object`?Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Lr(t)])):e}function Rr(e){return e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`)||`generated`}function zr(e){let[t=``,...n]=e;return`${t.toUpperCase()}${n.join(``)}`}async function Br(e){let t=await lr({stateDir:e.stateDir,flags:e.flags,env:e.env,io:{env:e.env,fetch:e.fetchImpl}}),n=await Vr({cloudBaseUrl:t.cloudBaseUrl,accessToken:t.accessToken,fetchImpl:e.fetchImpl}),r=Wr({stateDir:e.stateDir,cloudBaseUrl:t.cloudBaseUrl,daemonBaseUrl:typeof n.daemonBaseUrl==`string`?n.daemonBaseUrl:``,session:e.flags.session});return Pr({stateDir:e.stateDir,provider:`cloud`,profile:{...n,leaseProvider:n.leaseProvider??`cloud`,clientId:n.clientId??r,runId:n.runId??`cloud-${r}`},cwd:e.cwd,env:e.env,flags:e.flags,extraFlags:{daemonAuthToken:t.accessToken}})}async function Vr(e){let t=await(e.fetchImpl??fetch)(new URL(`/api/control-plane/connection-profile`,e.cloudBaseUrl),{method:`GET`,headers:{authorization:`Bearer ${e.accessToken}`},signal:AbortSignal.timeout(15e3)});return Hr(await ar(t,{invalidJsonMessage:`Cloud connection profile endpoint returned invalid JSON (${t.status}).`,rejectedMessage:`Cloud connection profile endpoint rejected the request.`}))}function Hr(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new t(`COMMAND_FAILED`,`Cloud connection profile response is invalid.`);let n=e.connection;if(!n||typeof n!=`object`)throw new t(`COMMAND_FAILED`,`Cloud connection profile response is missing profile.`);if(n.remoteConfigProfile!==void 0)return Ur(n.remoteConfigProfile);throw new t(`COMMAND_FAILED`,`Cloud connection profile did not include remoteConfigProfile.`)}function Ur(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new t(`COMMAND_FAILED`,`Cloud connection profile remoteConfigProfile is invalid.`);if(Object.keys(e).length===0)throw new t(`COMMAND_FAILED`,`Cloud connection profile remoteConfigProfile is empty.`);return e}function Wr(e){return P.createHash(`sha256`).update(`${e.stateDir}\0${e.cloudBaseUrl}\0${e.daemonBaseUrl}\0${e.session??``}`).digest(`hex`).slice(0,16)}function Gr(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}}function Kr(e){let t=Jr(e.provider)(e),n=ti(e.provider,e.stateDir,e.flags.session,t.device),r={tenant:e.flags.tenant??e.provider,sessionIsolation:e.flags.sessionIsolation??`tenant`,runId:e.flags.runId??`${e.provider}-${n}`,leaseProvider:e.provider,clientId:n,leaseBackend:e.flags.leaseBackend??q(e.flags),target:e.flags.target??`mobile`,session:e.flags.session,...t,...Gr(e.flags)};return Pr({stateDir:e.stateDir,provider:e.provider,profile:r,cwd:e.cwd,env:e.env,flags:e.flags})}const qr=[{provider:M.browserStack,buildProfileFields:Yr},{provider:M.awsDeviceFarm,buildProfileFields:Xr}];function Jr(e){let n=qr.find(t=>t.provider===e)?.buildProfileFields;if(n)return n;throw new t(`INVALID_ARGS`,`Unsupported cloud WebDriver provider "${e}".`)}function Yr(e){return Qr(e.env,`BROWSERSTACK_USERNAME`,`connect browserstack`),Qr(e.env,`BROWSERSTACK_ACCESS_KEY`,`connect browserstack`),{platform:Zr(e.flags.platform,`connect browserstack requires --platform ios|android.`),device:X(e.flags.device,`connect browserstack requires --device <name>.`),providerOsVersion:X(e.flags.providerOsVersion,`connect browserstack requires --provider-os-version <version>.`),providerApp:X(e.flags.providerApp,`connect browserstack requires --provider-app <bs://app-id-or-local-path>.`),providerProject:e.flags.providerProject,providerBuild:e.flags.providerBuild,providerSessionName:e.flags.providerSessionName}}function Xr(e){let{env:t,flags:n}=e;return{platform:Zr(n.platform,`connect aws-device-farm requires --platform ios|android.`),device:n.device,awsProjectArn:$r(n.awsProjectArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_PROJECT_ARN`,`AWS_DEVICE_FARM_PROJECT_ARN`],`connect aws-device-farm requires --aws-project-arn <arn> or AWS_DEVICE_FARM_PROJECT_ARN.`),awsDeviceArn:$r(n.awsDeviceArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_DEVICE_ARN`,`AWS_DEVICE_FARM_DEVICE_ARN`],`connect aws-device-farm requires --aws-device-arn <arn> or AWS_DEVICE_FARM_DEVICE_ARN.`),awsAppArn:ei(n.awsAppArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_APP_ARN`,`AWS_DEVICE_FARM_APP_ARN`]),awsRegion:ei(n.awsRegion,t,[`AWS_REGION`,`AWS_DEFAULT_REGION`]),awsInteractionMode:n.awsInteractionMode,providerSessionName:n.providerSessionName}}function Zr(e,n){if(e===`android`||e===`ios`)return e;throw new t(`INVALID_ARGS`,n)}function X(e,n){if(e)return e;throw new t(`INVALID_ARGS`,n)}function Qr(e,n,r){let i=e?.[n];if(i)return i;throw new t(`INVALID_ARGS`,`${r} requires ${n} in the environment.`)}function $r(e,t,n,r){return X(ei(e,t,n),r)}function ei(e,t,n){return e||n.map(e=>t?.[e]).find(e=>!!e)}function ti(e,t,n,r){return P.createHash(`sha256`).update(`${e}\0${t}\0${n??``}\0${r??``}`).digest(`hex`).slice(0,16)}function ni(e){let n=e.flags.daemonBaseUrl??e.env?.AGENT_DEVICE_DAEMON_BASE_URL;if(!n)throw new t(`INVALID_ARGS`,`connect proxy requires --daemon-base-url <url> or AGENT_DEVICE_DAEMON_BASE_URL.`);let r=ri(e.stateDir,n,e.flags.session),i={daemonBaseUrl:n,daemonTransport:e.flags.daemonTransport??`http`,daemonServerMode:e.flags.daemonServerMode,tenant:e.flags.tenant??`proxy`,sessionIsolation:e.flags.sessionIsolation??`tenant`,runId:e.flags.runId??`proxy-${r}`,leaseProvider:`proxy`,clientId:r,leaseBackend:e.flags.leaseBackend??q(e.flags),platform:e.flags.platform,target:e.flags.target,device:e.flags.device,udid:e.flags.udid,serial:e.flags.serial,iosSimulatorDeviceSet:e.flags.iosSimulatorDeviceSet,androidDeviceAllowlist:e.flags.androidDeviceAllowlist,session:e.flags.session,...Gr(e.flags)};return Pr({stateDir:e.stateDir,provider:`proxy`,profile:i,cwd:e.cwd,env:e.env,flags:e.flags,extraFlags:{daemonBaseUrl:n,daemonTransport:e.flags.daemonTransport??`http`}})}function ri(e,t,n){return P.createHash(`sha256`).update(`${e}\0${t}\0${n??``}`).digest(`hex`).slice(0,16)}const ii=async({positionals:e,flags:t,client:n})=>{let r=O(t.stateDir).baseDir,i=wi(e);oi(i,t);let a=await ai({provider:i,flags:t,stateDir:r}),o=a.flags,s=gi(a.remoteConfigPath),c=si(o,s),l=ci({stateDir:r,flags:o,remoteConfigPath:a.remoteConfigPath});li(l.previous,{flags:o,session:l.session,remoteConfigPath:a.remoteConfigPath,remoteConfigHash:l.remoteConfigHash,desiredLeaseBackend:q(o),connection:s,daemon:l.daemon});let u=ui({flags:o,scope:c,connectionMetadata:s,context:l,remoteConfigPath:a.remoteConfigPath});Jt({stateDir:r,state:u}),await mi(n,r,o,l.previous);let d=Ii(u),f=Pi(o,u);return N(o,zi(u,f),()=>[`Connected remote session "${l.session}" tenant "${c.tenant}" run "${c.runId}" ${u.leaseId?`lease ${u.leaseId}`:`lease pending`}`,d?.message,f?.message].filter(e=>!!e).join(`
|
|
2
|
-
`)),!0};async function
|
|
3
|
-
`)),!0};function
|
|
4
|
-
`)}function
|
|
5
|
-
`):`Not authenticated.`}
|
|
6
|
-
`)}function Z(e,t,n){return n?E(e,t,{validateStream:!1}):e}function Oa(){return new Promise(()=>{})}const ka=new Set([`id`,`text`,`label`]),Aa=new Set([`enabled`,`selected`]);function ja(e){let t=Be(e);return Ma(t.actions,{actionLines:t.actionLines,metadata:Ve(e)})}function Ma(e,n={}){let r={config:Na(n.metadata),warnings:[],unsupported:[]},i=[];for(let[t,a]of e.entries()){let e=n.actionLines?.[t]??t+1,o=Fa(a);switch(o.kind){case`commands`:i.push(...o.commands),po(r,o.warnings,a,e);break;case`config`:uo(r,o.appId,a,e),i.push(...o.commands),po(r,o.warnings,a,e);break;case`unsupported`:r.unsupported.push({line:e,action:_o(a),message:o.message});break}}if(r.unsupported.length>0)throw new t(`INVALID_ARGS`,`Cannot export replay to Maestro YAML: unsupported .ad action ${go(r.unsupported)}.`,{unsupported:r.unsupported});return{yaml:ho(r.config,i),warnings:r.warnings}}function Na(e){return e?.env&&Object.keys(e.env).length>0?{env:e.env}:{}}const Pa={open:Ia,click:za,press:za,longpress:Ba,fill:Wa,type:Ga,keyboard:Ka,back:()=>({kind:`commands`,commands:[`back`]}),wait:qa,find:Ja,screenshot:Ya,scroll:Xa,swipe:Za};function Fa(e){return Pa[e.command]?.(e)??{kind:`unsupported`,message:`${e.command} has no Maestro equivalent`}}function Ia(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`open requires an app id or URL`};if(vo(t))return{kind:`commands`,commands:[{openLink:t}]};let r=La(e,t);return n&&vo(n)?{kind:`config`,appId:t,commands:[r,{openLink:n}]}:n?{kind:`unsupported`,message:`open with a non-URL second argument is unsupported`}:{kind:`config`,appId:t,commands:[r]}}function La(e,t){let n=Ra(e);return n?{launchApp:{appId:t,...n}}:`launchApp`}function Ra(e){let t=e.flags?.launchArgs,n={};return e.flags?.relaunch===!0&&(n.stopApp=!0),e.flags?.clearAppState===!0&&(n.clearState=!0),Array.isArray(t)&&t.length>0&&(n.launchArguments=t),Object.keys(n).length>0?n:void 0}function za(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`${e.command} requires a target`};let r=to(t,n);if(!r)return{kind:`unsupported`,message:`tap target is not Maestro-compatible`};let i=oo(e);return i.ok?e.flags?.doubleTap===!0?{kind:`commands`,commands:[{doubleTapOn:r}],warnings:Ua(e,`doubleTapOn`)}:typeof e.flags?.holdMs==`number`?{kind:`commands`,commands:[{longPressOn:r}],warnings:[Ha(e.flags.holdMs),...Ua(e,`longPressOn`)]}:{kind:`commands`,commands:[lo(r,i.options)]}:{kind:`unsupported`,message:i.message}}function Ba(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`longpress requires a target`};let r=to(t,n);return r?{kind:`commands`,commands:[{longPressOn:r}],warnings:Va(e).map(Ha)}:{kind:`unsupported`,message:`longpress target is not Maestro-compatible`}}function Va(e){let[t,n,r]=e.positionals,i=Q(t)&&Q(n)?r:n;return i&&Q(i)?[Number(i)]:[]}function Ha(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function Ua(e,t){let n=[];return typeof e.flags?.count==`number`&&e.flags.count>1&&n.push(`tap --count ${e.flags.count} is not represented by Maestro ${t}`),typeof e.flags?.intervalMs==`number`&&e.flags.intervalMs>0&&n.push(`tap --interval-ms ${e.flags.intervalMs} is not represented by Maestro ${t}`),n}function Wa(e){let[t,n]=e.positionals;if(!t||n===void 0)return{kind:`unsupported`,message:`fill requires a target and text`};let r=to(t);return r?{kind:`commands`,commands:[{tapOn:r},{inputText:n}],warnings:[`fill exports as tapOn + inputText; Maestro may append text instead of replacing existing field contents`]}:{kind:`unsupported`,message:`fill target is not Maestro-compatible`}}function Ga(e){let[t]=e.positionals;if(t===void 0)return{kind:`unsupported`,message:`type requires text`};let n=fo(t);return n===null?{kind:`commands`,commands:[{inputText:t}]}:{kind:`commands`,commands:[{eraseText:n}]}}function Ka(e){let[t]=e.positionals;return t===`dismiss`?{kind:`commands`,commands:[`hideKeyboard`]}:t===`enter`||t===`return`?{kind:`commands`,commands:[{pressKey:`Enter`}]}:{kind:`unsupported`,message:`keyboard ${t??``}`.trim()}}function qa(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`wait requires a target or duration`};if(Q(t))return{kind:`commands`,commands:[{waitForAnimationToEnd:{timeout:Number(t)}}],warnings:[`wait <ms> exports as waitForAnimationToEnd and may return before the full duration`]};if(t===`text`&&n)return{kind:`commands`,commands:[{extendedWaitUntil:{visible:n,timeout:mo(e,17e3)}}]};let r=no(t);return r?{kind:`commands`,commands:[{extendedWaitUntil:{visible:r,timeout:mo(e,17e3)}}]}:{kind:`unsupported`,message:`wait selector is not Maestro-compatible`}}function Ja(e){let[t,n,r]=e.positionals;return t!==`text`||!n||!r?{kind:`unsupported`,message:`only find text <query> exists|missing exports to Maestro`}:r===`exists`?{kind:`commands`,commands:[{assertVisible:n}]}:r===`missing`||r===`not-exists`?{kind:`commands`,commands:[{assertNotVisible:n}]}:{kind:`unsupported`,message:`find text assertion "${r}" is unsupported`}}function Ya(e){let[t]=e.positionals;return t?{kind:`commands`,commands:[{takeScreenshot:t}]}:{kind:`unsupported`,message:`screenshot requires an output path`}}function Xa(e){let[t]=e.positionals;return!t||t===`down`?{kind:`commands`,commands:[`scroll`]}:{kind:`unsupported`,message:`scroll ${t} is not exported yet`}}function Za(e){let t=Qa(e);if(!t)return{kind:`unsupported`,message:`only coordinate swipe exports to Maestro`};let n=$a(e);if(n===null)return{kind:`unsupported`,message:`swipe count must be a positive integer`};let r=eo(e);return r?{kind:`unsupported`,message:r}:{kind:`commands`,commands:Array.from({length:n},()=>({swipe:t}))}}function Qa(e){let[t,n,r,i,a]=e.positionals;if(!(!Q(t)||!Q(n)||!Q(r)||!Q(i)))return{start:ze(t,n),end:ze(r,i),...a&&Q(a)?{duration:Number(a)}:{}}}function $a(e){let t=e.flags?.count??1;return Number.isInteger(t)&&t>=1?t:null}function eo(e){if(e.flags?.pauseMs!==void 0)return`swipe --pause-ms has no Maestro equivalent`;if(e.flags?.pattern&&e.flags.pattern!==`one-way`)return`swipe ping-pong pattern has no Maestro equivalent`}function to(e,t){return Q(e)&&Q(t)?{point:ze(e,t)}:e.startsWith(`@`)?null:no(e)}function no(e){let t;try{t=p(e)}catch{return e.includes(`=`)||e.includes(`||`)?null:e}let n=ro(t.selectors);return n===null?t.selectors.length===1?io(t.selectors[0]):null:n}function ro(e){if(e.length<=1)return null;let t=e.flatMap(e=>e.terms.length===1&&ka.has(e.terms[0].key)?[e.terms[0].value]:[]);if(t.length!==e.length||t.length===0)return null;let n=t[0];return typeof n==`string`&&t.every(e=>e===n)?n:null}function io(e){let t={};for(let n of e.terms)if(!ao(t,n))return null;return Object.keys(t).length>0?t:null}function ao(e,t){return ka.has(t.key)?typeof t.value!=`string`||e.id||e.text||e.label?!1:(e[t.key]=t.value,!0):Aa.has(t.key)&&typeof t.value==`boolean`?(e[t.key]=t.value,!0):!1}function oo(e){let t=co(e);return t?{ok:!1,message:t}:{ok:!0,options:so(e)}}function so(e){let t={};return typeof e.flags?.count==`number`&&e.flags.count>1&&(t.repeat=e.flags.count),typeof e.flags?.intervalMs==`number`&&e.flags.intervalMs>0&&(t.delay=e.flags.intervalMs),t}function co(e){if(e.flags?.jitterPx!==void 0)return`tap --jitter-px has no Maestro equivalent`;if(e.flags?.clickButton&&e.flags.clickButton!==`primary`)return`tap --button ${e.flags.clickButton} has no Maestro equivalent`}function lo(e,t){return Object.keys(t).length===0?{tapOn:e}:typeof e==`string`?{tapOn:{text:e,...t}}:e&&typeof e==`object`&&!Array.isArray(e)?{tapOn:{...e,...t}}:{tapOn:e}}function uo(e,t,n,r){if(!e.config.appId){e.config.appId=t;return}e.config.appId!==t&&e.unsupported.push({line:r,action:_o(n),message:`multiple app ids cannot be represented in one Maestro config (${e.config.appId} vs ${t})`})}function fo(e){return e.length===0||![...e].every(e=>e===`\b`)?null:e.length}function po(e,t,n,r){for(let i of t??[])e.warnings.push({line:r,action:_o(n),message:i})}function mo(e,t){let n=e.positionals.at(-1);return n&&Q(n)?Number(n):t}function ho(e,t){return Re(Object.keys(e).length>0?[e,t]:[t])}function go(e){return e.map(e=>`line ${e.line} (${e.action}): ${e.message}`).join(`; `)}function _o(e){return[e.command,...e.positionals??[]].join(` `).trim()}function vo(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function Q(e){return e!==void 0&&Number.isFinite(Number(e))}const yo=async e=>{let{positionals:t}=e;return t[0]===`export`?await xo(e):bo(e)};function bo({positionals:e,flags:n}){if(e.length>1)throw new t(`INVALID_ARGS`,`replay accepts exactly one input path: replay <path>`);if(n.replayExportFormat!==void 0||n.out!==void 0)throw new t(`INVALID_ARGS`,`replay --format/--out are only supported with replay export.`);return!1}async function xo({positionals:e,flags:n}){So(e,n);let r=e[1];if(!r)throw new t(`INVALID_ARGS`,`replay export requires an input path.`);let i=k(r),a=ja(F.readFileSync(i,`utf8`)),o=typeof n.out==`string`?k(n.out):void 0;o&&(F.mkdirSync(I.dirname(o),{recursive:!0}),F.writeFileSync(o,a.yaml));for(let e of a.warnings)process.stderr.write(`Warning: line ${e.line}: ${e.message}\n`);return N(n,{format:n.replayExportFormat??`maestro`,sourcePath:i,...o?{path:o}:{yaml:a.yaml},warnings:a.warnings},()=>o??a.yaml),!0}function So(e,n){if(e.length>2)throw new t(`INVALID_ARGS`,`replay export accepts exactly one input path: replay export <file.ad>`);if(n.replayUpdate)throw new t(`INVALID_ARGS`,`replay export does not support --update.`);if(n.replayMaestro)throw new t(`INVALID_ARGS`,`replay export reads .ad files; omit --maestro.`);if(n.replayEnv?.length)throw new t(`INVALID_ARGS`,`replay export does not evaluate --env substitutions.`);let r=n.replayExportFormat??`maestro`;if(r!==`maestro`)throw new t(`INVALID_ARGS`,`Unsupported replay export format: ${r}`)}const Co=async({positionals:e,flags:t,client:r})=>{let i=await Le({client:r,command:`screenshot`,positionals:e,flags:t});return n(t.responseLevel)?(N(t,i,()=>JSON.stringify(i,null,2)),!0):(N(t,le(i),()=>i.overlayRefs?`Annotated ${i.overlayRefs.length} refs onto ${i.path}`:Eo(i)),!0)},wo=async({positionals:e,flags:n,client:r})=>{if(e[0]===`snapshot`){let t=await Le({client:r,command:`diff`,positionals:e,flags:n});return N(n,t,()=>b(t)),!0}if(e[0]!==`screenshot`)return!1;let i=n.baseline;if(!i||typeof i!=`string`)throw new t(`INVALID_ARGS`,`diff screenshot requires --baseline <path>`);let a=k(i),o=typeof n.out==`string`?k(n.out):void 0,s=e[1];if(e.length>2)throw new t(`INVALID_ARGS`,`diff screenshot accepts at most one current screenshot path`);let[{createAgentDevice:c,localCommandPolicy:l},{createLocalArtifactAdapter:u}]=await Promise.all([import(`./runtime.js`).then(e=>e.r),import(`./sdk-io.js`).then(e=>e.n)]),d=await c({backend:To(r,n),artifacts:u(),sessions:{get:e=>({name:e}),set:()=>{}},policy:l()}).capture.diffScreenshot({session:n.session,baseline:{kind:`path`,path:a},current:s?{kind:`path`,path:k(s)}:{kind:`live`},...o?{out:{kind:`path`,path:o}}:{},threshold:Oo(n.threshold),overlayRefs:n.overlayRefs,normalizeStatusBar:n.screenshotNormalizeStatusBar,surface:n.surface});return N(n,d,()=>h(d)),!0};function To(e,t){return{platform:Do(t),captureScreenshot:async(t,n,r)=>le(await e.capture.screenshot({path:n,session:t.session,overlayRefs:r?.overlayRefs,pixelDensity:r?.pixelDensity,fullscreen:r?.fullscreen,normalizeStatusBar:r?.normalizeStatusBar,stabilize:r?.stabilize,surface:r?.surface}))}}function Eo(e){if(typeof e.width!=`number`||typeof e.height!=`number`)return e.path;let t=typeof e.pixelDensity==`number`?` @${e.pixelDensity}x`:``;return`${e.path} (${e.width}x${e.height}${t})`}function Do(e){switch(e.platform){case`android`:case`linux`:case`macos`:return e.platform;default:return`ios`}}function Oo(e){if(!(e==null||e===``))return Number(e)}const ko={connect:ii,disconnect:_i,connection:vi,auth:Bi,proxy:xa,replay:yo,screenshot:Co,diff:wo};async function Ao(e){let t={...e.flags},n=ko[e.command];return n&&await n({...e,flags:t})?!0:ir(e.command)?await jo({...e,command:e.command,flags:t}):!1}async function jo(e){let{runGenericClientBackedCommand:t}=await import(`./generic.js`);return await t(e)}function Mo(e){return[`exec`,`--yes`,`--package`,`agent-react-devtools@0.4.0`,`--`,`agent-react-devtools`,...e]}function No(e){return e===`ios-instance`}function Po(e){return e[0]===`wait`&&e.includes(`--connected`)}function Fo(e,t,n){n===0||!Po(e)||!No(t?.leaseBackend)||process.stderr.write([`Hint: Remote iOS React DevTools connects during JavaScript startup.`,"If the app was already open before `agent-device react-devtools start`, relaunch it with `agent-device open <bundle-id> --platform ios --relaunch`, then retry `agent-device react-devtools wait --connected`.",``].join(`
|
|
7
|
-
`)
|
|
8
|
-
`)}function
|
|
9
|
-
|
|
10
|
-
`),h===`cdp`){let t=await qt(g,{flags:T,runtime:e,cwd:process.cwd(),env:process.env});process.exit(t);return}let o=T.daemonBaseUrl;D=_&&!T.json&&!o?Bs(S.logPath):null;let s=h===`test`?await import(`./reporting.js`).then(({createReplayTestReporterRuntime:e})=>e({debug:_,verbose:T.verbose,json:T.json,reporter:T.reporter,reportJunit:T.reportJunit})):void 0,c=re(r(T,e,n),{transport:Is({command:h,flags:T,replayTestReporterRuntime:s,transport:a.sendToDaemon})});if(h===`batch`){if(!i)throw new t(`INVALID_ARGS`,`batch requires --steps or --steps-file.`);let e=i.map((e,t)=>({...e,input:v.lockPolicy&&b.platform===void 0?{...e.input}:rs(e.input,{policyOverrides:T,configuredPlatform:T.platform,configuredSession:T.session,inheritedPlatform:T.platform})}));if(await Ao({command:h,positionals:g,flags:{...T,batchSteps:e},client:c,debug:_,replayTestReporterRuntime:s}))return}else if(h===`runtime`)throw new t(`INVALID_ARGS`,`runtime command was removed. Use connect --remote-config <path> for remote runs, or metro prepare --remote-config <path> for inspection.`);else if(await Ao({command:h,positionals:g,flags:T,client:c,debug:_,replayTestReporterRuntime:s}))return;throw new t(`INVALID_ARGS`,Ts(h))}catch(t){let n=r(t),i=e(n,{diagnosticId:c().diagnosticId,logPath:s({force:!0})??void 0});if(h===`close`&&Os(n)){T.json&&x({success:!0,data:{closed:`session`,source:`no-daemon`}});return}if(T.json)x({success:!1,error:i});else if(y(i,{showDetails:_}),_)try{let e=S.logPath;if(F.existsSync(e)){let t=F.readFileSync(e,`utf8`).split(`
|
|
1
|
+
import{S as e,_ as t,a as n,v as r}from"./sdk-contracts.js";import{A as i,L as a,M as o,N as s,O as c,S as l,j as u,v as d}from"./sdk-android-adb.js";import{Q as f,l as p,m}from"./sdk-batch-runner.js";import{$t as h,Qt as g,Yt as ee,cn as te,cr as _,dn as v,fn as y,ln as ne,lr as re,pn as ie,sn as ae,sr as oe,ur as se}from"./recording-export-quality.js";import{_t as ce,b,bt as le,c as ue,g as de,gt as fe,ht as pe,lt as me,o as he,v as ge,vt as _e,w as x}from"./snapshot-diagnostics.js";import{a as ve,i as ye,n as be,o as xe,r as Se}from"./agent-device-client.js";import{n as Ce}from"./version.js";import{n as S}from"./path-resolution.js";import{h as we,i as Te,s as Ee,v as De}from"./sdk-device.js";import"./sdk-selectors.js";import{t as Oe}from"./timeouts.js";import{n as ke,u as Ae}from"./host-process.js";import{_ as je,l as Me,v as Ne}from"./registry.js";import{v as Pe}from"./url.js";import{i as Fe,r as Ie}from"./client-metro-companion.js";import{n as Le}from"./command-metadata.js";import{n as Re}from"./metro2.js";import{a as ze,b as Be,i as Ve,n as He,o as Ue,p as We,u as Ge,v as C,y as w}from"./selector-vocabulary.js";import{r as Ke,t as qe}from"./command-schema.js";import{t as Je}from"./update-check.js";import{i as T,r as E,t as Ye}from"./cli-config.js";import{i as Xe,n as Ze,r as Qe,t as $e}from"./sdk-remote-config.js";import{i as D,r as et,t as tt}from"./cli-runner.js";import{t as nt}from"./compatibility-policy.js";import O,{randomBytes as rt,randomUUID as it}from"node:crypto";import k from"node:fs";import A from"node:path";import at from"node:http";import{pipeline as ot}from"node:stream/promises";import{Readable as st}from"node:stream";import{pathToFileURL as ct}from"node:url";import{stringify as lt}from"yaml";const ut=new Map([{alias:`long-press`,command:`longpress`},{alias:`metrics`,command:`perf`},{alias:`tap`,command:`press`},{alias:`launch`,command:`open`},{alias:`relaunch`,command:`open`,impliedFlags:[`relaunch`]}].map(e=>[e.alias,e]));function dt(e){return ut.get(e.toLowerCase())?.command??e}function ft(e){return ut.get(e.toLowerCase())}const j=`open <app> --relaunch`,pt={start:{command:`open`,example:j},restart:{command:`open`,example:j},touch:{command:`press`,example:`press`},input:{command:`fill`,example:`fill`},settext:{command:`fill`,example:`fill`},entertext:{command:`fill`,example:`fill`},screencap:{command:`screenshot`,example:`screenshot`},capture:{command:`screenshot`,example:`screenshot`},dismiss:{command:`keyboard`,example:`keyboard dismiss`},"get-text":{command:`get`,example:`get text`},gettext:{command:`get`,example:`get text`},get_text:{command:`get`,example:`get text`},"open-url":{command:`open`,example:`open <url>`},"close-session":{command:`close`,example:`close`}};function mt(e){if(e.length<=2)return[];let t=se(),n=t.filter(t=>t.startsWith(e));if(n.length>0)return n.sort((e,t)=>e.length-t.length||e.localeCompare(t)).slice(0,3);let r=ht(e),i=t.map(t=>({name:t,distance:gt(e,t)})).filter(e=>e.distance<=r);if(i.length===0)return[];let a=Math.min(...i.map(e=>e.distance));return i.filter(e=>e.distance===a).sort((e,t)=>e.name.localeCompare(t.name)).slice(0,3).map(e=>e.name)}function ht(e){return e.length<4?1:e.length<=6?2:3}function gt(e,t){return e===t?0:e.startsWith(t)||t.startsWith(e)?Math.abs(e.length-t.length):_t(e,t)}function _t(e,t){let n=e.length+1,r=t.length+1,i=Array.from({length:n},()=>Array(r).fill(0));for(let e=0;e<n;e+=1)i[e][0]=e;for(let e=0;e<r;e+=1)i[0][e]=e;for(let a=1;a<n;a+=1)for(let n=1;n<r;n+=1){let r=e[a-1]===t[n-1]?0:1;i[a][n]=Math.min(i[a-1][n]+1,i[a][n-1]+1,i[a-1][n-1]+r)}return i[n-1][r-1]}function vt(e){let t=e.toLowerCase(),n=pt[t]?.example;if(n)return n;let r=mt(t);if(r.length!==0)return r.length===1?r[0]:`one of: ${r.join(`, `)}`}const yt=new Set([`--bundle-id`,`--bundleid`,`--bundle`,`--package`,`--package-name`,`--packagename`,`--app-id`,`--appid`,`--pkg`]),bt=new Set([`--session-locked`,`--session-lock-conflicts`]);function xt(e){return yt.has(e.toLowerCase())?`Unknown flag: ${e}. The app or bundle id is a positional argument, e.g. ${j}.`:bt.has(e.toLowerCase())?`Unknown flag: ${e}. Use --session-lock reject|strip instead.`:`Unknown flag: ${e}`}function St(e){let n={json:!1,help:!1,version:!1},r=null,i=null,a=[],o=[],s=[],c=!0;for(let o=0;o<e.length;o+=1){let l=e[o];if(c&&l===`--`){c=!1;continue}if(!c){r?a.push(l):(i=l,r=Bt(l));continue}if(Et(r)){a.push(l);continue}let u=l.startsWith(`--`),d=l.startsWith(`-`)&&l.length>1;if(!u&&!d){r?a.push(l):(i=l,r=Bt(l));continue}let[f,p]=u?At(l):[l,void 0];if(wt(r,f))continue;let m=Dt(f,r);if(Tt(r,m)){a.push(l);continue}if(!m){if(Ft(r,a,l)){r?a.push(l):r=l;continue}throw new t(`INVALID_ARGS`,xt(f))}let h=jt(m,f,p,e[o+1]);h.consumeNext&&(o+=1);let g=n[m.key];if(m.multiple){let e=Array.isArray(g)?[...g,h.value]:g===void 0?[h.value]:[g,h.value];n[m.key]=e}else n[m.key]=h.value;s.push({key:m.key,token:f})}return Ct(i,n),{command:r,positionals:a,flags:n,warnings:o,providedFlags:s}}function Ct(e,t){if(e)for(let n of ft(e)?.impliedFlags??[])t[n]=!0}function wt(e,t){return t===`-c`&&(e===`snapshot`||e===`diff`)}function Tt(e,t){return e===`react-devtools`?t?!E(t.key,e):!0:!1}function Et(e){return e===`cdp`}function Dt(e,t){let n=Ne().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??je(e);if(t){let e=n.find(e=>E(e.key,t));if(e)return e}return je(e)}function Ot(e,n){let r=n?.strictFlags??!0,i=[...e.warnings],a=T({json:!1,help:!1,version:!1},n?.defaultFlags??{});if(T(a,e.flags),e.command&&!re(e.command)&&!a.help){let n=vt(e.command);throw new t(`INVALID_ARGS`,n?`Unknown command: ${e.command}. Did you mean ${n}?`:`Unknown command: ${e.command}`)}let o=e.providedFlags.filter(t=>!E(t.key,e.command));if(o.length>0){let n=o.map(e=>e.token),s=Rt(e.command,n);if(r)throw new t(`INVALID_ARGS`,s);i.push(s);for(let e of o)delete a[e.key]}for(let t of Object.keys(a))a[t]!==void 0&&(E(t,e.command)||delete a[t]);if(kt(e),qe(e.command,a),e.command===`batch`&&+!!a.steps+ +!!a.stepsFile!=1)throw new t(`INVALID_ARGS`,`batch requires exactly one step source: --steps or --steps-file.`);return Lt({command:e.command,positionals:e.positionals,flags:a,warnings:i})}function kt(e){if(e.command!==`back`)return;let n=e.providedFlags.filter(e=>e.key===`backMode`);if(!(new Set(n.map(e=>e.token)).size<=1))throw new t(`INVALID_ARGS`,`back accepts only one explicit mode flag: use either --in-app or --system.`)}function At(e){let t=e.indexOf(`=`);return t===-1?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function jt(e,n,r,i){if(e.setValue!==void 0){if(r!==void 0)throw new t(`INVALID_ARGS`,`Flag ${n} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if(e.type===`boolean`){if(r!==void 0)throw new t(`INVALID_ARGS`,`Flag ${n} does not take a value.`);return{value:!0,consumeNext:!1}}if(e.type===`booleanOrString`){if(r!==void 0){if(r.trim().length===0)throw new t(`INVALID_ARGS`,`Flag ${n} requires a non-empty value when provided.`);return{value:r,consumeNext:!1}}return i===void 0||Nt(i)?{value:!0,consumeNext:!1}:Pt(i)?{value:i,consumeNext:!0}:{value:!0,consumeNext:!1}}let a=r??i;if(a===void 0||r===void 0&&Nt(a))throw new t(`INVALID_ARGS`,`Flag ${n} requires a value.`);if(e.type===`string`)return{value:a,consumeNext:r===void 0};if(e.type===`enum`){if(!e.enumValues?.includes(a))throw new t(`INVALID_ARGS`,`Invalid ${Mt(n)}: ${a}`);return{value:a,consumeNext:r===void 0}}let o=Number(a);if(!Number.isFinite(o)||typeof e.min==`number`&&o<e.min||typeof e.max==`number`&&o>e.max)throw new t(`INVALID_ARGS`,`Invalid ${Mt(n)}: ${a}`);return{value:Math.floor(o),consumeNext:r===void 0}}function Mt(e){return e.replace(/^-+/,``)}function Nt(e){if(!e.startsWith(`-`)||e===`-`)return!1;let[t]=e.startsWith(`--`)?At(e):[e,void 0];return je(t)!==void 0}function Pt(e){let t=e.trim();return!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t)?!1:!!(t.startsWith(`./`)||t.startsWith(`../`)||t.startsWith(`~/`)||t.startsWith(`/`)||t.includes(`/`)||t.includes(`\\`))}function Ft(e,t,n){if(!It(n)||!e)return!1;let r=Ke(e);if(!r||r.allowsExtraPositionals)return!0;let i=r.positionalArgs??[];return i.length===0?!1:t.length<i.length?!0:i.some(e=>e.includes(`?`))}function It(e){return/^-\d+(\.\d+)?$/.test(e)}function Lt(e){if(e.flags.help)return e;if(e.command===`snapshot`&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:`diff`,positionals:[`snapshot`,...e.positionals],flags:n,warnings:e.warnings}}return e}function Rt(e,t){return e?t.length===1?`Flag ${t[0]} is not supported for command ${e}.`:`Flags ${t.join(`, `)} are not supported for command ${e}.`:t.length===1?`Flag ${t[0]} requires a command that supports it.`:`Flags ${t.join(`, `)} require a command that supports them.`}async function M(){let{buildUsageText:e}=await import(`./cli-help.js`);return e()}async function zt(e){let{buildCommandUsageText:t}=await import(`./cli-help.js`);return t(Bt(e))}function Bt(e){if(e.toLowerCase()===`rotate`)throw new t(`INVALID_ARGS`,`rotate was renamed to orientation; for the two-finger gesture use: gesture rotate`);return dt(e)}const Vt={slug:`react-devtools-companion`,runArg:Pe,displayName:`React DevTools companion`};async function Ht(e){return await Ie({...e,definition:Vt,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 Ut(e){return await Fe({...e,definition:Vt})}function Wt(e){let n=e.env??process.env,r=qt(e);if(!k.existsSync(r))throw new t(`INVALID_ARGS`,`Remote config file not found: ${r}`);let i;try{i=k.readFileSync(r,`utf8`)}catch(e){throw new t(`INVALID_ARGS`,`Failed to read remote config file: ${r}`,{cause:e instanceof Error?e.message:String(e)})}let a;try{a=JSON.parse(i)}catch(e){throw new t(`INVALID_ARGS`,`Invalid JSON in remote config file: ${r}`,{cause:e instanceof Error?e.message:String(e)})}if(!a||typeof a!=`object`||Array.isArray(a))throw new t(`INVALID_ARGS`,`Remote config file must contain a JSON object: ${r}`);let o={},s=a,l=A.dirname(r);for(let[e,i]of Object.entries(s)){let a=Xe(e);if(!a)throw new t(`INVALID_ARGS`,`Unsupported remote config key "${e}" in remote config file ${r}.`);let s=c(a,i,`remote config file ${r}`,e);o[a.key]=typeof s==`string`&&`path`in a&&a.path?S(s,{cwd:l,env:n}):s}return{resolvedPath:r,profile:o}}function Gt(e=process.env){let t={};for(let n of Ze){let r=Qe(n.key).map(t=>({name:t,value:e[t]})).find(e=>typeof e.value==`string`&&e.value.trim().length>0);r&&(t[n.key]=c(n,r.value,`environment variable ${r.name}`,r.name))}return t}function Kt(...e){let t={};for(let n of e)if(n)for(let e of Ze){let r=n[e.key];r!==void 0&&(t[e.key]=r)}return t}function qt(e){let t=e.env??process.env;return S(e.configPath,{cwd:e.cwd,env:t})}function N(e){let t=Wt(e);return{resolvedPath:t.resolvedPath,profile:Kt(Gt(e.env),t.profile)}}function Jt(e){return e===`android-instance`||e===`ios-instance`}function Yt(e){return[`exec`,`--yes`,`--package`,`agent-cdp@1.6.1`,`--`,`agent-cdp`,...e]}function Xt(e){return e.some(e=>e===`--url`||e.startsWith(`--url=`))}function Zt(e){return e[0]===`target`&&(e[1]===`list`||e[1]===`select`)&&!Xt(e)}function Qt(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 $t(e){let t=e?.metroPublicBaseUrl?.trim();return t?Qt(t):null}function en(e,n={}){if(!Zt(e)||!n.flags?.metroProxyBaseUrl||!Jt(n.flags.leaseBackend))return e;let r=$t(n.flags);if(!r)throw new t(`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[...e,`--url`,r]}async function tn(e,t={}){return(await l(`npm`,Yt(en(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 P(e){let t=ln(e);if(!k.existsSync(t))return null;let n;try{n=JSON.parse(k.readFileSync(t,`utf8`))}catch(t){return _n(e,t),null}return yn(n)?n:(_n(e),null)}function nn(e){let t=ln({stateDir:e.stateDir,session:e.state.session});k.mkdirSync(A.dirname(t),{recursive:!0}),hn(t,e.state),hn(un(e.stateDir),{session:e.state.session})}function rn(e){return{baseUrl:gn(e.daemonBaseUrl),authToken:e.daemonAuthToken,transport:e.daemonTransport,serverMode:e.daemonServerMode}}function an(e){k.rmSync(ln(e),{force:!0});let t=un(e.stateDir);fn(e.stateDir)===e.session&&k.rmSync(t,{force:!0})}function on(e){let n=e.validateRemoteConfigHash??!0,r=e.remoteConfig?qt({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,i=P(e)??(e.allowActiveFallback?dn({stateDir:e.stateDir}):null);if(!i||r&&i.remoteConfigPath!==r)return null;if(n&&cn(i.remoteConfigPath)!==i.remoteConfigHash)throw new t(`INVALID_ARGS`,`Active remote connection config changed. Run agent-device connect --force to refresh it.`,{remoteConfig:i.remoteConfigPath});let a=mn(i,e),o=ee(i);return{runtime:i.runtime,connection:h(o),flags:{...a,remoteConfig:i.remoteConfigPath,daemonBaseUrl:i.daemon?.baseUrl??a.daemonBaseUrl,daemonAuthToken:i.daemon?.authToken??a.daemonAuthToken,daemonTransport:i.daemon?.transport??a.daemonTransport,daemonServerMode:i.daemon?.serverMode??a.daemonServerMode,...g(o),sessionIsolation:`tenant`,session:i.session,platform:i.platform??a.platform,target:i.target??a.target}}}function sn(e){return h(ee(e))}function cn(e){try{return O.createHash(`sha256`).update(k.readFileSync(e)).digest(`hex`)}catch(n){throw new t(`INVALID_ARGS`,`Remote config file not found: ${e}`,{cause:n instanceof Error?n.message:String(n)})}}function ln(e){return A.join(e.stateDir,`remote-connections`,`${vn(e.session)}.json`)}function un(e){return A.join(e,`remote-connections`,`.active-session.json`)}function dn(e){let t=fn(e.stateDir);return t?P({stateDir:e.stateDir,session:t}):null}function fn(e){let t=un(e);if(k.existsSync(t))try{let e=JSON.parse(k.readFileSync(t,`utf8`));return typeof e.session==`string`?e.session:void 0}catch{return}}function pn(e){if(e)return O.createHash(`sha256`).update(e).digest(`hex`).slice(0,12)}function mn(e,t){try{return N({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(t.validateRemoteConfigHash===!1)return{};throw e}}function hn(e,t){k.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,{encoding:`utf8`,mode:384}),k.chmodSync(e,384)}function gn(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 _n(e,t){u({level:`warn`,phase:`remote_connection_state_invalid`,data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),an(e)}function vn(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`);return t?t===e?t:`${t}-${O.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`:`default`}function yn(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;return t.version===1&&bn(t,[`session`,`remoteConfigPath`,`remoteConfigHash`,`tenant`,`runId`,`connectedAt`,`updatedAt`])&&xn(t,[`leaseId`,`leaseBackend`,`leaseProvider`,`deviceKey`,`clientId`])&&Sn(t.daemon)}function bn(e,t){return t.every(t=>typeof e[t]==`string`)}function xn(e,t){return t.every(t=>e[t]===void 0||typeof e[t]==`string`)}function Sn(e){return e===void 0?!0:!e||typeof e!=`object`||Array.isArray(e)?!1:Cn(e)}function Cn(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 wn=$e.map(e=>e.key);function Tn(e){let t={};for(let n of wn){let r=e[n];r!==void 0&&(t[n]=r)}return t}function En(e){return e.remoteConfig?{...Tn(N({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}).profile),remoteConfig:e.remoteConfig}:{}}function Dn(e){return e===`cloud`||e===`proxy`||F(e)}function F(e){return e===`limrun`||w(e)}function On(e){return w(e)}function kn(){return[`cloud`,`proxy`,C.browserStack,C.awsDeviceFarm,`limrun`].join(`, `)}function An(e){return!F(e)}function jn(e){return e===`proxy`?`proxy`:F(e)?`direct-device-provider`:`remote-provider`}const I=new Set([`artifacts`,`connect`,`connection`,`close`,`disconnect`,`metro`,`session`]),Mn=new Set([`open`]),Nn=new Set([_.open,_.install,_.reinstall,oe.installSource]);async function Pn(e){let{command:n,flags:r,client:i}=e;if(!r.remoteConfig)return{flags:r,runtime:e.runtime};let a=x(r.stateDir).baseDir,o=N({configPath:r.remoteConfig,cwd:process.cwd(),env:process.env}),s={...Tn(o.profile),...r,remoteConfig:o.resolvedPath},c=P({stateDir:a,session:s.session??`default`});if(c&&c.remoteConfigPath!==o.resolvedPath)throw new t(`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 l=c??rr(s,o.resolvedPath,o.profile),u={...s,session:l.session},d=nr(l.runtime,u.platform)??e.runtime,f=l,p=!c,m,h=Hn(f);if(h.shouldAllocate(n)){let e=await zn({command:n,client:i,state:l,nextState:f,nextFlags:u,policy:h});f=e.state,p||=e.changed,m=e.acquiredLeaseForCleanup}let g=await Fn({command:n,flags:u,client:i,state:l,nextState:f,runtime:d,positionals:e.positionals,batchSteps:e.batchSteps,forceRuntimePrepare:e.forceRuntimePrepare});return f=g.state,d=g.runtime,p||=g.changed,await Rn({changed:p,stateDir:a,state:f,client:i,acquiredLeaseForCleanup:m,preparedMetroCleanupOnFailure:g.preparedMetroCleanupOnFailure,metroCleanupToStop:g.metroCleanupToStop}),{flags:{...u,session:f.session,leaseId:f.leaseId,leaseBackend:f.leaseBackend,platform:f.platform??u.platform,target:f.target??u.target},runtime:d,connection:sn(f)}}async function Fn(e){let{command:n,flags:r,state:i,client:a}=e,o=In(e.nextState,r),s=e.runtime;if(!Qn(n,r,e.batchSteps,e.positionals)||!$n(r)||!Ln(e.forceRuntimePrepare,s,r.platform))return{state:o,runtime:s,changed:!1};if(!o.leaseId)throw new t(`INVALID_ARGS`,`${n} requires a resolved remote lease before Metro runtime can be prepared.`);let c=await Kn(r,a,i.remoteConfigPath,i.session,{tenantId:i.tenant,runId:i.runId,leaseId:o.leaseId}),l=!tr(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?e.nextState.metro:void 0,preparedMetroCleanupOnFailure:l?c.cleanup:void 0}}function In(e,t){return e.leaseId||!t.leaseId?e:{...e,leaseId:t.leaseId,leaseBackend:t.leaseBackend}}function Ln(e,t,n){return e===!0||!t||!er(t,n)}async function Rn(e){if(e.changed)try{nn({stateDir:e.stateDir,state:e.state})}catch(t){throw await L(e.preparedMetroCleanupOnFailure),await Xn(e.client,e.state,e.acquiredLeaseForCleanup),t}await L(e.metroCleanupToStop)}async function zn(e){let{command:t,client:n,state:r,nextFlags:i,policy:a}=e,o=r.leaseBackend??R(i),s=e.nextState,c=await a.resolveLeaseState({command:t,client:n,state:s,flags:i,leaseBackend:o});s=c.state,c.device&&or(i,c.device);let l=s.leaseBackend??o??Zn(i,t);ur(r,i,l);let u=await ir(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,Bn(s,d,l)?{state:s,changed:!1,acquiredLeaseForCleanup:u.acquired?d:void 0}:{state:Vn(s,d,l,i),changed:!0,acquiredLeaseForCleanup:u.acquired?d:void 0}}function Bn(e,t,n){return e.leaseId===t.leaseId&&e.leaseBackend===n&&e.deviceKey===(t.deviceKey??e.deviceKey)}function Vn(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 Hn(e){return e.leaseProvider===`proxy`?Wn:w(e.leaseProvider)?Gn:Un}const Un={shouldAllocate:e=>!I.has(e),ttlMs:()=>void 0,resolveLeaseState:async e=>({state:e.state})},Wn={shouldAllocate:e=>e!==`devices`&&!I.has(e),ttlMs:()=>3e5,resolveLeaseState:ar},Gn={shouldAllocate:e=>!I.has(e),ttlMs:()=>6e5,resolveLeaseState:async e=>({state:e.state})};async function Kn(e,n,r,i,a){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if(e.platform!==`ios`&&e.platform!==`android`)throw new t(`INVALID_ARGS`,`Deferred Metro preparation requires platform "ios" or "android".`);if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new t(`INVALID_ARGS`,`Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.`);let o=await n.metro.prepare({projectRoot:e.metroProjectRoot,kind:Me(e.metroKind),publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:a,launchUrl:e.launchUrl,companionProfileKey:r,companionConsumerKey:i,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:e.metroNoReuseExisting?!1:void 0,installDependenciesIfNeeded:e.metroNoInstallDeps?!1:void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:e.platform===`ios`?o.iosRuntime:o.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:o.projectRoot,profileKey:r,consumerKey:i}:void 0}}async function L(e){if(e)try{await Re(e)}catch{}}async function qn(e){try{await Ut({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function Jn(e,t){return t.leaseId?await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,daemonBaseUrl:t.daemon?.baseUrl,daemonAuthToken:t.daemon?.authToken,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode,leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey}):{released:!1}}async function Yn(e,t){if(t.leaseId)try{await Jn(e,t)}catch{}}async function Xn(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 R(e){if(e.leaseBackend)return e.leaseBackend;if(e.platform===`android`)return`android-instance`;if(e.platform===`ios`)return`ios-instance`}function Zn(e,n){let r=R(e);if(r)return r;throw new t(`INVALID_ARGS`,`${n} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}function Qn(e,t,n,r=[]){return e===`cdp`?Zt(r)&&!!t.metroPublicBaseUrl:Mn.has(e)?!0:e!==`batch`||!n?!1:n.some(e=>{let t=e.command.trim().toLowerCase();return Mn.has(t)&&e.runtime===void 0})}function $n(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function er(e,t){return!e.platform||!t||t!==`ios`&&t!==`android`?!0:e.platform===t}function tr(e,t){return e?.projectRoot===t?.projectRoot&&e?.profileKey===t?.profileKey&&e?.consumerKey===t?.consumerKey}function nr(e,t){if(e)return er(e,t)?e:void 0}function rr(e,n,r={}){if(!e.tenant)throw new t(`INVALID_ARGS`,`remote command requires tenant in remote config or via --tenant <id>.`);if(!e.runId)throw new t(`INVALID_ARGS`,`remote command requires runId in remote config or via --run-id <id>.`);if(!e.daemonBaseUrl&&An(r.leaseProvider))throw new t(`INVALID_ARGS`,`remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);let i=new Date().toISOString();return{version:1,session:e.session??`default`,remoteConfigPath:n,remoteConfigHash:cn(n),daemon:rn(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??R(e),leaseProvider:r.leaseProvider,clientId:r.clientId,deviceKey:r.deviceKey,platform:e.platform,target:e.target,connectedAt:i,updatedAt:i}}async function ir(e,t,n,r,i){if(t.leaseId&&t.leaseBackend===n){let i=await dr(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,awsProjectArn:i.awsProjectArn,awsDeviceArn:i.awsDeviceArn,awsAppArn:i.awsAppArn,awsRegion:i.awsRegion,awsInteractionMode:i.awsInteractionMode}),acquired:!0}}async function ar(e){if(!Nn.has(e.command)){if(e.state.leaseId&&e.state.deviceKey)return{state:e.state};throw new t(`INVALID_ARGS`,`No active proxy device lease for this session; run open first.`)}let n=await sr(e.client,e.flags),r=cr(n);return{state:{...e.state,deviceKey:r,leaseBackend:e.state.leaseBackend??e.leaseBackend??lr(n),platform:e.state.platform??n.platform,target:e.state.target??n.target,updatedAt:new Date().toISOString()},device:n}}function or(e,t){if(e.platform=t.platform,e.target=t.target??e.target,Ee(t)){e.udid=t.id;return}t.platform===`android`&&(e.serial=t.id)}async function sr(e,t){return await De((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=>({...Te(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 cr(e){return`${we(e)}:${e.target??`mobile`}:${e.id}`}function lr(e){if(Ee(e))return`ios-instance`;if(e.platform===`android`)return`android-instance`}function ur(e,n,r){if(e.leaseBackend&&e.leaseBackend!==r)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.`,{session:e.session,leaseBackend:e.leaseBackend});if(e.platform&&n.platform&&e.platform!==n.platform)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different platform. Re-run connect --force to replace it.`,{session:e.session,platform:e.platform});if(e.target&&n.target&&e.target!==n.target)throw new t(`INVALID_ARGS`,`Active remote connection is already bound to a different target. Re-run connect --force to replace it.`,{session:e.session,target:e.target})}async function dr(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(fr(e))return;throw e}}function fr(e){return!(e instanceof t)||e.code!==`UNAUTHORIZED`?!1:e.details?.reason===`LEASE_NOT_FOUND`||e.details?.reason===`LEASE_EXPIRED`||e.details?.reason===`LEASE_REVOKED`}function pr(e){return Le(e)}async function mr(e,n){let r=await e.text(),i={};if(r.trim().length>0)try{i=JSON.parse(r)}catch(r){throw new t(`COMMAND_FAILED`,n.invalidJsonMessage,{status:e.status},r instanceof Error?r:void 0)}if(!e.ok)throw new t(`UNAUTHORIZED`,n.rejectedMessage,{status:e.status,response:i});return i}const hr=1e3;async function gr(e){return await _r({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:e.command===`connect`&&!e.flags.noLogin,env:e.env})}async function _r(e){let n=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:`none`};if(W(e.flags.daemonAuthToken))return{flags:e.flags,source:`flag`};if(W(n.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{flags:e.flags,source:`env`};if(!jr(e.flags.daemonBaseUrl,n))return{flags:e.flags,source:`none`};let r=await Cr({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});if(r)return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:`cli-session`};if(!e.allowInteractiveLogin)throw e.flags.noLogin?new t(`UNAUTHORIZED`,`Remote daemon authentication is required.`,{hint:`Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`}):Ar(e.command,n);let i=await z({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});return{flags:{...e.flags,daemonAuthToken:i.accessToken},source:`login`}}async function vr(e){let n=e.env??e.io?.env??process.env;if(W(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:H(n)};if(W(n.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:n.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:H(n)};let r=await Cr({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io});if(r)return{accessToken:r.accessToken,cloudBaseUrl:r.cloudBaseUrl};if(e.flags.noLogin)throw new t(`UNAUTHORIZED`,`Cloud connection profile authentication is required.`,{hint:`Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`});let i=await z({stateDir:e.stateDir,flags:e.flags,env:n,io:e.io,commandLabel:`agent-device connect`});return{accessToken:i.accessToken,cloudBaseUrl:i.session.cloudBaseUrl}}async function z(e){let n=e.env??e.io?.env??process.env,r=Dr(n,e.io);if(r===`non-interactive`)throw Ar(e.commandLabel??`agent-device connect`,n);let i=H(n),a=await V({baseUrl:i,pathName:`/api/control-plane/device-auth/start`,body:{client:`agent-device`,tenant:e.flags.tenant,runId:e.flags.runId,daemonBaseUrl:e.flags.daemonBaseUrl,session:e.flags.session},fetchImpl:e.io?.fetch});Er(a);let o=a.verificationUriComplete??a.verificationUri,s=r===`local-browser`?a.verificationUri:Mr(a.verificationUri,a.userCode);r===`local-browser`?(U(e.io,`Opening ${a.verificationUri}...\n`),await Nr(o,e.io)):U(e.io,`Open this URL on your machine:\n${s}\n\nWaiting for approval for 10 minutes...\n`);let c=await Tr({cloudBaseUrl:i,deviceCode:a.deviceCode,expiresIn:a.expiresIn,interval:a.interval,fetchImpl:e.io?.fetch,now:e.io?.now}),l=c.cliSession?.refreshCredential??c.cliSession?.refreshToken;if(!W(c.accessToken)||!W(l))throw new t(`UNAUTHORIZED`,`Device authorization did not return CLI credentials.`);let u=new Date(e.io?.now?.()??Date.now()).toISOString(),d={version:1,id:c.cliSession?.id??`cli-${Date.now().toString(36)}`,cloudBaseUrl:i,workspaceId:c.cliSession?.workspaceId,accountId:c.cliSession?.accountId,name:c.cliSession?.name,refreshCredential:l,createdAt:u,expiresAt:c.cliSession?.expiresAt};return br({stateDir:e.stateDir,session:d}),{accessToken:c.accessToken,expiresAt:c.expiresAt,session:d}}function yr(e){let t=B(e.stateDir);if(!k.existsSync(t))return null;try{let e=JSON.parse(k.readFileSync(t,`utf8`));return e.version!==1||!W(e.id)||!W(e.cloudBaseUrl)||!W(e.refreshCredential)||!W(e.createdAt)?null:e}catch{return null}}function br(e){let t=B(e.stateDir);k.mkdirSync(A.dirname(t),{recursive:!0,mode:448}),k.writeFileSync(t,`${JSON.stringify(e.session,null,2)}\n`,{mode:384});try{k.chmodSync(t,384)}catch{}}function xr(e){let t=B(e.stateDir);return k.existsSync(t)?(k.rmSync(t,{force:!0}),!0):!1}function B(e){return A.join(e,`auth`,`cli-session.json`)}function Sr(e){let t=yr({stateDir:e.stateDir});return t?{authenticated:!0,source:`cli-session`,sessionId:t.id,cloudBaseUrl:t.cloudBaseUrl,workspaceId:t.workspaceId,accountId:t.accountId,name:t.name,createdAt:t.createdAt,expiresAt:t.expiresAt,expired:Pr(t.expiresAt,e.now)}:{authenticated:!1,source:`none`}}async function Cr(e){let t=yr({stateDir:e.stateDir});return!t||Pr(t.expiresAt,e.io?.now)?null:{accessToken:(await wr({session:t,flags:e.flags,env:e.env,io:e.io})).accessToken,cloudBaseUrl:H(e.env,t.cloudBaseUrl)}}async function wr(e){let n=await V({baseUrl:H(e.env,e.session.cloudBaseUrl),pathName:`/api/control-plane/cli-session/refresh`,body:{refreshCredential:e.session.refreshCredential,tenant:e.flags.tenant,runId:e.flags.runId,daemonBaseUrl:e.flags.daemonBaseUrl,session:e.flags.session},fetchImpl:e.io?.fetch});if(W(n.accessToken))return{accessToken:n.accessToken,expiresAt:n.expiresAt};throw n.status===`revoked`||n.error===`revoked`?new t(`UNAUTHORIZED`,`Stored cloud CLI session was revoked.`,{hint:`Run agent-device auth login again, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`,status:n.status,error:n.error}):new t(`UNAUTHORIZED`,`Failed to refresh CLI session.`,{hint:`Run agent-device auth login again, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.`,status:n.status,error:n.error})}async function Tr(e){let n=e.now??Date.now,r=Math.min((e.expiresIn??600)*1e3,6e5),i=n()+r,a=Math.max(hr,(e.interval??5e3/1e3)*1e3);for(;n()<i;){let n=await V({baseUrl:e.cloudBaseUrl,pathName:`/api/control-plane/device-auth/poll`,body:{deviceCode:e.deviceCode},fetchImpl:e.fetchImpl});if(n.status===`approved`||W(n.accessToken))return n;if(n.status===`slow_down`||n.error===`slow_down`)a+=hr;else if(n.status!==`authorization_pending`&&n.error!==`authorization_pending`)throw new t(`UNAUTHORIZED`,`Device authorization was not approved.`,{status:n.status,error:n.error});await Fr(a)}throw new t(`TIMEOUT`,`Device authorization expired before approval.`)}async function V(e){let t=await(e.fetchImpl??fetch)(new URL(e.pathName,e.baseUrl),{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e.body),signal:AbortSignal.timeout(15e3)});return await mr(t,{invalidJsonMessage:`Cloud auth endpoint returned invalid JSON (${t.status}).`,rejectedMessage:`Cloud auth endpoint rejected the request.`})}function Er(e){if(!W(e.deviceCode)||!W(e.userCode)||!W(e.verificationUri))throw new t(`COMMAND_FAILED`,`Cloud auth start returned an unusable response.`)}function Dr(e,t){let n=t?.stdinIsTTY??process.stdin.isTTY,r=t?.stdoutIsTTY??process.stdout.isTTY;return Or(e)||!n||!r?`non-interactive`:kr(e)?`device-code`:`local-browser`}function Or(e){return e.CI===`true`||e.GITHUB_ACTIONS===`true`||e.BUILDKITE===`true`}function kr(e){return!!(e.SSH_TTY||e.SSH_CONNECTION||e.CODESPACES===`true`||e.GITPOD_WORKSPACE_ID||e.REMOTE_CONTAINERS===`true`)}function Ar(e,n){let r=H(n);return new t(`UNAUTHORIZED`,`${e} cannot perform interactive login in CI or a non-interactive shell.`,{hint:`Create a service/API token: ${new URL(`/api-keys`,r).toString()} Then set AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_...`})}function H(e,n){let r=e.AGENT_DEVICE_CLOUD_BASE_URL??n??`https://cloud.agent-device.dev`;try{return new URL(r).toString().replace(/\/+$/,``)}catch(e){throw new t(`INVALID_ARGS`,`Invalid AGENT_DEVICE_CLOUD_BASE_URL.`,{cloudBaseUrl:r},e instanceof Error?e:void 0)}}function jr(e,t){if(t.AGENT_DEVICE_CLOUD_AUTH===`1`||t.AGENT_DEVICE_CLOUD_AUTH===`true`||W(t.AGENT_DEVICE_CLOUD_BASE_URL))return!0;try{let t=new URL(e).hostname.toLowerCase();return t===`agent-device.dev`||t.endsWith(`.agent-device.dev`)}catch{return!1}}function Mr(e,t){let n=new URL(e);return n.searchParams.set(`user_code`,t),n.toString()}async function Nr(e,t){if(t?.openBrowser){await t.openBrowser(e);return}let n=process.platform;try{n===`darwin`?await d(`open`,[e],{allowFailure:!0,timeoutMs:5e3}):n===`win32`?await d(`cmd`,[`/c`,`start`,``,e],{allowFailure:!0,timeoutMs:5e3}):await d(`xdg-open`,[e],{allowFailure:!0,timeoutMs:5e3})}catch{U(t,`Open this URL on your machine:\n${e}\n`)}}function U(e,t){(e?.stderr??process.stderr).write(t)}function Pr(e,t){if(!e)return!1;let n=Date.parse(e);return Number.isFinite(n)?n<=(t?.()??Date.now()):!0}function W(e){return typeof e==`string`&&e.trim().length>0}async function Fr(e){await new Promise(t=>setTimeout(t,e))}const Ir=new Set([`daemonAuthToken`,`metroBearerToken`]);function Lr(e){let t=K(zr(e.profile)),n=A.join(e.stateDir,`remote-connections`,`generated`);k.mkdirSync(n,{recursive:!0,mode:448});let r=A.join(n,`${Vr(e.provider)}-${Br(t)}.json`);k.writeFileSync(r,`${JSON.stringify(t,null,2)}\n`,{mode:384});try{k.chmodSync(r,384)}catch{}return r}function Rr(e){try{return N(e)}catch(n){let i=r(n);throw new t(`COMMAND_FAILED`,`${e.provider} connection profile returned invalid remote config.`,{generatedConfigPath:e.configPath,cause:i.message},i)}}function G(e){let t=Rr({configPath:Lr({stateDir:e.stateDir,provider:e.provider,profile:e.profile}),cwd:e.cwd,env:e.env,provider:Hr(e.provider)});return{flags:{...Tn(t.profile),...e.flags,...e.extraFlags??{},remoteConfig:t.resolvedPath},remoteConfigPath:t.resolvedPath}}function zr(e){return Object.fromEntries(Object.entries(e).filter(([e])=>!Ir.has(e)))}function Br(e){return O.createHash(`sha256`).update(JSON.stringify(e)).digest(`hex`).slice(0,16)}function K(e){return Array.isArray(e)?e.map(K):e&&typeof e==`object`?Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,K(t)])):e}function Vr(e){return e.replaceAll(/[^a-zA-Z0-9._-]/g,`_`)||`generated`}function Hr(e){let[t=``,...n]=e;return`${t.toUpperCase()}${n.join(``)}`}function q(...e){return O.createHash(`sha256`).update(e.map(e=>e??``).join(`\0`)).digest(`hex`).slice(0,16)}async function Ur(e){let t=await vr({stateDir:e.stateDir,flags:e.flags,env:e.env,io:{env:e.env,fetch:e.fetchImpl}}),n=await Wr({cloudBaseUrl:t.cloudBaseUrl,accessToken:t.accessToken,fetchImpl:e.fetchImpl}),r=q(e.stateDir,t.cloudBaseUrl,typeof n.daemonBaseUrl==`string`?n.daemonBaseUrl:``,e.flags.session);return G({stateDir:e.stateDir,provider:`cloud`,profile:{...n,leaseProvider:n.leaseProvider??`cloud`,clientId:n.clientId??r,runId:n.runId??`cloud-${r}`},cwd:e.cwd,env:e.env,flags:e.flags,extraFlags:{daemonAuthToken:t.accessToken}})}async function Wr(e){let t=await(e.fetchImpl??fetch)(new URL(`/api/control-plane/connection-profile`,e.cloudBaseUrl),{method:`GET`,headers:{authorization:`Bearer ${e.accessToken}`},signal:AbortSignal.timeout(15e3)});return Gr(await mr(t,{invalidJsonMessage:`Cloud connection profile endpoint returned invalid JSON (${t.status}).`,rejectedMessage:`Cloud connection profile endpoint rejected the request.`}))}function Gr(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new t(`COMMAND_FAILED`,`Cloud connection profile response is invalid.`);let n=e.connection;if(!n||typeof n!=`object`)throw new t(`COMMAND_FAILED`,`Cloud connection profile response is missing profile.`);if(n.remoteConfigProfile!==void 0)return Kr(n.remoteConfigProfile);throw new t(`COMMAND_FAILED`,`Cloud connection profile did not include remoteConfigProfile.`)}function Kr(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new t(`COMMAND_FAILED`,`Cloud connection profile remoteConfigProfile is invalid.`);if(Object.keys(e).length===0)throw new t(`COMMAND_FAILED`,`Cloud connection profile remoteConfigProfile is empty.`);return e}function qr(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}}function Jr(e){let t=Xr(e.provider)(e),n=q(e.provider,e.stateDir,e.flags.session,t.device),r={tenant:e.flags.tenant??e.provider,sessionIsolation:e.flags.sessionIsolation??`tenant`,runId:e.flags.runId??`${e.provider}-${n}`,leaseProvider:e.provider,clientId:n,leaseBackend:e.flags.leaseBackend??R(e.flags),target:e.flags.target??`mobile`,session:e.flags.session,...t,...qr(e.flags)};return G({stateDir:e.stateDir,provider:e.provider,profile:r,cwd:e.cwd,env:e.env,flags:e.flags})}const Yr=[{provider:C.browserStack,buildProfileFields:Zr},{provider:C.awsDeviceFarm,buildProfileFields:Qr}];function Xr(e){let n=Yr.find(t=>t.provider===e)?.buildProfileFields;if(n)return n;throw new t(`INVALID_ARGS`,`Unsupported cloud WebDriver provider "${e}".`)}function Zr(e){return ei(e.env,`BROWSERSTACK_USERNAME`,`connect browserstack`),ei(e.env,`BROWSERSTACK_ACCESS_KEY`,`connect browserstack`),{platform:$r(e.flags.platform,`connect browserstack requires --platform ios|android.`),device:J(e.flags.device,`connect browserstack requires --device <name>.`),providerOsVersion:J(e.flags.providerOsVersion,`connect browserstack requires --provider-os-version <version>.`),providerApp:J(e.flags.providerApp,`connect browserstack requires --provider-app <bs://app-id-or-local-path>.`),providerProject:e.flags.providerProject,providerBuild:e.flags.providerBuild,providerSessionName:e.flags.providerSessionName}}function Qr(e){let{env:t,flags:n}=e;return{platform:$r(n.platform,`connect aws-device-farm requires --platform ios|android.`),device:n.device,awsProjectArn:ti(n.awsProjectArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_PROJECT_ARN`,`AWS_DEVICE_FARM_PROJECT_ARN`],`connect aws-device-farm requires --aws-project-arn <arn> or AWS_DEVICE_FARM_PROJECT_ARN.`),awsDeviceArn:ti(n.awsDeviceArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_DEVICE_ARN`,`AWS_DEVICE_FARM_DEVICE_ARN`],`connect aws-device-farm requires --aws-device-arn <arn> or AWS_DEVICE_FARM_DEVICE_ARN.`),awsAppArn:ni(n.awsAppArn,t,[`AGENT_DEVICE_AWS_DEVICE_FARM_APP_ARN`,`AWS_DEVICE_FARM_APP_ARN`]),awsRegion:ni(n.awsRegion,t,[`AWS_REGION`,`AWS_DEFAULT_REGION`]),awsInteractionMode:n.awsInteractionMode,providerSessionName:n.providerSessionName}}function $r(e,n){if(e===`android`||e===`ios`)return e;throw new t(`INVALID_ARGS`,n)}function J(e,n){if(e)return e;throw new t(`INVALID_ARGS`,n)}function ei(e,n,r){let i=e?.[n];if(i)return i;throw new t(`INVALID_ARGS`,`${r} requires ${n} in the environment.`)}function ti(e,t,n,r){return J(ni(e,t,n),r)}function ni(e,t,n){return e||n.map(e=>t?.[e]).find(e=>!!e)}function ri(e){let n=e.env??process.env;if(!n.LIMRUN_API_KEY?.trim())throw new t(`INVALID_ARGS`,`connect limrun requires LIMRUN_API_KEY.`,{hint:`Set LIMRUN_API_KEY in the environment before running agent-device connect limrun.`});let r=ii({flags:e.flags});return G({stateDir:e.stateDir,provider:`limrun`,profile:r,cwd:e.cwd,env:n,flags:e.flags})}function ii(e){let t=e.flags,n=ai(t);return{stateDir:x(t.stateDir).baseDir,daemonTransport:`auto`,tenant:t.tenant??`limrun`,runId:t.runId??`cli-${Date.now().toString(36)}`,sessionIsolation:`tenant`,leaseBackend:n,leaseProvider:`limrun`,platform:t.platform,target:`mobile`,session:t.session,...qr(t)}}function ai(e){if(e.platform!==`android`&&e.platform!==`ios`)throw new t(`INVALID_ARGS`,`connect limrun requires --platform ios or android.`);if(e.device!==void 0)throw new t(`INVALID_ARGS`,`connect limrun does not accept --device; Limrun selects a remote simulator or emulator.`);let n=R(e),r=e.platform===`ios`?`ios-instance`:`android-instance`;if(n!==r)throw new t(`INVALID_ARGS`,`connect limrun --platform ${e.platform} requires --lease-backend ${r}.`);return r}function oi(e){let n=e.flags.daemonBaseUrl??e.env?.AGENT_DEVICE_DAEMON_BASE_URL;if(!n)throw new t(`INVALID_ARGS`,`connect proxy requires --daemon-base-url <url> or AGENT_DEVICE_DAEMON_BASE_URL.`);let r=q(e.stateDir,n,e.flags.session),i={daemonBaseUrl:n,daemonTransport:e.flags.daemonTransport??`http`,daemonServerMode:e.flags.daemonServerMode,tenant:e.flags.tenant??`proxy`,sessionIsolation:e.flags.sessionIsolation??`tenant`,runId:e.flags.runId??`proxy-${r}`,leaseProvider:`proxy`,clientId:r,leaseBackend:e.flags.leaseBackend??R(e.flags),platform:e.flags.platform,target:e.flags.target,device:e.flags.device,udid:e.flags.udid,serial:e.flags.serial,iosSimulatorDeviceSet:e.flags.iosSimulatorDeviceSet,androidDeviceAllowlist:e.flags.androidDeviceAllowlist,session:e.flags.session,...qr(e.flags)};return G({stateDir:e.stateDir,provider:`proxy`,profile:i,cwd:e.cwd,env:e.env,flags:e.flags,extraFlags:{daemonBaseUrl:n,daemonTransport:e.flags.daemonTransport??`http`}})}const si=async({positionals:e,flags:t,client:n})=>{let r=x(t.stateDir).baseDir,i=Di(e);li(i,t);let a=await ci({provider:i,flags:t,stateDir:r}),o=a.flags,s=yi(a.remoteConfigPath),c=ui(o,s),l=di({stateDir:r,flags:o,remoteConfigPath:a.remoteConfigPath});fi(l.previous,{flags:o,session:l.session,remoteConfigPath:a.remoteConfigPath,remoteConfigHash:l.remoteConfigHash,desiredLeaseBackend:R(o),connection:s,daemon:l.daemon});let u=pi({flags:o,scope:c,connectionMetadata:s,context:l,remoteConfigPath:a.remoteConfigPath});nn({stateDir:r,state:u}),await _i(n,r,o,l.previous);let d=zi(u),f=Li(o,u);return D(o,Hi(u,f),()=>[`Connected remote session "${l.session}" tenant "${c.tenant}" run "${c.runId}" ${u.leaseId?`lease ${u.leaseId}`:`lease pending`}`,d?.message,f?.message].filter(e=>!!e).join(`
|
|
2
|
+
`)),!0};async function ci(e){let{provider:t,flags:n,stateDir:r}=e;return n.remoteConfig?vi(n):On(t)?Jr({provider:t,flags:n,stateDir:r,cwd:process.cwd(),env:process.env}):t===`proxy`||!t&&Oi(n)?oi({flags:n,stateDir:r,cwd:process.cwd(),env:process.env}):t===`limrun`?ri({flags:n,stateDir:r,cwd:process.cwd(),env:process.env}):await Ur({flags:n,stateDir:r,cwd:process.cwd(),env:process.env})}function li(e,n){if(!(!e||!n.remoteConfig))throw new t(`INVALID_ARGS`,`connect provider positional and --remote-config are mutually exclusive.`)}function ui(e,n){if(!e.tenant)throw new t(`INVALID_ARGS`,`connect requires tenant in remote config or via --tenant <id>.`);if(!e.runId)throw new t(`INVALID_ARGS`,`connect requires runId in remote config or via --run-id <id>.`);if(!e.daemonBaseUrl&&An(n?.leaseProvider))throw new t(`INVALID_ARGS`,`connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.`);return{tenant:e.tenant,runId:e.runId}}function di(e){let{stateDir:t,flags:n,remoteConfigPath:r}=e,i=n.session?null:dn({stateDir:t}),a=n.session??i?.session??Si(t);return{session:a,previous:i?.session===a?i:P({stateDir:t,session:a}),remoteConfigHash:cn(r),daemon:Ii(n)}}function fi(e,n){if(!(!e||Mi(e,n))&&!n.flags.force)throw new t(`INVALID_ARGS`,`A different remote connection is already active for this session. Re-run connect with --force to replace it.`,{session:n.session,remoteConfig:e.remoteConfigPath})}function pi(e){let{flags:t,scope:n,connectionMetadata:r,context:i,remoteConfigPath:a}=e,o=gi(t,i.previous)?i.previous:null,s=new Date().toISOString(),c=mi(t,o,r),l=hi(t,o,s);return{version:1,session:i.session,remoteConfigPath:a,remoteConfigHash:i.remoteConfigHash,daemon:i.daemon,tenant:n.tenant,runId:n.runId,...c,...l,updatedAt:s}}function mi(e,t,n){return{leaseId:t?.leaseId,leaseBackend:t?.leaseBackend??R(e),leaseProvider:n?.leaseProvider??t?.leaseProvider,clientId:n?.clientId??t?.clientId,deviceKey:t?.deviceKey??n?.deviceKey}}function hi(e,t,n){return{platform:e.platform??t?.platform,target:e.target??t?.target,runtime:t?.runtime,metro:t?.metro,connectedAt:t?.connectedAt??n}}function gi(e,t){return!!(t&&!e.force)}async function _i(e,t,n,r){!r||!n.force||(await L(r.metro),await qn({stateDir:t,state:r}),await Yn(e,r))}function vi(e){if(!e.remoteConfig)throw new t(`INVALID_ARGS`,`connect requires --remote-config <path>.`);return{flags:e,remoteConfigPath:N({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env}).resolvedPath}}function yi(e){let t=N({configPath:e,cwd:process.cwd(),env:process.env}).profile,n={leaseProvider:t.leaseProvider,clientId:t.clientId,deviceKey:t.deviceKey};return Object.values(n).some(e=>e!==void 0)?n:void 0}const bi=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:i}=Ai(e);if(!i)return ji(e,n),!0;let a=i.session,o;try{o=(await t.sessions.close({session:a,shutdown:e.shutdown})).provider}catch{}await L(i.metro),await qn({stateDir:r,state:i});let s=!1;if(i.leaseId)try{let e=await Jn(t,i);s=e.released,o??=e.provider}catch{}return an({stateDir:r,session:a}),D(e,{connected:!1,session:a,released:s,...o?{provider:o}:{}},()=>Ci(a,o)),!0},xi=async({positionals:e,flags:n})=>{if(e[0]!==`status`)throw new t(`INVALID_ARGS`,`connection accepts only: status`);let{session:r,state:i}=Ai(n);if(!i)return ji(n,r),!0;let a=zi(i),o=Ri(i);return D(n,Hi(i,o),()=>[`Connected remote session "${i.session}".`,`tenant=${i.tenant} runId=${i.runId} leaseId=${i.leaseId??`pending`} backend=${i.leaseBackend??`pending`}`,`remoteConfig=${i.remoteConfigPath}`,i.runtime?`metro=prepared`:`metro=not-prepared`,a?.message,o?.message].filter(e=>!!e).join(`
|
|
3
|
+
`)),!0};function Si(e){for(let t=0;t<8;t+=1){let t=`adc-${O.randomBytes(3).toString(`hex`)}`;if(!P({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${O.randomBytes(2).toString(`hex`)}`}function Ci(e,t){return[`Disconnected remote session "${e}".`,...wi(t),...Ei(t?.cloudArtifacts?.cloudArtifacts)].join(`
|
|
4
|
+
`)}function wi(e){return(Array.isArray(e?.warnings)?e.warnings:[]).flatMap(e=>{let t=Ti(e);return t?[t]:[]})}function Ti(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.message!=`string`||t.message.length===0))return`Provider release warning${typeof t.code==`string`&&t.code.length>0?` (${t.code})`:``}: ${t.message}`}function Ei(e){return(e??[]).filter(e=>(e.availability??`ready`)===`ready`&&e.url).slice(0,3).map(e=>`${e.name}: ${e.url}`)}function Di(e){let n=e[0];if(n!==void 0){if(e.length>1)throw new t(`INVALID_ARGS`,`connect accepts at most one provider positional.`);if(Dn(n))return n;throw new t(`INVALID_ARGS`,`Unknown connect provider: ${n}. Supported providers: ${kn()}.`)}}function Oi(e){return!e.daemonBaseUrl||e.tenant||e.runId||e.leaseId||e.leaseBackend?!1:ki(e.daemonBaseUrl)}function ki(e){try{return new URL(e).pathname.replace(/\/+$/,``).endsWith(`/agent-device`)}catch{return!1}}function Ai(e){let t=e.session??`default`,n=x(e.stateDir).baseDir;return{session:t,stateDir:n,state:P({stateDir:n,session:t})??(e.session?null:dn({stateDir:n}))}}function ji(e,t){D(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function Mi(e,t){return Ni(e,t)&&Pi(e,t)&&Fi(e.daemon,t.daemon)}function Ni(e,t){return[[e.remoteConfigPath,t.remoteConfigPath],[e.remoteConfigHash,t.remoteConfigHash],[e.session,t.session],[e.tenant,t.flags.tenant],[e.runId,t.flags.runId]].every(([e,t])=>e===t)}function Pi(e,t){return[[e.leaseBackend,t.desiredLeaseBackend],[e.platform,t.flags.platform],[e.target,t.flags.target],[e.leaseProvider,t.connection?.leaseProvider],[e.clientId,t.connection?.clientId]].every(([e,t])=>t===void 0||e===t)}function Fi(e,t){return[`baseUrl`,`transport`,`serverMode`].every(n=>(e?.[n]??void 0)===(t?.[n]??void 0))}function Ii(e){return rn(e)}function Li(e,t){if(!t.runtime&&!(!$n(e)&&!Vi(t.remoteConfigPath)))return Bi(t.remoteConfigPath)}function Ri(e){if(!(e.runtime||!Vi(e.remoteConfigPath)))return Bi(e.remoteConfigPath)}function zi(e){if(e.leaseId)return;let t=jn(e.leaseProvider);return t===`proxy`?{status:`deferred`,nextSteps:[`agent-device open <app-id> --relaunch`,`agent-device devices`],message:`Proxy lease allocation is pending; run open when ready to allocate or refresh the device lease. Devices can inspect inventory but do not allocate a proxy lease.`}:t===`direct-device-provider`?{status:`deferred`,nextSteps:[`agent-device open <app-id> --relaunch`,`agent-device snapshot -i`,`agent-device artifacts --json`,`agent-device close`],message:`Hosted ${e.leaseProvider} lease allocation is pending; run open when ready to create the provider session. After close, run "agent-device artifacts --json" to fetch provider video/log links when available.`}:{status:`deferred`,nextSteps:[`agent-device install-from-source <artifact-url> --platform ios|android`,`agent-device open <app-id> --relaunch`,`agent-device snapshot -i`,`agent-device devices`],message:`Lease allocation is pending; run install-from-source, open, snapshot, or devices when ready to allocate or refresh the lease.`+(e.platform===void 0&&e.leaseBackend===void 0?` Add --platform ios|android if the profile does not set a platform.`:``)}}function Bi(e){let t=`agent-device metro prepare --remote-config ${e}`;return{status:`deferred`,nextStep:t,message:`Metro runtime is not prepared yet; it will be prepared automatically on first open, or run "${t}" to inspect it before launch.`}}function Vi(e){try{let t=N({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function Hi(e,t){let n=zi(e);return{connected:!0,session:e.session,tenant:e.tenant,runId:e.runId,leaseAllocated:!!e.leaseId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,leaseProvider:e.leaseProvider,platform:e.platform,target:e.target,remoteConfig:e.remoteConfigPath,remoteConfigHash:e.remoteConfigHash,daemonBaseUrlFingerprint:pn(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...n?{leasePreparation:n}:{},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}const Ui=async({positionals:e,flags:n})=>{let r=e[0]??`status`,i=x(n.stateDir).baseDir;if(r===`status`){let e=Sr({stateDir:i});return D(n,e,()=>Wi(e)),!0}if(r===`login`){let e=await z({stateDir:i,flags:n,commandLabel:`agent-device auth login`});return D(n,{authenticated:!0,source:`cli-session`,sessionId:e.session.id,cloudBaseUrl:e.session.cloudBaseUrl,workspaceId:e.session.workspaceId,accountId:e.session.accountId,expiresAt:e.session.expiresAt,agentTokenExpiresAt:e.expiresAt},()=>`Authenticated with cloud CLI session.`),!0}if(r===`logout`){let e=xr({stateDir:i});return D(n,{authenticated:!1,removed:e},()=>e?`Removed stored cloud CLI session.`:`No stored cloud CLI session.`),!0}throw new t(`INVALID_ARGS`,`auth accepts only: status, login, logout`)};function Wi(e){return e.authenticated?[`Authenticated with cloud CLI session.`,`cloud=${e.cloudBaseUrl}`,`session=${e.sessionId}`,e.workspaceId?`workspace=${e.workspaceId}`:null,e.accountId?`account=${e.accountId}`:null,e.expiresAt?`expiresAt=${e.expiresAt}`:null,e.expired?`status=expired`:null].filter(e=>!!e).join(`
|
|
5
|
+
`):`Not authenticated.`}async function Gi(e){let n=Ji(e.paths.infoPath);if(!n)return Y();if(!n.processStartTime){if(!ke(n.pid))return Y();throw new t(`COMMAND_FAILED`,`Refusing to stop a daemon without a verified process start-time identity.`,{pid:n.pid})}if(!de(n.pid,n.processStartTime)){if(!ke(n.pid))return Y();throw new t(`COMMAND_FAILED`,`Refusing to stop a daemon whose PID or start-time identity could not be verified.`,{pid:n.pid,processStartTime:n.processStartTime})}if(!Ki(n.pid,`SIGTERM`))return Y();if(await Ae(n.pid,e.graceTimeoutMs??1e4))return await Xi(e.paths,1e3),{stopped:!0,mode:`graceful`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]};if(de(n.pid,n.processStartTime)&&Ki(n.pid,`SIGKILL`),!await Ae(n.pid,e.killTimeoutMs??2e3))throw new t(`COMMAND_FAILED`,`Daemon did not exit after SIGKILL.`,{pid:n.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 Ki(e,n){if(ge(e,n))return!0;if(!ke(e))return!1;throw new t(`COMMAND_FAILED`,`Daemon could not be signaled with ${n}.`,{pid:e,signal:n})}function qi(e){let t=Ji(e);return t?.processStartTime?{pid:t.pid,processStartTime:t.processStartTime}:null}function Ji(e){try{let t=JSON.parse(k.readFileSync(e,`utf8`)),n=t.pid;return typeof n!=`number`||!Number.isInteger(n)||n<=0?null:{pid:n,...Yi(t.processStartTime)?{processStartTime:t.processStartTime}:{}}}catch{return null}}function Yi(e){return typeof e==`string`&&e.trim().length>0}async function Xi(e,t){let n=Date.now();for(;Date.now()-n<t;){if(!k.existsSync(e.infoPath)&&!k.existsSync(e.lockPath))return;await Oe(25)}}function Y(){return{stopped:!1,mode:`not-running`,cleanupConfidence:`known`,claimsReleased:[],claimsOrphaned:[],providerReleases:{status:`completed`,released:[],pending:[]},warnings:[]}}const Zi=async({positionals:e,flags:n})=>{if(e[0]!==`stop`||e.length!==1)throw new t(`INVALID_ARGS`,`daemon accepts only: stop`);let r=x(n.stateDir),i=qi(r.infoPath),a=await Gi({paths:r}),o=Qi(a,a.mode===`graceful`?Ge(r.baseDir):null),s=n.clean===!0&&i!==null&&o.stopped;if(s){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:i.pid,startTime:i.processStartTime},t)}let c={...o,clean:s};return D(n,c,()=>$i(c)),!0};function Qi(e,t){return e.mode!==`graceful`||t?t?{...e,providerReleases:{status:`completed`,...t.providerReleases}}: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 $i(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(`
|
|
6
|
+
`)}const ea=async({positionals:e,flags:n})=>{if(e[0]!==`status`||e.length!==1)throw new t(`INVALID_ARGS`,`device accepts only: status`);let r=We({platform:n.platform,device:n.device,udid:n.udid,serial:n.serial}),i=r.filter(ta),a=(n.stale?i:r.filter(e=>!ta(e))).map(na);return D(n,{claims:a,...n.stale?{}:{hiddenStaleClaims:i.length}},()=>ra(a,{staleOnly:n.stale===!0,hiddenStaleClaims:i.length,staleCommand:sa(n)})),!0};function ta(e){return e.classification===`owner-process-dead`||e.classification===`owner-state-dir-gone`}function na(e){let t=e.claim;return{...e.deviceKey?{deviceKey:e.deviceKey}:{},...t?{}:{fileName:e.fileName},classification:e.classification,...t?{device:t.device,owner:{session:t.session,workspace:t.workspace,stateDir:t.stateDir,pid:t.ownerPid,startTime:t.ownerStartTime}}:{},...e.error?{error:e.error}:{}}}function ra(e,t){let n=e.map(ia);if(n.length===0){if(t.staleOnly)return`No stale local advisory device claims found.`;if(t.hiddenStaleClaims===0)return`No local advisory device claims found.`}return[...n,!t.staleOnly&&t.hiddenStaleClaims>0?`${t.hiddenStaleClaims} stale ${t.hiddenStaleClaims===1?`claim`:`claims`} hidden; inspect with: ${t.staleCommand}`:null].filter(e=>!!e).join(`
|
|
7
|
+
`)}function ia(e){return`${aa(e)}: ${e.classification}${oa(e.owner)}`}function aa(e){let t=e.device;return t?`${t.platform??`unknown`} ${t.name??t.id??`claim`}`:String(e.deviceKey??e.fileName??`claim`)}function oa(e){if(!e||typeof e!=`object`)return``;let t=e;return` session=${t.session} workspace=${t.workspace}`}function sa(e){return[`agent-device device status`,...[e.platform?`--platform ${b(e.platform)}`:null,e.device?`--device ${b(e.device)}`:null,e.udid?`--udid ${b(e.udid)}`:null,e.serial?`--serial ${b(e.serial)}`:null].filter(e=>!!e),`--stale`].join(` `)}const ca=`${pe}/`,la=[`content-type`,`content-range`,`x-artifact-type`,`x-artifact-filename`,`x-artifact-hash`,`x-artifact-hash-algorithm`,fe],ua=[`content-type`,`content-disposition`,`x-request-id`];function da(e){let t=Ca(e);return at.createServer((e,n)=>{fa(e,n,t).catch(e=>{Ba(n,e)})})}async function fa(e,t,n){let r=Ea(e.url??`/`);if(e.method===`GET`&&r===`/health`){await pa(t,n);return}if(!Da(r,e.method)){t.statusCode=404,t.end(`Not found`);return}let i;if(r===`/rpc`&&(i=(await me(e,n.maxRpcBodyBytes,`Proxy request body is too large.`)).toString(`utf8`)),!Na(e,n.clientToken,i)){za(t,r,La(i));return}await ha({req:e,res:t,route:r,options:n,rpcBody:i})}async function pa(e,t){let n=await ma(t);e.statusCode=200,e.setHeader(`content-type`,`application/json`),e.end(JSON.stringify(ue(`agent-device-proxy`,{upstream:n})))}async function ma(e){let t=new URL(le(e.upstreamBaseUrl,`health`)),n=await e.fetchImpl(t,{method:`GET`,headers:ja({headers:{}},e.upstreamToken,`/health`),signal:AbortSignal.timeout(e.upstreamTimeoutMs)}),r=await n.text();try{return r?JSON.parse(r):{ok:n.ok,status:n.status}}catch{return{ok:n.ok,status:n.status}}}async function ha(e){let{req:t,res:n,route:r,options:i,rpcBody:a}=e,o=Aa(i.upstreamBaseUrl,r,t.url??`/`),s=t.method??`GET`,c=ja(t,i.upstreamToken,r),l=Ma(t,r,a,i.upstreamToken);await ga({req:t,res:n,route:r,response:await i.fetchImpl(o,{method:s,headers:c,signal:AbortSignal.timeout(i.upstreamTimeoutMs),...l?{body:l,duplex:`half`}:{}}),clientToken:i.clientToken})}async function ga(e){let{req:t,res:n,route:r,response:i,clientToken:a}=e;if(n.statusCode=i.status,_a(i,n),va(t,n),ka(r)){await ya({req:t,res:n,response:i,clientToken:a});return}await Sa(i,n)}function _a(e,t){for(let n of ua){let r=e.headers.get(n);r&&t.setHeader(n,r)}}function va(e,t){t.hasHeader(`x-request-id`)||t.setHeader(`x-request-id`,Ra(e))}async function ya(e){let{req:t,res:n,response:r,clientToken:i}=e,a=await r.text();n.setHeader(`content-type`,r.headers.get(`content-type`)??`application/json`),n.end(ba(a,t,i))}function ba(e,t,n){let r;try{r=JSON.parse(e)}catch{return e}if(!r||typeof r!=`object`)return e;let i=r;if(!i.upload||typeof i.upload.url!=`string`)return e;let a=xa(i.upload.url,t);if(!a)return e;let o=i.upload.headers&&typeof i.upload.headers==`object`?{...i.upload.headers}:{};return Object.assign(o,ce(n)),JSON.stringify({...r,upload:{...i.upload,url:a,headers:o}})}function xa(e,t){let n;try{n=new URL(e)}catch{return null}if(!n.pathname.startsWith(`/upload/`))return null;let r=typeof t.headers.host==`string`?t.headers.host:``;if(!r)return null;let i=new URL(t.url??`/`,`http://127.0.0.1`).pathname,a=i.lastIndexOf(`/upload/preflight`),o=a>=0?i.slice(0,a):``,s=t.headers[`x-forwarded-proto`],c=Array.isArray(s)?s[0]:s,l=new URL(`${c||`http`}://${r}`);return l.pathname=`${o}${n.pathname}`,l.search=n.search,l.toString()}async function Sa(e,t){if(!e.body){t.end();return}await ot(st.fromWeb(e.body),t)}function Ca(e){return{upstreamBaseUrl:wa(e.upstreamBaseUrl,`upstreamBaseUrl`),upstreamToken:Ta(e.upstreamToken,`upstreamToken`),clientToken:Ta(e.clientToken,`clientToken`),maxRpcBodyBytes:e.maxRpcBodyBytes??1048576,upstreamTimeoutMs:e.upstreamTimeoutMs??3e5,fetchImpl:e.fetchImpl??fetch}}function wa(e,n){try{let t=new URL(e);if(t.protocol!==`http:`&&t.protocol!==`https:`)throw Error(`unsupported protocol`);return t.toString().replace(/\/+$/,``)}catch(r){throw new t(`INVALID_ARGS`,`Invalid ${n}`,{[n]:e},r)}}function Ta(e,n){let r=e.trim();if(!r)throw new t(`INVALID_ARGS`,`Proxy ${n} is required.`);return r}function Ea(e){let t=new URL(e,`http://127.0.0.1`).pathname;return t===`/agent-device`?`/`:t.startsWith(ca)?`/${t.slice(ca.length)}`:t}function Da(e,t){return e===`/rpc`?t===`POST`:Oa(e,t)?!0:e===`/artifacts`||e===`/artifacts/`||e.startsWith(`/artifacts/`)?t===`GET`:!1}function Oa(e,t){return e===`/upload`||ka(e)||e===`/upload/finalize`?t===`POST`:e.startsWith(`/upload/direct/`)?t===`PUT`:!1}function ka(e){return e===`/upload/preflight`}function Aa(e,t,n){let r=new URL(le(e,t)),i=n.indexOf(`?`);return i>=0&&(r.search=n.slice(i)),r}function ja(e,t,n){let r=new Headers;for(let t of la){let n=e.headers[t];typeof n==`string`&&n.trim()&&r.set(t,n)}n===`/rpc`&&!r.has(`content-type`)&&r.set(`content-type`,`application/json`);for(let[e,n]of Object.entries(ce(t)))r.set(e,n);return r}function Ma(e,t,n,r){if(!(e.method===`GET`||e.method===`HEAD`))return t===`/rpc`?Fa(n??``,r):e}function Na(e,t,n){let r=Pa(e,n);return r.length>0&&Be(r,t)}function Pa(e,t){let n=typeof e.headers.authorization==`string`?e.headers.authorization:``;if(n.toLowerCase().startsWith(`bearer `))return n.slice(7);let r=e.headers[`x-agent-device-token`];if(typeof r==`string`)return r;if(t){let e=Ia(t);if(e)return e}return``}function Fa(e,t){let n=JSON.parse(e);return n.params={...n.params??{},token:t},JSON.stringify(n)}function Ia(e){try{let t=JSON.parse(e);return typeof t.params?.token==`string`?t.params.token:``}catch{return``}}function La(e){if(!e)return null;try{return JSON.parse(e).id??null}catch{return null}}function Ra(e){let t=e.headers[`x-request-id`];return typeof t==`string`&&t.trim()?t.trim().slice(0,128):it()}function za(n,r,i){if(n.statusCode=401,n.setHeader(`content-type`,`application/json`),r===`/rpc`){n.end(JSON.stringify({jsonrpc:`2.0`,id:i,error:{code:-32001,message:`Invalid proxy token`,data:e(new t(`UNAUTHORIZED`,`Invalid proxy token`))}}));return}n.end(JSON.stringify({ok:!1,error:`Invalid proxy token`,code:`UNAUTHORIZED`}))}function Ba(t,n){if(t.headersSent){t.destroy(n instanceof Error?n:void 0);return}let r=e(n);t.statusCode=r.code===`INVALID_ARGS`?400:500,t.setHeader(`content-type`,`application/json`),t.end(JSON.stringify({ok:!1,error:r.message,code:r.code}))}const Va=async({positionals:e,flags:n})=>{if(e.length>0)throw new t(`INVALID_ARGS`,`proxy does not accept positional arguments.`);let r=await Ha(n);return D(n,r,()=>qa(r)),await Ja(),!0};async function Ha(e){let n=xe({session:`default`,command:`proxy`,positionals:[],flags:{stateDir:e.stateDir,daemonBaseUrl:``,daemonTransport:`http`,daemonServerMode:`http`}}),r=await ve(n),i=Ua(r.info.httpPort),a=Wa(e),o=da({upstreamBaseUrl:i,upstreamToken:r.info.token,clientToken:a});await Ga(o,e.proxyHost?.trim()||`127.0.0.1`,e.proxyPort??0);let s=o.address();if(!s||typeof s==`string`)throw new t(`COMMAND_FAILED`,`Proxy did not bind to a TCP address.`);let c=`http://${Ka(s.address)}:${s.port}`;return{proxyBaseUrl:c,agentDeviceBaseUrl:_e(c),token:a,upstreamBaseUrl:i,stateDir:n.paths.baseDir}}function Ua(e){if(!e)throw new t(`COMMAND_FAILED`,`Local daemon HTTP endpoint is unavailable.`,{hint:`Retry after cleaning daemon state, or run proxy with a fresh --state-dir.`});return`http://127.0.0.1:${e}`}function Wa(e){return e.daemonAuthToken?.trim()||rt(32).toString(`hex`)}function Ga(e,t,n){return new Promise((r,i)=>{e.once(`error`,i),e.listen(n,t,()=>{e.off(`error`,i),r()})})}function Ka(e){return e.includes(`:`)&&!e.startsWith(`[`)?`[${e}]`:e}function qa(e,t={}){let n=t.useColor??ie(),r=X(`✓`,`green`,n),i=X(e.proxyBaseUrl,`cyan`,n),a=X(`<tunnel URL>`,`cyan`,n),o=X(e.token,`yellow`,n);return[`${r} Proxy listening at ${i}`,``,`Provide this to the agent-device instance connecting:`,``,`Daemon base URL: ${a}`,`Daemon auth token: ${o}`].join(`
|
|
8
|
+
`)}function X(e,t,n){return n?ae(e,t,{validateStream:!1}):e}function Ja(){return new Promise(()=>{})}function Z(e,t){return`${e},${t}`}function Ya(e){return`${e.map(e=>lt(e).trimEnd()).join(`
|
|
9
|
+
---
|
|
10
|
+
`)}\n`}const Xa=new Set(Ve),Za=new Set(He);function Qa(e){let t=ze(e);return $a(t.actions,{actionLines:t.actionLines,metadata:Ue(e)})}function $a(e,n={}){let r={config:eo(n.metadata),warnings:[],unsupported:[]},i=[];for(let[t,a]of e.entries()){let e=n.actionLines?.[t]??t+1,o=no(a);switch(o.kind){case`commands`:i.push(...o.commands),Po(r,o.warnings,a,e);break;case`config`:Mo(r,o.appId,a,e),i.push(...o.commands),Po(r,o.warnings,a,e);break;case`unsupported`:r.unsupported.push({line:e,action:Ro(a),message:o.message});break}}if(r.unsupported.length>0)throw new t(`INVALID_ARGS`,`Cannot export replay to Maestro YAML: unsupported .ad action ${Lo(r.unsupported)}.`,{unsupported:r.unsupported});return{yaml:Io(r.config,i),warnings:r.warnings}}function eo(e){return e?.env&&Object.keys(e.env).length>0?{env:e.env}:{}}const to={open:ro,click:oo,press:oo,longpress:so,fill:fo,type:po,keyboard:mo,back:()=>({kind:`commands`,commands:[`back`]}),wait:ho,find:go,screenshot:_o,scroll:vo,swipe:yo};function no(e){return to[e.command]?.(e)??{kind:`unsupported`,message:`${e.command} has no Maestro equivalent`}}function ro(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`open requires an app id or URL`};if(zo(t))return{kind:`commands`,commands:[{openLink:t}]};let r=io(e,t);return n&&zo(n)?{kind:`config`,appId:t,commands:[r,{openLink:n}]}:n?{kind:`unsupported`,message:`open with a non-URL second argument is unsupported`}:{kind:`config`,appId:t,commands:[r]}}function io(e,t){let n=ao(e);return n?{launchApp:{appId:t,...n}}:`launchApp`}function ao(e){let t=e.flags?.launchArgs,n={};return e.flags?.relaunch===!0&&(n.stopApp=!0),e.flags?.clearAppState===!0&&(n.clearState=!0),Array.isArray(t)&&t.length>0&&(n.launchArguments=t),Object.keys(n).length>0?n:void 0}function oo(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`${e.command} requires a target`};let r=Co(t,n);if(!r)return{kind:`unsupported`,message:`tap target is not Maestro-compatible`};let i=Oo(e);return i.ok?e.flags?.doubleTap===!0?{kind:`commands`,commands:[{doubleTapOn:r}],warnings:uo(e,`doubleTapOn`)}:typeof e.flags?.holdMs==`number`?{kind:`commands`,commands:[{longPressOn:r}],warnings:[lo(e.flags.holdMs),...uo(e,`longPressOn`)]}:{kind:`commands`,commands:[jo(r,i.options)]}:{kind:`unsupported`,message:i.message}}function so(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`longpress requires a target`};let r=Co(t,n);return r?{kind:`commands`,commands:[{longPressOn:r}],warnings:co(e).map(lo)}:{kind:`unsupported`,message:`longpress target is not Maestro-compatible`}}function co(e){let[t,n,r]=e.positionals,i=Q(t)&&Q(n)?r:n;return i&&Q(i)?[Number(i)]:[]}function lo(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function uo(e,t){let n=[];return typeof e.flags?.count==`number`&&e.flags.count>1&&n.push(`tap --count ${e.flags.count} is not represented by Maestro ${t}`),typeof e.flags?.intervalMs==`number`&&e.flags.intervalMs>0&&n.push(`tap --interval-ms ${e.flags.intervalMs} is not represented by Maestro ${t}`),n}function fo(e){let[t,n]=e.positionals;if(!t||n===void 0)return{kind:`unsupported`,message:`fill requires a target and text`};let r=Co(t);return r?{kind:`commands`,commands:[{tapOn:r},{inputText:n}],warnings:[`fill exports as tapOn + inputText; Maestro may append text instead of replacing existing field contents`]}:{kind:`unsupported`,message:`fill target is not Maestro-compatible`}}function po(e){let[t]=e.positionals;if(t===void 0)return{kind:`unsupported`,message:`type requires text`};let n=No(t);return n===null?{kind:`commands`,commands:[{inputText:t}]}:{kind:`commands`,commands:[{eraseText:n}]}}function mo(e){let[t]=e.positionals;return t===`dismiss`?{kind:`commands`,commands:[`hideKeyboard`]}:t===`enter`||t===`return`?{kind:`commands`,commands:[{pressKey:`Enter`}]}:{kind:`unsupported`,message:`keyboard ${t??``}`.trim()}}function ho(e){let[t,n]=e.positionals;if(!t)return{kind:`unsupported`,message:`wait requires a target or duration`};if(Q(t))return{kind:`commands`,commands:[{waitForAnimationToEnd:{timeout:Number(t)}}],warnings:[`wait <ms> exports as waitForAnimationToEnd and may return before the full duration`]};if(t===`text`&&n)return{kind:`commands`,commands:[{extendedWaitUntil:{visible:n,timeout:Fo(e,nt.extendedWaitUntilTimeoutMs)}}]};let r=wo(t);return r?{kind:`commands`,commands:[{extendedWaitUntil:{visible:r,timeout:Fo(e,nt.extendedWaitUntilTimeoutMs)}}]}:{kind:`unsupported`,message:`wait selector is not Maestro-compatible`}}function go(e){let[t,n,r]=e.positionals;return t!==`text`||!n||!r?{kind:`unsupported`,message:`only find text <query> exists|missing exports to Maestro`}:r===`exists`?{kind:`commands`,commands:[{assertVisible:n}]}:r===`missing`||r===`not-exists`?{kind:`commands`,commands:[{assertNotVisible:n}]}:{kind:`unsupported`,message:`find text assertion "${r}" is unsupported`}}function _o(e){let[t]=e.positionals;return t?{kind:`commands`,commands:[{takeScreenshot:t}]}:{kind:`unsupported`,message:`screenshot requires an output path`}}function vo(e){let[t]=e.positionals;return!t||t===`down`?{kind:`commands`,commands:[`scroll`]}:{kind:`unsupported`,message:`scroll ${t} is not exported yet`}}function yo(e){let t=bo(e);if(!t)return{kind:`unsupported`,message:`only coordinate swipe exports to Maestro`};let n=xo(e);if(n===null)return{kind:`unsupported`,message:`swipe count must be a positive integer`};let r=So(e);return r?{kind:`unsupported`,message:r}:{kind:`commands`,commands:Array.from({length:n},()=>({swipe:t}))}}function bo(e){let[t,n,r,i]=e.positionals;if(!(!Q(t)||!Q(n)||!Q(r)||!Q(i)))return{start:Z(t,n),end:Z(r,i),duration:100}}function xo(e){let t=e.flags?.count??1;return Number.isInteger(t)&&t>=1?t:null}function So(e){if(e.flags?.pauseMs!==void 0)return`swipe --pause-ms has no Maestro equivalent`;if(e.flags?.pattern&&e.flags.pattern!==`one-way`)return`swipe ping-pong pattern has no Maestro equivalent`}function Co(e,t){return Q(e)&&Q(t)?{point:Z(e,t)}:e.startsWith(`@`)?null:wo(e)}function wo(e){let t;try{t=f(e)}catch{return e.includes(`=`)||e.includes(`||`)?null:e}let n=To(t.selectors);return n===null?t.selectors.length===1?Eo(t.selectors[0]):null:n}function To(e){if(e.length<=1)return null;let t=e.flatMap(e=>e.terms.length===1&&Xa.has(e.terms[0].key)?[e.terms[0].value]:[]);if(t.length!==e.length||t.length===0)return null;let n=t[0];return typeof n==`string`&&t.every(e=>e===n)?n:null}function Eo(e){let t={};for(let n of e.terms)if(!Do(t,n))return null;return Object.keys(t).length>0?t:null}function Do(e,t){return Xa.has(t.key)?typeof t.value!=`string`||e.id||e.text||e.label?!1:(e[t.key]=t.value,!0):Za.has(t.key)&&typeof t.value==`boolean`?(e[t.key]=t.value,!0):!1}function Oo(e){let t=Ao(e);return t?{ok:!1,message:t}:{ok:!0,options:ko(e)}}function ko(e){let t={};return typeof e.flags?.count==`number`&&e.flags.count>1&&(t.repeat=e.flags.count),typeof e.flags?.intervalMs==`number`&&e.flags.intervalMs>0&&(t.delay=e.flags.intervalMs),t}function Ao(e){if(e.flags?.jitterPx!==void 0)return`tap --jitter-px has no Maestro equivalent`;if(e.flags?.clickButton&&e.flags.clickButton!==`primary`)return`tap --button ${e.flags.clickButton} has no Maestro equivalent`}function jo(e,t){return Object.keys(t).length===0?{tapOn:e}:typeof e==`string`?{tapOn:{text:e,...t}}:e&&typeof e==`object`&&!Array.isArray(e)?{tapOn:{...e,...t}}:{tapOn:e}}function Mo(e,t,n,r){if(!e.config.appId){e.config.appId=t;return}e.config.appId!==t&&e.unsupported.push({line:r,action:Ro(n),message:`multiple app ids cannot be represented in one Maestro config (${e.config.appId} vs ${t})`})}function No(e){return e.length===0||![...e].every(e=>e===`\b`)?null:e.length}function Po(e,t,n,r){for(let i of t??[])e.warnings.push({line:r,action:Ro(n),message:i})}function Fo(e,t){let n=e.positionals.at(-1);return n&&Q(n)?Number(n):t}function Io(e,t){return Ya(Object.keys(e).length>0?[e,t]:[t])}function Lo(e){return e.map(e=>`line ${e.line} (${e.action}): ${e.message}`).join(`; `)}function Ro(e){return[e.command,...e.positionals??[]].join(` `).trim()}function zo(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function Q(e){return e!==void 0&&Number.isFinite(Number(e))}const Bo=async e=>{let{positionals:t}=e;return t[0]===`export`?await Ho(e):Vo(e)};function Vo({positionals:e,flags:n}){if(e.length>1)throw new t(`INVALID_ARGS`,`replay accepts exactly one input path: replay <path>`);if(n.out!==void 0)throw new t(`INVALID_ARGS`,`replay --out is only supported with replay export.`);return!1}async function Ho({positionals:e,flags:n}){Uo(e,n);let r=e[1];if(!r)throw new t(`INVALID_ARGS`,`replay export requires an input path.`);let i=S(r),a=Qa(k.readFileSync(i,`utf8`)),o=typeof n.out==`string`?S(n.out):void 0;o&&(k.mkdirSync(A.dirname(o),{recursive:!0}),k.writeFileSync(o,a.yaml));for(let e of a.warnings)process.stderr.write(`Warning: line ${e.line}: ${e.message}\n`);return D(n,{format:`maestro`,sourcePath:i,...o?{path:o}:{yaml:a.yaml},warnings:a.warnings},()=>o??a.yaml),!0}function Uo(e,n){if(e.length>2)throw new t(`INVALID_ARGS`,`replay export accepts exactly one input path: replay export <file.ad>`);if(n.replayUpdate)throw new t(`INVALID_ARGS`,`replay export does not support --update.`);if(n.replayMaestro)throw new t(`INVALID_ARGS`,`replay export reads .ad files; omit --maestro.`);if(n.replayEnv?.length)throw new t(`INVALID_ARGS`,`replay export does not evaluate --env substitutions.`)}const Wo=async({positionals:e,flags:t,client:r})=>{let i=await tt({client:r,command:`screenshot`,positionals:e,flags:t});return n(t.responseLevel)?(D(t,i,()=>JSON.stringify(i,null,2)),!0):(D(t,he(i),()=>i.overlayRefs?`Annotated ${i.overlayRefs.length} refs onto ${i.path}`:qo(i)),!0)},Go=async({positionals:e,flags:n,client:r})=>{if(e[0]===`snapshot`){let t=await tt({client:r,command:`diff`,positionals:e,flags:n});return D(n,t,()=>ne(t)),!0}if(e[0]!==`screenshot`)return!1;let i=n.baseline;if(!i||typeof i!=`string`)throw new t(`INVALID_ARGS`,`diff screenshot requires --baseline <path>`);let a=S(i),o=typeof n.out==`string`?S(n.out):void 0,s=e[1];if(e.length>2)throw new t(`INVALID_ARGS`,`diff screenshot accepts at most one current screenshot path`);let[{createAgentDevice:c,localCommandPolicy:l},{createLocalArtifactAdapter:u}]=await Promise.all([import(`./runtime.js`).then(e=>e.r),import(`./sdk-io.js`).then(e=>e.n)]),d=await c({backend:Ko(r,n),artifacts:u(),sessions:{get:e=>({name:e}),set:()=>{}},policy:l()}).capture.diffScreenshot({session:n.session,baseline:{kind:`path`,path:a},current:s?{kind:`path`,path:S(s)}:{kind:`live`},...o?{out:{kind:`path`,path:o}}:{},threshold:Yo(n.threshold),overlayRefs:n.overlayRefs,normalizeStatusBar:n.screenshotNormalizeStatusBar,surface:n.surface});return D(n,d,()=>te(d)),!0};function Ko(e,t){return{platform:Jo(t),captureScreenshot:async(t,n,r)=>he(await e.capture.screenshot({path:n,session:t.session,overlayRefs:r?.overlayRefs,pixelDensity:r?.pixelDensity,fullscreen:r?.fullscreen,normalizeStatusBar:r?.normalizeStatusBar,stabilize:r?.stabilize,surface:r?.surface}))}}function qo(e){if(typeof e.width!=`number`||typeof e.height!=`number`)return e.path;let t=typeof e.pixelDensity==`number`?` @${e.pixelDensity}x`:``;return`${e.path} (${e.width}x${e.height}${t})`}function Jo(e){switch(e.platform){case`android`:case`linux`:case`macos`:return e.platform;default:return`ios`}}function Yo(e){if(!(e==null||e===``))return Number(e)}const Xo={connect:si,disconnect:bi,connection:xi,auth:Ui,daemon:Zi,device:ea,proxy:Va,replay:Bo,screenshot:Wo,diff:Go};async function Zo(e){let t={...e.flags},n=Xo[e.command];return n&&await n({...e,flags:t})?!0:pr(e.command)?await Qo({...e,command:e.command,flags:t}):!1}async function Qo(e){let{runGenericClientBackedCommand:t}=await import(`./generic.js`);return await t(e)}function $o(e){return[`exec`,`--yes`,`--package`,`agent-react-devtools@0.4.0`,`--`,`agent-react-devtools`,...e]}function es(e){return e===`ios-instance`}function ts(e){return e[0]===`wait`&&e.includes(`--connected`)}function ns(e,t,n){n===0||!ts(e)||!es(t?.leaseBackend)||process.stderr.write([`Hint: Remote iOS React DevTools connects during JavaScript startup.`,"If the app was already open before `agent-device react-devtools start`, relaunch it with `agent-device open <bundle-id> --platform ios --relaunch`, then retry `agent-device react-devtools wait --connected`.",``].join(`
|
|
11
|
+
`))}function $(e,t,n){return n||(e.push(t),``)}function rs(e){if(!e?.metroProxyBaseUrl||!Jt(e.leaseBackend))return null;let n=[],r={serverBaseUrl:$(n,`metroProxyBaseUrl`,e.metroProxyBaseUrl),bearerToken:$(n,`metroBearerToken`,e.metroBearerToken),tenantId:$(n,`tenant`,e.tenant),runId:$(n,`runId`,e.runId),leaseId:$(n,`leaseId`,e.leaseId)};if(n.length>0)throw new t(`INVALID_ARGS`,`react-devtools remote bridge requires ${n.join(`, `)}.`,{missing:n});return r}async function is(e,t,n){let{flags:r}=t,i=rs(r);if(!i)return n();let a=t.stateDir??process.cwd(),o=t.session??r?.session??`default`,s=r?.remoteConfig??`${i.tenantId}:${i.runId}:${i.leaseId}`;if(e[0]===`stop`)try{return await n()}finally{await Ut({projectRoot:t.cwd??process.cwd(),stateDir:a,profileKey:s,consumerKey:o})}return await Ht({projectRoot:t.cwd??process.cwd(),stateDir:a,serverBaseUrl:i.serverBaseUrl,bearerToken:i.bearerToken,bridgeScope:{tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId},session:o,profileKey:s,consumerKey:o,env:t.env??process.env}),await n()}function as(e,t){if(e[0]!==`start`)return!1;let{flags:n}=t;return n?n.leaseProvider===`limrun`&&n.leaseBackend===`android-instance`&&n.metroProxyBaseUrl===void 0&&t.configureDirectPortReverse!==void 0:!1}async function os(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,i=await is(e,t,async()=>(as(e,t)&&await t.configureDirectPortReverse?.(),(await l(`npm`,$o(e),{cwd:n,env:r,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode));return ns(e,t.flags,i),i}async function ss(e,n){switch(e[0]){case`setup`:{cs(n.flags.json);let{setupManagedAgentBrowser:e}=await import(`./agent-browser-tool.js`).then(e=>e.t),t=await e({stateDir:n.stateDir});return ls(n.flags.json,t),0}case`doctor`:{let{doctorManagedAgentBrowser:e}=await import(`./agent-browser-tool.js`).then(e=>e.t),t=await e({stateDir:n.stateDir});return us(n.flags.json,t.exitCode===0?`Web backend is healthy.`:`Web backend doctor reported issues.`,t),t.exitCode}default:throw new t(`INVALID_ARGS`,`web requires setup or doctor`)}}function cs(e){e||process.stdout.write(`Setting up managed agent-browser backend (downloads if needed)...
|
|
12
|
+
`)}function ls(e,t){if(e){y({success:!0,data:{status:ds(t)}});return}process.stdout.write(`Managed web backend installed.\nagent-browser available at: ${t.binaryPath}\n`)}function us(e,t,n){if(e){y({success:!0,data:fs(n)});return}process.stdout.write(`${t}\n`)}function ds(e){let{socketDir:t,...n}=e;return n}function fs(e){let t=e.status;return ps(t)?{...e,status:ds(t)}:e}function ps(e){return typeof e==`object`&&!!e&&`socketDir`in e&&`installDir`in e&&`binaryPath`in e}function ms(e){let n;try{n=JSON.parse(e)}catch{throw new t(`INVALID_ARGS`,`Batch steps must be valid JSON.`)}if(!Array.isArray(n)||n.length===0)throw new t(`INVALID_ARGS`,`Batch steps must be a non-empty JSON array.`);return hs(n)}function hs(e){let t=!1,n=e.map((e,n)=>{if(_s(e))return vs(e,n+1);let r=ys(e,n+1);return t=!0,gs(r)});return t&&process.stderr.write(`Warning: batch steps using positionals/flags are deprecated and will be removed in the next major version. Use {"command":"...","input":{...}} steps instead.
|
|
13
|
+
`),n}function gs(e){let t=et(e.command,e.positionals??[],ws(e.flags));return{command:e.command,input:t,...e.runtime===void 0?{}:{runtime:e.runtime}}}function _s(e){return m(e)&&`input`in e&&!(`positionals`in e)&&!(`flags`in e)}function vs(e,t){let n=p(e.runtime,t),{runtime:r,...i}=e;return{...i,...n===void 0?{}:{runtime:n}}}function ys(e,n){if(!m(e))throw new t(`INVALID_ARGS`,`Invalid batch step ${n}.`);xs(e,n);let r=bs(e.command,n),i=Ss(e.positionals,n),a=Cs(e.flags,n),o=p(e.runtime,n);return{command:r,...i===void 0?{}:{positionals:i},...a===void 0?{}:{flags:a},...o===void 0?{}:{runtime:o}}}function bs(e,n){let r=typeof e==`string`?e.trim().toLowerCase():``;if(!r)throw new t(`INVALID_ARGS`,`Batch step ${n} requires command.`);if(Le(r))return r;throw new t(`INVALID_ARGS`,`Batch step ${n} command is not available through command batch: ${String(e)}`)}function xs(e,n){let r=Object.keys(e).filter(e=>![`command`,`positionals`,`flags`,`runtime`].includes(e));if(r.length>0)throw new t(`INVALID_ARGS`,`Batch step ${n} has unknown legacy field(s): ${r.join(`, `)}.`)}function Ss(e,n){if(e!==void 0){if(!Array.isArray(e)||e.some(e=>typeof e!=`string`))throw new t(`INVALID_ARGS`,`Batch step ${n} positionals must contain only strings.`);return e}}function Cs(e,n){if(e!==void 0){if(!m(e))throw new t(`INVALID_ARGS`,`Batch step ${n} flags must be an object.`);return e}}function ws(e){return{json:!1,help:!1,version:!1,...e}}function Ts(e,t={}){let n=Es(t),r={...e};return n.defaultPlatform&&r.platform===void 0&&(r.platform=n.defaultPlatform),r}function Es(e){let t=e.env??process.env,n=e.inheritedPlatform??e.configuredPlatform??Os(t.AGENT_DEVICE_PLATFORM),r=As(e.configuredSession??t.AGENT_DEVICE_SESSION);return{defaultPlatform:n,lockPolicy:Ds(e.policyOverrides,t,r)}}function Ds(e,t,n){let r=e?.sessionLock??ks(t.AGENT_DEVICE_SESSION_LOCK);if(r)return r;if(n)return`reject`}function Os(e){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(n===`ios`||n===`android`||n===`apple`)return n;throw new t(`INVALID_ARGS`,`Invalid AGENT_DEVICE_PLATFORM: ${e}. Use ios, android, or apple.`)}}function ks(e){if(e===void 0)return;let n=e.trim().toLowerCase();if(n){if(n===`reject`||n===`strip`)return n;throw new t(`INVALID_ARGS`,`Invalid session lock mode: ${e}. Use reject or strip.`)}}function As(e){return typeof e==`string`&&e.trim().length>0}function js(e,t){let n=St(e),r=t?.env??process.env,i=t?.cwd??process.cwd(),a=Ms(n.command)?En({remoteConfig:n.flags.remoteConfig,cwd:i,env:r}):{},o=T(Ye({command:n.command,cwd:i,cliFlags:n.flags,env:r}),a);return{...Ot(n,{strictFlags:t?.strictFlags,defaultFlags:o}),providedFlags:n.providedFlags}}function Ms(e){return e!==null}const Ns={sendToDaemon:ye},Ps=new Set([`launchUrl`,`kind`,`metroBearerToken`,`metroKind`,`metroListenHost`,`metroNoInstallDeps`,`metroNoReuseExisting`,`metroPreparePort`,`metroProbeTimeoutMs`,`metroProjectRoot`,`metroProxyBaseUrl`,`metroPublicBaseUrl`,`metroRuntimeFile`,`metroStartupTimeoutMs`,`metroStatusHost`]),Fs=new Set([`connect`,`connection`,`close`,`daemon`,`device`,`disconnect`,`metro`,`proxy`,`session`]);async function Is(e,t=Ns){let n=i(),r=Ce(),o=qs(e),s=e.includes(`--json`);await a({session:lc(e)??process.env.AGENT_DEVICE_SESSION??`default`,requestId:n,command:e[0],debug:o},async()=>{let{parsed:i,command:a,positionals:c}=await Ls(e,{version:r,jsonRequested:s,debugEnabled:o}),l=Xs(a,i.providedFlags),u=Rs(i,{command:a,positionals:c,requestId:n,debugOutputEnabled:l}),d=null;try{if(a===`react-devtools`){process.exit(await zs(u,t));return}if(a===`web`){process.exit(await ss(c,{flags:u.effectiveFlags,stateDir:u.daemonPaths.baseDir}));return}if(Je({command:a,currentVersion:r,stateDir:u.daemonPaths.baseDir,flags:u.effectiveFlags}),await Bs(u,t),a===`cdp`){process.exit(await tn(c,{flags:u.effectiveFlags,runtime:u.resolvedRuntime,cwd:process.cwd(),env:process.env}));return}d=Hs(u);let e=await Us(u);await Ws(u,be(Vs(u),{transport:oc({command:a,flags:u.effectiveFlags,replayTestReporterRuntime:e,transport:t.sendToDaemon})}),e)}catch(e){Gs(e,u,d)}finally{d&&d()}})}async function Ls(n,r){let i;try{i=js(n,{cwd:process.cwd(),env:process.env})}catch(t){u({level:`error`,phase:`cli_parse_failed`,data:{error:t instanceof Error?t.message:String(t)}});let n=e(t,{diagnosticId:s().diagnosticId,logPath:o({force:!0})??void 0});r.jsonRequested?y({success:!1,error:n}):v(n,{showDetails:r.debugEnabled}),process.exit(1)}for(let e of i.warnings)process.stderr.write(`Warning: ${e}\n`);i.flags.version&&(process.stdout.write(`${r.version}\n`),process.exit(0));let a=i.command===`help`,c=i.flags.help;if(a||c){a&&i.positionals.length>1&&(v(new t(`INVALID_ARGS`,`help accepts at most one command.`)),process.exit(1));let e=a?i.positionals[0]:i.command;e||(process.stdout.write(`${await M()}\n`),process.exit(0));let n=await zt(e);n&&(process.stdout.write(n),process.exit(0)),v(new t(`INVALID_ARGS`,Js(e))),process.stdout.write(`${await M()}\n`),process.exit(1)}return i.command||(process.stdout.write(`${await M()}\n`),process.exit(1)),{parsed:i,command:i.command,positionals:i.positionals}}function Rs(t,n){let i=new Set(t.providedFlags.map(e=>e.key));try{let e=Es({policyOverrides:t.flags,configuredPlatform:t.flags.platform,configuredSession:t.flags.session}),r=e.lockPolicy?{...t.flags}:Ts(t.flags,{policyOverrides:t.flags,configuredPlatform:t.flags.platform,configuredSession:t.flags.session}),a=x(r.stateDir),o=r.session??`default`,s=$s({command:n.command,explicitFlagKeys:i,stateDir:a.baseDir,session:o,remoteConfig:r.remoteConfig,hasResolvedSession:r.session!==void 0}),c=s?ic(r,s.flags,i):r;return{...n,binding:e,flags:r,daemonPaths:a,sessionName:o,connectionDefaults:s,explicitFlagKeys:i,effectiveFlags:c,resolvedRuntime:s?.runtime,connectionMetadata:s?.connection,parsedBatchSteps:void 0}}catch(i){let a=e(r(i),{diagnosticId:s().diagnosticId,logPath:o({force:!0})??void 0});t.flags.json?y({success:!1,error:a}):v(a,{showDetails:n.debugOutputEnabled}),process.exit(1)}}async function zs(e,t){return await os(e.positionals,{flags:{...e.effectiveFlags,leaseProvider:e.connectionDefaults?.connection?.leaseProvider},stateDir:e.daemonPaths.baseDir,session:e.effectiveFlags.session??e.sessionName,cwd:process.cwd(),env:process.env,configureDirectPortReverse:async()=>{let n=await t.sendToDaemon({command:oe.runtime,positionals:[`port-reverse`],flags:{...e.effectiveFlags,leaseProvider:e.connectionDefaults?.connection?.leaseProvider,devicePort:8097,hostPort:8097,portReverseName:`react-devtools`},session:e.effectiveFlags.session??e.sessionName});n.ok||Se(n.error)}})}async function Bs(e,n){if(e.command===`batch`){if(e.positionals.length>0)throw new t(`INVALID_ARGS`,`batch does not accept positional arguments.`);e.parsedBatchSteps=Zs(e.flags)}if(tc(e.command)&&(e.effectiveFlags=(await gr({command:e.command,flags:e.effectiveFlags,stateDir:e.daemonPaths.baseDir,env:process.env})).flags),e.effectiveFlags.remoteConfig&&ec(e.command)){let t=be(Vs(e),{transport:sc(n.sendToDaemon)}),r=await Pn({command:e.command,flags:e.effectiveFlags,client:t,runtime:e.resolvedRuntime,positionals:e.positionals,batchSteps:e.parsedBatchSteps,forceRuntimePrepare:ac(e.explicitFlagKeys)});e.effectiveFlags=r.flags,e.resolvedRuntime=r.runtime,e.connectionMetadata=r.connection}nc({command:e.command,flags:e.effectiveFlags,runtime:e.resolvedRuntime,explicitFlagKeys:e.explicitFlagKeys,hadConnectionDefaults:!!e.connectionDefaults})&&process.stderr.write(`Warning: open is using explicit remote daemon or tenant flags without saved Metro runtime hints. React Native apps may launch without bundle/runtime hints; prefer connect --remote-config <path> first or pass --remote-config <path> on this command.
|
|
14
|
+
`)}function Vs(e){let t=e.effectiveFlags,n=e.connectionMetadata;return{session:t.session,requestId:e.requestId,stateDir:t.stateDir,daemonBaseUrl:t.daemonBaseUrl,daemonAuthToken:t.daemonAuthToken,daemonTransport:t.daemonTransport,daemonServerMode:t.daemonServerMode,tenant:t.tenant,sessionIsolation:t.sessionIsolation,runId:t.runId,leaseId:t.leaseId,leaseBackend:t.leaseBackend,leaseProvider:n?.leaseProvider,clientId:n?.clientId,deviceKey:n?.deviceKey,providerApp:t.providerApp,providerOsVersion:t.providerOsVersion,providerProject:t.providerProject,providerBuild:t.providerBuild,providerSessionName:t.providerSessionName,awsProjectArn:t.awsProjectArn,awsDeviceArn:t.awsDeviceArn,awsAppArn:t.awsAppArn,awsRegion:t.awsRegion,awsInteractionMode:t.awsInteractionMode,runtime:e.resolvedRuntime,lockPolicy:e.binding.lockPolicy,lockPlatform:e.binding.defaultPlatform,cwd:process.cwd(),debug:e.debugOutputEnabled,cost:t.cost,responseLevel:t.responseLevel}}function Hs(e){let t=e.effectiveFlags.daemonBaseUrl;return e.debugOutputEnabled&&!e.effectiveFlags.json&&!t?uc(e.daemonPaths.logPath):null}async function Us(e){if(e.command!==`test`)return;let{createReplayTestReporterRuntime:t}=await import(`./reporting.js`);return t({debug:e.debugOutputEnabled,verbose:e.effectiveFlags.verbose,json:e.effectiveFlags.json,reporter:e.effectiveFlags.reporter,reportJunit:e.effectiveFlags.reportJunit})}async function Ws(e,n,r){let{command:i,positionals:a,effectiveFlags:o}=e;if(i===`batch`){if(!e.parsedBatchSteps)throw new t(`INVALID_ARGS`,`batch requires --steps or --steps-file.`);let s=e.parsedBatchSteps.map((t,n)=>({...t,input:e.binding.lockPolicy&&e.flags.platform===void 0?{...t.input}:Ts(t.input,{policyOverrides:o,configuredPlatform:o.platform,configuredSession:o.session,inheritedPlatform:o.platform})}));if(await Zo({command:i,positionals:a,flags:{...o,batchSteps:s},client:n,debug:e.debugOutputEnabled,replayTestReporterRuntime:r}))return}else if(i===`runtime`)throw new t(`INVALID_ARGS`,`runtime command was removed. Use connect --remote-config <path> for remote runs, or metro prepare --remote-config <path> for inspection.`);else if(await Zo({command:i,positionals:a,flags:o,client:n,debug:e.debugOutputEnabled,replayTestReporterRuntime:r}))return;throw new t(`INVALID_ARGS`,Ys(i))}function Gs(t,n,i){let a=r(t),c=e(a,{diagnosticId:s().diagnosticId,logPath:o({force:!0})??void 0});if(n.command===`close`&&Qs(a)){n.effectiveFlags.json&&y({success:!0,data:{closed:`session`,source:`no-daemon`}});return}n.effectiveFlags.json?y({success:!1,error:c}):(v(c,{showDetails:n.debugOutputEnabled}),n.debugOutputEnabled&&Ks(n.daemonPaths.logPath)),i&&i(),process.exit(1)}function Ks(e){try{if(k.existsSync(e)){let t=k.readFileSync(e,`utf8`).split(`
|
|
11
15
|
`),n=t.slice(Math.max(0,t.length-200)).join(`
|
|
12
|
-
`);n.trim().length>0&&process.stderr.write(`\n[daemon log]\n${n}\n`)}}catch{}
|
|
16
|
+
`);n.trim().length>0&&process.stderr.write(`\n[daemon log]\n${n}\n`)}}catch{}}function qs(e){try{let t=St(e);return Xs(t.command??``,t.providedFlags)}catch{return e.includes(`--debug`)||e.includes(`-v`)||e.includes(`--verbose`)}}function Js(e){let t=vt(e);return t?`Unknown command: ${e}. Did you mean ${t}?`:`Unknown command: ${e}`}function Ys(e){return re(e)?(u({level:`error`,phase:`cli_known_command_unhandled`,data:{command:e}}),`Command is registered but no CLI handler accepted it: ${e}`):`Unknown command: ${e}`}function Xs(e,t){return t.some(t=>t.key===`verbose`&&(t.token===`--debug`||t.token===`-v`||e!==`test`))}function Zs(e){let n=``;if(e.steps)n=e.steps;else if(e.stepsFile)try{n=k.readFileSync(e.stepsFile,`utf8`)}catch(n){let r=n instanceof Error?n.message:String(n);throw new t(`INVALID_ARGS`,`Failed to read --steps-file ${e.stepsFile}: ${r}`)}return ms(n)}function Qs(e){return e.code===`COMMAND_FAILED`?e.details?.kind===`daemon_startup_failed`?!0:e.message.toLowerCase().includes(`failed to start daemon`)?typeof e.details?.infoPath==`string`||typeof e.details?.lockPath==`string`:!1:!1}function $s(e){return e.command===`connect`||e.command===`connection`||e.command===`daemon`||e.command===`proxy`?null:on({stateDir:e.stateDir,session:e.session,remoteConfig:e.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!e.explicitFlagKeys.has(`session`)&&(!e.remoteConfig||e.command===`disconnect`||!e.hasResolvedSession),validateRemoteConfigHash:e.command!==`disconnect`})}function ec(e){return!Fs.has(e)}function tc(e){return e!==`auth`&&e!==`connection`&&e!==`daemon`&&e!==`device`&&e!==`proxy`}function nc(e){return e.command!==`open`||e.runtime||e.flags.bundleUrl||e.flags.metroHost||e.flags.metroPort||e.flags.remoteConfig||e.hadConnectionDefaults?!1:rc(e.explicitFlagKeys)}function rc(e){return e.has(`daemonBaseUrl`)||e.has(`daemonTransport`)||e.has(`tenant`)||e.has(`sessionIsolation`)||e.has(`runId`)||e.has(`leaseId`)||e.has(`leaseBackend`)}function ic(e,t,n){let r={...e};for(let[e,i]of Object.entries(t))i!==void 0&&(n.has(e)||(r[e]=i));return r}function ac(e){for(let t of Ps)if(e.has(t))return!0;return!1}function oc(e){let{command:t,flags:n,replayTestReporterRuntime:r,transport:i}=e;return n.json?sc(i):async e=>await cc(i,{...e,meta:{...e.meta,requestProgress:t===`test`?`replay-test`:`command`}},t===`test`&&r?{onProgress:r.onProgress}:void 0)}function sc(e){return async t=>await cc(e,t)}async function cc(e,t,n){return await e(t,n)}function lc(e){for(let t=0;t<e.length;t+=1){let n=e[t];if(n.startsWith(`--session=`)){let e=n.slice(10).trim();return e.length>0?e:null}if(n===`--session`){let n=e[t+1]?.trim();return n&&!n.startsWith(`-`)?n:null}}return null}ct(process.argv[1]??``).href===import.meta.url&&Is(process.argv.slice(2)).catch(t=>{v(e(r(t)),{showDetails:!0}),process.exit(1)});function uc(e){try{let t=k.existsSync(e)?k.statSync(e).size:0,n=!1,r=setInterval(()=>{if(!n&&k.existsSync(e))try{let n=k.statSync(e);if(n.size<t&&(t=0),n.size<=t)return;let r=k.openSync(e,`r`);try{let e=Buffer.alloc(n.size-t);k.readSync(r,e,0,e.length,t),t=n.size,e.length>0&&process.stdout.write(e.toString(`utf8`))}finally{k.closeSync(r)}}catch{}},200);return()=>{n=!0,clearInterval(r)}}catch{return null}}export{Is as runCli};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{j as e}from"./sdk-batch-runner.js";import{o as t}from"./registry.js";const n=t(),r=new Map(n.map(e=>[e.name,e]));function i(){return[...n]}function a(){return e().map(e=>{let t=s(e);if(!t)throw Error(`Missing command metadata for MCP-exposed command: ${e}`);return t})}function o(e){return r.has(e)}function s(e){return r.get(e)}export{a as i,o as n,i as r,s as t};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{d as e,p as t,r as n}from"./registry.js";import{r}from"./command-metadata.js";const i={cdp:{usageOverride:`cdp [...args]`,listUsageOverride:`cdp`,helpDescription:`Run CDP commands for React Native diagnostics, JS heap usage, heap snapshots, and leak analysis`,summary:`Inspect React Native CDP targets, JS heap growth, heap snapshots, retainers, and leak signals`,positionalArgs:[`args?`],allowsExtraPositionals:!0,supportedFlags:e},auth:{usageOverride:`auth status|login|logout`,listUsageOverride:`auth`,helpDescription:`Manage cloud login state used by remote daemon and cloud device workflows.`,summary:`Manage cloud login state used by remote daemon and cloud device workflows`,positionalArgs:[`status|login|logout`],supportedFlags:[`remoteConfig`,`stateDir`]},daemon:{usageOverride:`daemon stop [--state-dir <path>] [--clean]`,listUsageOverride:`daemon stop`,helpDescription:`Stop a local daemon after verifying its PID/start-time identity. Use --clean to remove retained Apple runner processes and leases owned by that daemon.`,summary:`Safely stop a local daemon and optionally clean retained runner resources`,positionalArgs:[`stop`],allowedFlags:[`clean`],supportedFlags:[`stateDir`]},device:{usageOverride:`device status [--platform <platform>] [--udid <udid>] [--serial <serial>] [--stale]`,listUsageOverride:`device status`,helpDescription:`Inspect advisory host-local device ownership claims without starting or contacting a daemon. --stale only inspects proven-stale claims; it does not reclaim claims or clean platform resources.`,summary:`Inspect local advisory device ownership without daemon side effects`,positionalArgs:[`status`],allowedFlags:[`stale`],supportedFlags:[`platform`,`device`,`udid`,`serial`]},connect:{usageOverride:`connect [cloud|proxy|limrun|browserstack|aws-device-farm] [--remote-config <path>] [--daemon-base-url <url>] [--tenant <id>] [--run-id <id>] [--lease-id <id>] [--lease-backend <backend>] [--force] [--no-login]`,helpDescription:`Connect to a remote daemon, authenticate when needed, and save remote session state. AGENT_DEVICE_CLOUD_BASE_URL is the bridge/control-plane API origin; use AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_... for CI/service-token automation.`,listUsageOverride:`connect`,summary:`Attach CLI commands to a saved remote daemon/cloud lease; inspect for remote runs, tenants, or service-token CI`,allowedFlags:[`remoteConfig`,`daemonBaseUrl`,`tenant`,`runId`,`leaseId`,`leaseBackend`,`providerApp`,`providerOsVersion`,`providerProject`,`providerBuild`,`providerSessionName`,`awsProjectArn`,`awsDeviceArn`,`awsAppArn`,`awsRegion`,`awsInteractionMode`,`force`,`noLogin`],supportedFlags:[`stateDir`,`daemonAuthToken`,`session`,`platform`,`device`,...t,`launchUrl`]},connection:{usageOverride:`connection status`,listUsageOverride:`connection`,helpDescription:`Inspect active remote connection state`,summary:`Inspect the active saved remote connection before assuming commands are local`,positionalArgs:[`status`],supportedFlags:[`remoteConfig`,`stateDir`,`session`]},disconnect:{helpDescription:`Disconnect remote daemon state, stop owned Metro companion, and release lease`,listUsageOverride:`disconnect`,summary:`Clear remote connection state, stop owned Metro companions, and release remote leases`,allowedFlags:[`shutdown`],supportedFlags:[`remoteConfig`,`stateDir`,`session`]},mcp:{helpDescription:`Start the official stdio MCP server. It exposes structured command tools backed by the agent-device client.`,summary:`Start MCP server`},proxy:{usageOverride:`proxy [--host <host>] [--port <port>] [--daemon-auth-token <token>] [--state-dir <path>]`,listUsageOverride:`proxy`,helpDescription:`Expose the local daemon HTTP contract through a tunnel-friendly reverse proxy.
|
|
2
2
|
|
|
3
3
|
Run this on the host that has access to simulators/devices, expose the printed local proxy URL through a tunnel, then point another machine at the tunnel URL with connect proxy.
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ Use the /agent-device base path when connecting through cloudflared, ngrok, or a
|
|
|
9
9
|
Examples:
|
|
10
10
|
agent-device proxy --port 4310
|
|
11
11
|
cloudflared tunnel --url http://127.0.0.1:4310
|
|
12
|
-
agent-device connect proxy --daemon-base-url https://example.trycloudflare.com/agent-device --daemon-auth-token <token>`,summary:`Expose a local daemon through cloudflared, ngrok, or another HTTP tunnel`,allowedFlags:[`proxyHost`,`proxyPort`,`daemonAuthToken`,`stateDir`]},"react-devtools":{usageOverride:`react-devtools [...args]`,listUsageOverride:`react-devtools`,helpDescription:`Run pinned agent-react-devtools commands for React Native performance profiling, component trees, props/state/hooks, and render analysis`,summary:`Inspect React Native components, props, hooks, errors, slow renders, and rerender profiles`,positionalArgs:[`args?`],allowsExtraPositionals:!0,supportedFlags:
|
|
12
|
+
agent-device connect proxy --daemon-base-url https://example.trycloudflare.com/agent-device --daemon-auth-token <token>`,summary:`Expose a local daemon through cloudflared, ngrok, or another HTTP tunnel`,allowedFlags:[`proxyHost`,`proxyPort`,`daemonAuthToken`,`stateDir`]},"react-devtools":{usageOverride:`react-devtools [...args]`,listUsageOverride:`react-devtools`,helpDescription:`Run pinned agent-react-devtools commands for React Native performance profiling, component trees, props/state/hooks, and render analysis`,summary:`Inspect React Native components, props, hooks, errors, slow renders, and rerender profiles`,positionalArgs:[`args?`],allowsExtraPositionals:!0,supportedFlags:e},web:{usageOverride:`web setup | web doctor`,listUsageOverride:`web setup|doctor`,helpDescription:`Install and inspect the managed web automation backend used by --platform web.
|
|
13
13
|
|
|
14
14
|
First-run flow:
|
|
15
15
|
agent-device web setup
|
|
@@ -19,4 +19,4 @@ First-run flow:
|
|
|
19
19
|
|
|
20
20
|
Runtime web commands do not install the backend implicitly. If the managed backend is missing, run agent-device web setup. The backend is resolved only from the managed install in the effective agent-device state dir.
|
|
21
21
|
|
|
22
|
-
Use web setup to install or reuse the pinned backend. Use web doctor after setup to verify browser backend health.`,summary:`Manage web automation backend`,positionalArgs:[`setup|doctor`],supportedFlags:[`stateDir`]}},a=n();function o(e){return Object.hasOwn(i,e)?i[e]:void 0}function s(e){return Object.hasOwn(a,e)?a[e]:void 0}const c=new Map(r().map(
|
|
22
|
+
Use web setup to install or reuse the pinned backend. Use web doctor after setup to verify browser backend health.`,summary:`Manage web automation backend`,positionalArgs:[`setup|doctor`],supportedFlags:[`stateDir`]}},a=n();function o(e){return Object.hasOwn(i,e)?i[e]:void 0}function s(e){return Object.hasOwn(a,e)?a[e]:void 0}const c=new Map(r().map(t=>[t.name,{helpDescription:t.description,supportedFlags:e}]));function l(e){if(e)return d(e)}function u(e){let t=d(e);if(!t)throw Error(`Missing command schema for ${e}`);return t}function d(e){let t=o(e);if(t)return t;let n=c.get(e),r=s(e);if(n)return r?{...n,...r}:n}function f(e,t){let n=l(e);if(!n?.defaults)return!1;let r=!1;for(let[e,i]of Object.entries(n.defaults))t[e]===void 0&&(t[e]=i,r=!0);return r}export{u as n,l as r,f as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={control:{retryMaxRetries:3},command:{retryTapMaxAttempts:2,targetLookupTimeoutMs:17e3,optionalTargetLookupTimeoutMs:7e3,scrollUntilVisibleTimeoutMs:2e4,waitForAnimationToEndTimeoutMs:15e3,waitForAnimationToEndDifferencePercent:.005,longPressDurationMs:3e3,swipeDurationMs:400,repeatDelayMs:100,scrollUntilVisibleSpeed:40,scrollUntilVisiblePercentage:100,eraseTextMaxCharacters:50},observation:{pollIntervalMs:200,defaultSettleAttempts:10},targetSwipe:{nearEdgeFraction:.1,farEdgeFraction:.9},screenSwipe:{nearEdgeFraction:.1,farEdgeFraction:.9,centerFraction:.5,downStartFraction:.2,upStartFraction:{android:.5,ios:.9}},scrollUntilVisibleSwipe:{nearEdgeFraction:.1,farEdgeFraction:.9}};function t(e){return Math.trunc(1e3*(100-e)/100)+1}const n={assertVisibleTimeoutMs:e.command.targetLookupTimeoutMs,assertNotVisibleTimeoutMs:e.command.targetLookupTimeoutMs,extendedWaitUntilTimeoutMs:e.command.targetLookupTimeoutMs,runFlowConditionTimeoutMs:e.command.optionalTargetLookupTimeoutMs},r=e.observation.pollIntervalMs*e.observation.defaultSettleAttempts;export{t as i,e as n,r,n as t};
|