agent-device 0.17.2 → 0.17.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.apk → agent-device-android-multitouch-helper-0.17.4.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.4.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.manifest.json → agent-device-android-multitouch-helper-0.17.4.manifest.json} +4 -4
- package/android-snapshot-helper/README.md +3 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.apk → agent-device-android-snapshot-helper-0.17.4.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.4.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.manifest.json → agent-device-android-snapshot-helper-0.17.4.manifest.json} +6 -6
- package/dist/src/123.js +1 -1
- package/dist/src/1231.js +1 -1
- package/dist/src/1352.js +1 -1
- package/dist/src/221.js +2 -2
- package/dist/src/2403.js +3 -3
- package/dist/src/2415.js +37 -29
- package/dist/src/4012.js +4 -0
- package/dist/src/5611.js +1 -0
- package/dist/src/5827.js +1 -0
- package/dist/src/6088.js +1 -0
- package/dist/src/6133.js +1 -0
- package/dist/src/7847.js +1 -1
- package/dist/src/9471.js +1 -1
- package/dist/src/9542.js +6 -3
- package/dist/src/9616.js +2 -1
- package/dist/src/9818.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +0 -1
- package/dist/src/android.js +5 -5
- package/dist/src/apple.js +1 -1
- package/dist/src/apps.js +10 -10
- package/dist/src/args.js +53 -14
- package/dist/src/batch.js +1 -1
- package/dist/src/cli-output.js +30 -0
- package/dist/src/cli.js +15 -16
- package/dist/src/command-surface.js +1 -1
- package/dist/src/contracts.d.ts +52 -0
- package/dist/src/contracts.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/generic.js +5 -5
- package/dist/src/index.d.ts +127 -8
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace-recording.js +3 -3
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +14 -0
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session.js +8 -10
- package/dist/src/snapshot.js +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests-Bridging-Header.h +1 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +14 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +297 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +327 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +122 -173
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +153 -5
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +171 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -10
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +64 -18
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +200 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +450 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +82 -178
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +425 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +77 -6
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +10 -1
- package/ios-runner/README.md +5 -5
- package/ios-runner/RUNNER_PROTOCOL.md +0 -1
- package/package.json +3 -3
- package/server.json +2 -2
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.2.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.2.apk.sha256 +0 -1
- package/dist/src/1534.js +0 -1
- package/dist/src/1620.js +0 -1
- package/dist/src/1644.js +0 -2
- package/dist/src/2284.js +0 -1
- package/dist/src/2474.js +0 -1
- package/dist/src/2672.js +0 -1
- package/dist/src/3393.js +0 -1
- package/dist/src/5898.js +0 -1
- package/dist/src/695.js +0 -1
- package/dist/src/7455.js +0 -1
- package/dist/src/8173.js +0 -27
- package/dist/src/8407.js +0 -1
- package/dist/src/8699.js +0 -1
- package/dist/src/9238.js +0 -4
- package/dist/src/9673.js +0 -1
- package/dist/src/9974.js +0 -1
package/dist/src/cli.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import{pathToFileURL as e}from"node:url";import t from"node:fs";import n from"node:crypto";import r from"node:path";import{ensureCompanionTunnel as o,stopCompanionTunnel as s}from"./1974.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as a}from"./2301.js";import{REMOTE_CONFIG_FIELD_SPECS as i,resolveRemoteConfigProfile as l,resolveRemoteConfigPath as c}from"./208.js";import{asAppError as d,normalizeError as u,AppError as f}from"./9152.js";import{createRequestId as m,withDiagnosticsScope as p,getDiagnosticsMeta as g,flushDiagnosticsToSessionFile as h,emitDiagnostic as w}from"./7599.js";import{resolveDaemonPaths as v}from"./
|
|
2
|
-
`,{encoding:"utf8",mode:384}),t.chmodSync(e,384)}function eA(e,t){w({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),ep(e)}let e_=i.map(e=>e.key);function eS(e){let t={};for(let n of e_){let r=e[n];void 0!==r&&(t[n]=r)}return t}let eD=new Set(["connect","connection","close","disconnect","metro","session"]),eC=new Set(["open"]);async function ek(e){let t,n,{command:r,flags:o,client:s}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let a=v(o.stateDir).baseDir,i=l({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),c={...eS(i.profile),...o,remoteConfig:i.resolvedPath},d=eu({stateDir:a,session:c.session??"default"});if(d&&d.remoteConfigPath!==i.resolvedPath)throw new f("INVALID_ARGS","A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.",{session:d.session,activeRemoteConfig:d.remoteConfigPath,requestedRemoteConfig:i.resolvedPath});let u=d??function(e,t){if(!e.tenant)throw new f("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new f("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new f("INVALID_ARGS","remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let n=new Date().toISOString();return{version:1,session:e.session??"default",remoteConfigPath:t,remoteConfigHash:eg(t),daemon:em(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??eE(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(c,i.resolvedPath),m={...c,session:u.session},p=function(e,t){if(e)return eT(e,t)?e:void 0}(u.runtime,m.platform)??e.runtime,g=u,h=!d;if(w=r,!eD.has(w)){let e=u.leaseBackend??function(e,t){let n=eE(e);if(n)return n;throw new f("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var w,I,y,A,_,S=u,D=o,C=e;if(S.leaseBackend&&S.leaseBackend!==C)throw new f("INVALID_ARGS","Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.",{session:S.session,leaseBackend:S.leaseBackend});if(S.platform&&D.platform&&S.platform!==D.platform)throw new f("INVALID_ARGS","Active remote connection is already bound to a different platform. Re-run connect --force to replace it.",{session:S.session,platform:S.platform});if(S.target&&D.target&&S.target!==D.target)throw new f("INVALID_ARGS","Active remote connection is already bound to a different target. Re-run connect --force to replace it.",{session:S.session,target:S.target});let t=await eB(s,g,e);m.leaseId=t.leaseId,m.leaseBackend=e,m.platform=g.platform??m.platform,m.target=g.target??m.target,(g.leaseId!==t.leaseId||g.leaseBackend!==e)&&(g={...g,leaseId:t.leaseId,leaseBackend:e,platform:g.platform??o.platform,target:g.target??o.target,updatedAt:new Date().toISOString()},h=!0)}if(I=r,y=e.batchSteps,(eC.has(I)||"batch"===I&&y&&y.some(e=>{let t=e.command.trim().toLowerCase();return eC.has(t)&&void 0===e.runtime}))&&eP(m)&&(!g.leaseId&&m.leaseId&&(g={...g,leaseId:m.leaseId,leaseBackend:m.leaseBackend}),e.forceRuntimePrepare||!p||!eT(p,m.platform))){if(!g.leaseId)throw new f("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await eN(m,s,u.remoteConfigPath,u.session,{tenantId:u.tenant,runId:u.runId,leaseId:g.leaseId});p=e.runtime;let o=(A=g.metro,_=e.cleanup,A?.projectRoot!==_?.projectRoot||A?.profileKey!==_?.profileKey||A?.consumerKey!==_?.consumerKey);t=o?g.metro:void 0,n=o?e.cleanup:void 0,g={...g,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},h=!0}if(h)try{ef({stateDir:a,state:g})}catch(e){throw await eb(n),e}return await eb(t),{flags:{...m,session:g.session,leaseId:g.leaseId,leaseBackend:g.leaseBackend,platform:g.platform??m.platform,target:g.target??m.target},runtime:p}}async function eN(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new f("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new f("INVALID_ARGS","Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.");let s=await t.metro.prepare({projectRoot:e.metroProjectRoot,kind:e.metroKind,publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:o,launchUrl:e.launchUrl,companionProfileKey:n,companionConsumerKey:r,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:!e.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!e.metroNoInstallDeps&&void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:"ios"===e.platform?s.iosRuntime:s.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:s.projectRoot,profileKey:n,consumerKey:r}:void 0}}async function eb(e){if(e)try{await I(e)}catch{}}async function eU(e){try{await ed({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function eR(e,t){if(t.leaseId)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,daemonBaseUrl:t.daemon?.baseUrl,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode})}catch{}}function eE(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function eP(e){return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||e.metroKind)}function eT(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function eB(e,t,n){if(t.leaseId&&t.leaseBackend===n){let r=await eL(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n});if(r)return r}return await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n})}async function eL(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend})}catch(e){var r;if((r=e)instanceof f&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}async function ex(e,t){let n=await e.text(),r={};if(n.trim().length>0)try{r=JSON.parse(n)}catch(n){throw new f("COMMAND_FAILED",t.invalidJsonMessage,{status:e.status},n instanceof Error?n:void 0)}if(!e.ok)throw new f("UNAUTHORIZED",t.rejectedMessage,{status:e.status,response:r});return r}async function eM(e){return await eO({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:"connect"===e.command&&!e.flags.noLogin,env:e.env})}async function eO(e){let t=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:"none"};if(eX(e.flags.daemonAuthToken))return{flags:e.flags,source:"flag"};if(eX(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{flags:e.flags,source:"env"};if(!function(e,t){if("1"===t.AGENT_DEVICE_CLOUD_AUTH||"true"===t.AGENT_DEVICE_CLOUD_AUTH||eX(t.AGENT_DEVICE_CLOUD_BASE_URL))return!0;try{let t=new URL(e).hostname.toLowerCase();return"agent-device.dev"===t||t.endsWith(".agent-device.dev")}catch{return!1}}(e.flags.daemonBaseUrl,t))return{flags:e.flags,source:"none"};let n=await eK({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{flags:{...e.flags,daemonAuthToken:n.accessToken},source:"cli-session"};if(!e.allowInteractiveLogin){if(e.flags.noLogin)throw new f("UNAUTHORIZED","Remote daemon authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});throw eJ(e.command,t)}let r=await ej({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:"login"}}async function e$(e){let t=e.env??e.io?.env??process.env;if(eX(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:ez(t)};if(eX(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:t.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:ez(t)};let n=await eK({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{accessToken:n.accessToken,cloudBaseUrl:n.cloudBaseUrl};if(e.flags.noLogin)throw new f("UNAUTHORIZED","Cloud connection profile authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});let r=await ej({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io,commandLabel:"agent-device connect"});return{accessToken:r.accessToken,cloudBaseUrl:r.session.cloudBaseUrl}}async function ej(e){let n,o,s,a=e.env??e.io?.env??process.env,i=(d=a,u=e.io,n=u?.stdinIsTTY??process.stdin.isTTY,o=u?.stdoutIsTTY??process.stdout.isTTY,"true"!==(m=d).CI&&"true"!==m.GITHUB_ACTIONS&&"true"!==m.BUILDKITE&&n&&o?(p=d).SSH_TTY||p.SSH_CONNECTION||"true"===p.CODESPACES||p.GITPOD_WORKSPACE_ID||"true"===p.REMOTE_CONTAINERS?"device-code":"local-browser":"non-interactive");if("non-interactive"===i)throw eJ(e.commandLabel??"agent-device connect",a);let l=ez(a),c=await eq({baseUrl:l,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});var d,u,m,p,g,h,w=c;if(!eX(w.deviceCode)||!eX(w.userCode)||!eX(w.verificationUri))throw new f("COMMAND_FAILED","Cloud auth start returned an unusable response.");let v=c.verificationUriComplete??c.verificationUri,I="local-browser"===i?c.verificationUri:(g=c.verificationUri,h=c.userCode,(s=new URL(g)).searchParams.set("user_code",h),s.toString());"local-browser"===i?(eZ(e.io,`Opening ${c.verificationUri}...
|
|
3
|
-
`),await
|
|
1
|
+
import{pathToFileURL as e}from"node:url";import t from"node:fs";import n from"node:crypto";import r from"node:path";import{ensureCompanionTunnel as o,stopCompanionTunnel as s}from"./1974.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as a}from"./2301.js";import{REMOTE_CONFIG_FIELD_SPECS as i,resolveRemoteConfigProfile as l,resolveRemoteConfigPath as c}from"./208.js";import{asAppError as d,normalizeError as u,AppError as f}from"./9152.js";import{createRequestId as m,withDiagnosticsScope as p,getDiagnosticsMeta as g,flushDiagnosticsToSessionFile as h,emitDiagnostic as w}from"./7599.js";import{resolveDaemonPaths as v}from"./4012.js";import{stopMetroTunnel as I}from"./metro.js";import{runCmdStreaming as y,runCmd as A}from"./9818.js";import{formatSnapshotDiffText as _,formatScreenshotDiffText as S,printHumanError as C,printJson as D,formatCliOutput as k}from"./cli-output.js";import{parseSelectorChain as N}from"./7847.js";import{stringifyMaestroYamlDocuments as U,parseReplayScriptDetailed as b,formatMaestroPoint as R,readReplayScriptMetadata as E}from"./2403.js";import{resolveUserPath as P,expandUserHomePath as T}from"./3267.js";import{captureCliReaders as L,interactionCliReaders as B,replayCliReaders as x,batchCliReaders as M,appCliReaders as O,observabilityCliReaders as $,parseInstallSourceConfig as G,gestureCliReaders as V,reactNativeCliReaders as j,recordingCliReaders as K,selectorCliReaders as H,systemCliReaders as F,perfCliReaders as q}from"./6133.js";import{isCommandName as J,metroCliReaders as z,debuggingCliReaders as W}from"./5611.js";import{runCommand as Z}from"./command-surface.js";import{createLocalArtifactAdapter as Y}from"./7719.js";import{localCommandPolicy as X,createAgentDevice as Q}from"./123.js";import{isClientBackedCliCommandName as ee}from"./6088.js";import{mergeDefinedFlags as et,parseOptionValueFromSource as en,getConfigurableOptionSpecs as er,getOptionSpec as eo,usage as es,parseRawArgs as ea,usageForCommand as ei,finalizeParsedArgs as el}from"./args.js";import{readVersion as ec}from"./9671.js";import{createAgentDeviceClient as ed,sendToDaemon as eu}from"./9542.js";import{maybeRunUpgradeNotifier as ef}from"./113.js";let em={slug:"react-devtools-companion",runArg:a,displayName:"React DevTools companion"};async function ep(e){return await o({...e,definition:em,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 eg(e){return await s({...e,definition:em})}function eh(e){var n;let r,o=eA(e);if(!t.existsSync(o))return null;try{r=JSON.parse(t.readFileSync(o,"utf8"))}catch(t){return ek(e,t),null}return!(!(n=r)||"object"!=typeof n||Array.isArray(n))&&1===n.version&&"string"==typeof n.session&&"string"==typeof n.remoteConfigPath&&"string"==typeof n.remoteConfigHash&&(void 0===n.daemon||"object"==typeof n.daemon&&null!==n.daemon&&!Array.isArray(n.daemon))&&"string"==typeof n.tenant&&"string"==typeof n.runId&&(void 0===n.leaseId||"string"==typeof n.leaseId)&&(void 0===n.leaseBackend||"string"==typeof n.leaseBackend)&&"string"==typeof n.connectedAt&&"string"==typeof n.updatedAt?r:(ek(e),null)}function ew(e){let n=eA({stateDir:e.stateDir,session:e.state.session});t.mkdirSync(r.dirname(n),{recursive:!0}),eD(n,e.state),eD(e_(e.stateDir),{session:e.state.session})}function ev(e){return{baseUrl:function(e){if(!e)return;let t=new URL(e);for(let e of(t.username="",t.password="",[...t.searchParams.keys()]))/(auth|key|password|secret|token)/i.test(e)&&t.searchParams.delete(e);return t.toString().replace(/\/+$/,"")}(e.daemonBaseUrl),transport:e.daemonTransport,serverMode:e.daemonServerMode}}function eI(e){t.rmSync(eA(e),{force:!0});let n=e_(e.stateDir);eC(e.stateDir)===e.session&&t.rmSync(n,{force:!0})}function ey(e){try{return n.createHash("sha256").update(t.readFileSync(e)).digest("hex")}catch(t){throw new f("INVALID_ARGS",`Remote config file not found: ${e}`,{cause:t instanceof Error?t.message:String(t)})}}function eA(e){return r.join(e.stateDir,"remote-connections",`${function(e){let t=e.replaceAll(/[^a-zA-Z0-9._-]/g,"_");if(!t)return"default";if(t===e)return t;let r=n.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t}-${r}`}(e.session)}.json`)}function e_(e){return r.join(e,"remote-connections",".active-session.json")}function eS(e){let t=eC(e.stateDir);return t?eh({stateDir:e.stateDir,session:t}):null}function eC(e){let n=e_(e);if(t.existsSync(n))try{let e=JSON.parse(t.readFileSync(n,"utf8"));return"string"==typeof e.session?e.session:void 0}catch{return}}function eD(e,n){t.writeFileSync(e,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384}),t.chmodSync(e,384)}function ek(e,t){w({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eI(e)}let eN=i.map(e=>e.key);function eU(e){let t={};for(let n of eN){let r=e[n];void 0!==r&&(t[n]=r)}return t}let eb=new Set(["connect","connection","close","disconnect","metro","session"]),eR=new Set(["open"]);async function eE(e){let t,n,{command:r,flags:o,client:s}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let a=v(o.stateDir).baseDir,i=l({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),c={...eU(i.profile),...o,remoteConfig:i.resolvedPath},d=eh({stateDir:a,session:c.session??"default"});if(d&&d.remoteConfigPath!==i.resolvedPath)throw new f("INVALID_ARGS","A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.",{session:d.session,activeRemoteConfig:d.remoteConfigPath,requestedRemoteConfig:i.resolvedPath});let u=d??function(e,t){if(!e.tenant)throw new f("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new f("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new f("INVALID_ARGS","remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let n=new Date().toISOString();return{version:1,session:e.session??"default",remoteConfigPath:t,remoteConfigHash:ey(t),daemon:ev(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??ex(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(c,i.resolvedPath),m={...c,session:u.session},p=function(e,t){if(e)return eO(e,t)?e:void 0}(u.runtime,m.platform)??e.runtime,g=u,h=!d;if(w=r,!eb.has(w)){let e=u.leaseBackend??function(e,t){let n=ex(e);if(n)return n;throw new f("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var w,I,y,A,_,S=u,C=o,D=e;if(S.leaseBackend&&S.leaseBackend!==D)throw new f("INVALID_ARGS","Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.",{session:S.session,leaseBackend:S.leaseBackend});if(S.platform&&C.platform&&S.platform!==C.platform)throw new f("INVALID_ARGS","Active remote connection is already bound to a different platform. Re-run connect --force to replace it.",{session:S.session,platform:S.platform});if(S.target&&C.target&&S.target!==C.target)throw new f("INVALID_ARGS","Active remote connection is already bound to a different target. Re-run connect --force to replace it.",{session:S.session,target:S.target});let t=await e$(s,g,e);m.leaseId=t.leaseId,m.leaseBackend=e,m.platform=g.platform??m.platform,m.target=g.target??m.target,(g.leaseId!==t.leaseId||g.leaseBackend!==e)&&(g={...g,leaseId:t.leaseId,leaseBackend:e,platform:g.platform??o.platform,target:g.target??o.target,updatedAt:new Date().toISOString()},h=!0)}if(I=r,y=e.batchSteps,(eR.has(I)||"batch"===I&&y&&y.some(e=>{let t=e.command.trim().toLowerCase();return eR.has(t)&&void 0===e.runtime}))&&eM(m)&&(!g.leaseId&&m.leaseId&&(g={...g,leaseId:m.leaseId,leaseBackend:m.leaseBackend}),e.forceRuntimePrepare||!p||!eO(p,m.platform))){if(!g.leaseId)throw new f("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await eP(m,s,u.remoteConfigPath,u.session,{tenantId:u.tenant,runId:u.runId,leaseId:g.leaseId});p=e.runtime;let o=(A=g.metro,_=e.cleanup,A?.projectRoot!==_?.projectRoot||A?.profileKey!==_?.profileKey||A?.consumerKey!==_?.consumerKey);t=o?g.metro:void 0,n=o?e.cleanup:void 0,g={...g,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},h=!0}if(h)try{ew({stateDir:a,state:g})}catch(e){throw await eT(n),e}return await eT(t),{flags:{...m,session:g.session,leaseId:g.leaseId,leaseBackend:g.leaseBackend,platform:g.platform??m.platform,target:g.target??m.target},runtime:p}}async function eP(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new f("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new f("INVALID_ARGS","Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.");let s=await t.metro.prepare({projectRoot:e.metroProjectRoot,kind:function(e){if(void 0!==e){if("auto"===e||"react-native"===e||"expo"===e)return e;throw new f("INVALID_ARGS","metro prepare --kind must be auto, react-native, or expo")}}(e.metroKind),publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:o,launchUrl:e.launchUrl,companionProfileKey:n,companionConsumerKey:r,port:e.metroPreparePort,listenHost:e.metroListenHost,statusHost:e.metroStatusHost,startupTimeoutMs:e.metroStartupTimeoutMs,probeTimeoutMs:e.metroProbeTimeoutMs,reuseExisting:!e.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!e.metroNoInstallDeps&&void 0,runtimeFilePath:e.metroRuntimeFile});return{runtime:"ios"===e.platform?s.iosRuntime:s.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:s.projectRoot,profileKey:n,consumerKey:r}:void 0}}async function eT(e){if(e)try{await I(e)}catch{}}async function eL(e){try{await eg({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function eB(e,t){if(t.leaseId)try{await e.leases.release({tenant:t.tenant,runId:t.runId,leaseId:t.leaseId,daemonBaseUrl:t.daemon?.baseUrl,daemonTransport:t.daemon?.transport,daemonServerMode:t.daemon?.serverMode})}catch{}}function ex(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function eM(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function eO(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function e$(e,t,n){if(t.leaseId&&t.leaseBackend===n){let r=await eG(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:n});if(r)return r}return await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:n})}async function eG(e,t,n){try{return await e.leases.heartbeat({tenant:n.tenant,runId:n.runId,leaseId:t,leaseBackend:n.leaseBackend})}catch(e){var r;if((r=e)instanceof f&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}async function eV(e,t){let n=await e.text(),r={};if(n.trim().length>0)try{r=JSON.parse(n)}catch(n){throw new f("COMMAND_FAILED",t.invalidJsonMessage,{status:e.status},n instanceof Error?n:void 0)}if(!e.ok)throw new f("UNAUTHORIZED",t.rejectedMessage,{status:e.status,response:r});return r}async function ej(e){return await eK({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:"connect"===e.command&&!e.flags.noLogin,env:e.env})}async function eK(e){let t=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:"none"};if(e8(e.flags.daemonAuthToken))return{flags:e.flags,source:"flag"};if(e8(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{flags:e.flags,source:"env"};if(!function(e,t){if("1"===t.AGENT_DEVICE_CLOUD_AUTH||"true"===t.AGENT_DEVICE_CLOUD_AUTH||e8(t.AGENT_DEVICE_CLOUD_BASE_URL))return!0;try{let t=new URL(e).hostname.toLowerCase();return"agent-device.dev"===t||t.endsWith(".agent-device.dev")}catch{return!1}}(e.flags.daemonBaseUrl,t))return{flags:e.flags,source:"none"};let n=await ez({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{flags:{...e.flags,daemonAuthToken:n.accessToken},source:"cli-session"};if(!e.allowInteractiveLogin){if(e.flags.noLogin)throw new f("UNAUTHORIZED","Remote daemon authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});throw eX(e.command,t)}let r=await eF({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:"login"}}async function eH(e){let t=e.env??e.io?.env??process.env;if(e8(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:eQ(t)};if(e8(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:t.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:eQ(t)};let n=await ez({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});if(n)return{accessToken:n.accessToken,cloudBaseUrl:n.cloudBaseUrl};if(e.flags.noLogin)throw new f("UNAUTHORIZED","Cloud connection profile authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});let r=await eF({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io,commandLabel:"agent-device connect"});return{accessToken:r.accessToken,cloudBaseUrl:r.session.cloudBaseUrl}}async function eF(e){let n,o,s,a=e.env??e.io?.env??process.env,i=(d=a,u=e.io,n=u?.stdinIsTTY??process.stdin.isTTY,o=u?.stdoutIsTTY??process.stdout.isTTY,"true"!==(m=d).CI&&"true"!==m.GITHUB_ACTIONS&&"true"!==m.BUILDKITE&&n&&o?(p=d).SSH_TTY||p.SSH_CONNECTION||"true"===p.CODESPACES||p.GITPOD_WORKSPACE_ID||"true"===p.REMOTE_CONTAINERS?"device-code":"local-browser":"non-interactive");if("non-interactive"===i)throw eX(e.commandLabel??"agent-device connect",a);let l=eQ(a),c=await eY({baseUrl:l,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});var d,u,m,p,g,h,w=c;if(!e8(w.deviceCode)||!e8(w.userCode)||!e8(w.verificationUri))throw new f("COMMAND_FAILED","Cloud auth start returned an unusable response.");let v=c.verificationUriComplete??c.verificationUri,I="local-browser"===i?c.verificationUri:(g=c.verificationUri,h=c.userCode,(s=new URL(g)).searchParams.set("user_code",h),s.toString());"local-browser"===i?(e1(e.io,`Opening ${c.verificationUri}...
|
|
3
|
+
`),await e0(v,e.io)):e1(e.io,`Open this URL on your machine:
|
|
4
4
|
${I}
|
|
5
5
|
|
|
6
6
|
Waiting for approval for 10 minutes...
|
|
7
|
-
`);let y=await
|
|
8
|
-
`,{mode:384});try{t.chmodSync(n,384)}catch{}}({stateDir:e.stateDir,session:S}),{accessToken:y.accessToken,expiresAt:y.expiresAt,session:S}}function
|
|
7
|
+
`);let y=await eZ({cloudBaseUrl:l,deviceCode:c.deviceCode,expiresIn:c.expiresIn,interval:c.interval,fetchImpl:e.io?.fetch,now:e.io?.now}),A=y.cliSession?.refreshCredential??y.cliSession?.refreshToken;if(!e8(y.accessToken)||!e8(A))throw new f("UNAUTHORIZED","Device authorization did not return CLI credentials.");let _=new Date(e.io?.now?.()??Date.now()).toISOString(),S={version:1,id:y.cliSession?.id??`cli-${Date.now().toString(36)}`,cloudBaseUrl:l,workspaceId:y.cliSession?.workspaceId,accountId:y.cliSession?.accountId,name:y.cliSession?.name,refreshCredential:A,createdAt:_,expiresAt:y.cliSession?.expiresAt};return function(e){let n=eJ(e.stateDir);t.mkdirSync(r.dirname(n),{recursive:!0,mode:448}),t.writeFileSync(n,`${JSON.stringify(e.session,null,2)}
|
|
8
|
+
`,{mode:384});try{t.chmodSync(n,384)}catch{}}({stateDir:e.stateDir,session:S}),{accessToken:y.accessToken,expiresAt:y.expiresAt,session:S}}function eq(e){let n=eJ(e.stateDir);if(!t.existsSync(n))return null;try{let e=JSON.parse(t.readFileSync(n,"utf8"));if(1!==e.version||!e8(e.id)||!e8(e.cloudBaseUrl)||!e8(e.refreshCredential)||!e8(e.createdAt))return null;return e}catch{return null}}function eJ(e){return r.join(e,"auth","cli-session.json")}async function ez(e){let t=eq({stateDir:e.stateDir});return!t||e3(t.expiresAt,e.io?.now)?null:{accessToken:(await eW({session:t,flags:e.flags,env:e.env,io:e.io})).accessToken,cloudBaseUrl:eQ(e.env,t.cloudBaseUrl)}}async function eW(e){let t=eQ(e.env,e.session.cloudBaseUrl),n=await eY({baseUrl:t,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(e8(n.accessToken))return{accessToken:n.accessToken,expiresAt:n.expiresAt};if("revoked"===n.status||"revoked"===n.error)throw new f("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});throw new f("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 eZ(e){let t=e.now??Date.now,n=Math.min((e.expiresIn??600)*1e3,6e5),r=t()+n,o=Math.max(1e3,(e.interval??5)*1e3);for(;t()<r;){let t=await eY({baseUrl:e.cloudBaseUrl,pathName:"/api/control-plane/device-auth/poll",body:{deviceCode:e.deviceCode},fetchImpl:e.fetchImpl});if("approved"===t.status||e8(t.accessToken))return t;if("slow_down"===t.status||"slow_down"===t.error)o+=1e3;else if("authorization_pending"!==t.status&&"authorization_pending"!==t.error)throw new f("UNAUTHORIZED","Device authorization was not approved.",{status:t.status,error:t.error});await e2(o)}throw new f("TIMEOUT","Device authorization expired before approval.")}async function eY(e){let t=e.fetchImpl??fetch,n=await t(new URL(e.pathName,e.baseUrl),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e.body),signal:AbortSignal.timeout(15e3)});return await eV(n,{invalidJsonMessage:`Cloud auth endpoint returned invalid JSON (${n.status}).`,rejectedMessage:"Cloud auth endpoint rejected the request."})}function eX(e,t){let n=eQ(t);return new f("UNAUTHORIZED",`${e} cannot perform interactive login in CI or a non-interactive shell.`,{hint:`Create a service/API token: ${new URL("/api-keys",n).toString()} Then set AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_...`})}function eQ(e,t){let n=e.AGENT_DEVICE_CLOUD_BASE_URL??t??"https://cloud.agent-device.dev";try{return new URL(n).toString().replace(/\/+$/,"")}catch(e){throw new f("INVALID_ARGS","Invalid AGENT_DEVICE_CLOUD_BASE_URL.",{cloudBaseUrl:n},e instanceof Error?e:void 0)}}async function e0(e,t){if(t?.openBrowser)return void await t.openBrowser(e);let n=process.platform;try{"darwin"===n?await A("open",[e],{allowFailure:!0,timeoutMs:5e3}):"win32"===n?await A("cmd",["/c","start","",e],{allowFailure:!0,timeoutMs:5e3}):await A("xdg-open",[e],{allowFailure:!0,timeoutMs:5e3})}catch{e1(t,`Open this URL on your machine:
|
|
9
9
|
${e}
|
|
10
|
-
`)}}function
|
|
11
|
-
`,{mode:384});try{t.chmodSync(i,384)}catch{}return i}({stateDir:e.stateDir,profile:s}),cwd:e.cwd,env:e.env});return{flags:{...
|
|
12
|
-
`))}let e8=async({flags:e,client:t})=>{var r,o,s,a;let i=v(e.stateDir).baseDir,c=e.remoteConfig?function(e){if(!e.remoteConfig)throw new f("INVALID_ARGS","connect requires --remote-config <path>.");let t=l({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await e0({flags:e,stateDir:i,cwd:process.cwd(),env:process.env}),d=c.flags,u=d.tenant,m=d.runId;if(!u)throw new f("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!m)throw new f("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!d.daemonBaseUrl)throw new f("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let p=d.session?null:ev({stateDir:i}),g=d.session??p?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${n.randomBytes(3).toString("hex")}`;if(!eu({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${n.randomBytes(2).toString("hex")}`}(i),h=eg(c.remoteConfigPath),w=em(d),I=p?.session===g?p:eu({stateDir:i,session:g});if(I&&(r=I,o={flags:d,session:g,remoteConfigPath:c.remoteConfigPath,remoteConfigHash:h,desiredLeaseBackend:eE(d),daemon:w},r.remoteConfigPath!==o.remoteConfigPath||r.remoteConfigHash!==o.remoteConfigHash||r.session!==o.session||r.tenant!==o.flags.tenant||r.runId!==o.flags.runId||void 0!==o.desiredLeaseBackend&&r.leaseBackend!==o.desiredLeaseBackend||void 0!==o.flags.platform&&r.platform!==o.flags.platform||void 0!==o.flags.target&&r.target!==o.flags.target||(s=r.daemon,a=o.daemon,(s?.baseUrl??void 0)!==(a?.baseUrl??void 0)||(s?.transport??void 0)!==(a?.transport??void 0)||(s?.serverMode??void 0)!==(a?.serverMode??void 0)))&&!d.force)throw new f("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:g,remoteConfig:I.remoteConfigPath});let y=new Date().toISOString(),A={version:1,session:g,remoteConfigPath:c.remoteConfigPath,remoteConfigHash:h,daemon:w,tenant:u,runId:m,leaseId:I&&!d.force?I.leaseId:void 0,leaseBackend:I&&!d.force?I.leaseBackend:eE(d),platform:d.platform??(I&&!d.force?I.platform:void 0),target:d.target??(I&&!d.force?I.target:void 0),runtime:I&&!d.force?I.runtime:void 0,metro:I&&!d.force?I.metro:void 0,connectedAt:I&&!d.force?I.connectedAt:y,updatedAt:y};ef({stateDir:i,state:A}),I&&d.force&&(await eb(I.metro),await eU({stateDir:i,state:I}),await eR(t,I));let _=e5(A),S=function(e,t){if(!t.runtime&&(eP(e)||te(t.remoteConfigPath)))return e6(t.remoteConfigPath)}(d,A);return e3(d,tt(A,S),()=>[`Connected remote session "${g}" tenant "${u}" run "${m}" ${A.leaseId?`lease ${A.leaseId}`:"lease pending"}`,_?.message,S?.message].filter(e=>!!e).join("\n")),!0},e2=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=e7(e);if(!o)return e4(e,n),!0;let s=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await eb(o.metro),await eU({stateDir:r,state:o});let a=!1;if(o.leaseId)try{a=(await t.leases.release({tenant:o.tenant,runId:o.runId,leaseId:o.leaseId})).released}catch{}return ep({stateDir:r,session:s}),e3(e,{connected:!1,session:s,released:a},()=>`Disconnected remote session "${s}".`),!0},e9=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new f("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=e7(t);if(!r)return e4(t,n),!0;let o=e5(r),s=function(e){if(!e.runtime&&te(e.remoteConfigPath))return e6(e.remoteConfigPath)}(r);return e3(t,tt(r,s),()=>[`Connected remote session "${r.session}".`,`tenant=${r.tenant} runId=${r.runId} leaseId=${r.leaseId??"pending"} backend=${r.leaseBackend??"pending"}`,`remoteConfig=${r.remoteConfigPath}`,r.runtime?"metro=prepared":"metro=not-prepared",o?.message,s?.message].filter(e=>!!e).join("\n")),!0};function e7(e){let t=e.session??"default",n=v(e.stateDir).baseDir;return{session:t,stateDir:n,state:eu({stateDir:n,session:t})??(e.session?null:ev({stateDir:n}))}}function e4(e,t){e3(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function e5(e){if(!e.leaseId)return{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."+(void 0===e.platform&&void 0===e.leaseBackend?" Add --platform ios|android if the profile does not set a platform.":"")}}function e6(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 te(e){try{let t=l({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function tt(e,t){let r=e5(e);return{connected:!0,session:e.session,tenant:e.tenant,runId:e.runId,leaseAllocated:!!e.leaseId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,platform:e.platform,target:e.target,remoteConfig:e.remoteConfigPath,remoteConfigHash:e.remoteConfigHash,daemonBaseUrlFingerprint:function(e){if(e)return n.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...r?{leasePreparation:r}:{},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let tn=async({positionals:e,flags:n})=>{let r=e[0]??"status",o=v(n.stateDir).baseDir;if("status"===r){var s;let e,t=(e=eG({stateDir:(s={stateDir:o}).stateDir}))?{authenticated:!0,source:"cli-session",sessionId:e.id,cloudBaseUrl:e.cloudBaseUrl,workspaceId:e.workspaceId,accountId:e.accountId,name:e.name,createdAt:e.createdAt,expiresAt:e.expiresAt,expired:eY(e.expiresAt,s.now)}:{authenticated:!1,source:"none"};return e3(n,t,()=>{var e;return(e=t).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("\n"):"Not authenticated."}),!0}if("login"===r){let e=await ej({stateDir:o,flags:n,commandLabel:"agent-device auth login"});return e3(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("logout"===r){let e,r=(e=eV({stateDir:o}.stateDir),!!t.existsSync(e)&&(t.rmSync(e,{force:!0}),!0));return e3(n,{authenticated:!1,removed:r},()=>r?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new f("INVALID_ARGS","auth accepts only: status, login, logout")},tr=new Set(["id","text","label"]),to=new Set(["enabled","selected"]),ts={open:function(e){var t,n,r;let o,s,a,[i,l]=e.positionals;if(!i)return{kind:"unsupported",message:"open requires an app id or URL"};if(tp(i))return{kind:"commands",commands:[{openLink:i}]};let c=(t=e,n=i,(a=(r=t,o=r.flags?.launchArgs,s={},r.flags?.relaunch===!0&&(s.stopApp=!0),r.flags?.clearAppState===!0&&(s.clearState=!0),Array.isArray(o)&&o.length>0&&(s.launchArguments=o),Object.keys(s).length>0?s:void 0))?{launchApp:{appId:n,...a}}:"launchApp");return l&&tp(l)?{kind:"config",appId:i,commands:[c,{openLink:l}]}:l?{kind:"unsupported",message:"open with a non-URL second argument is unsupported"}:{kind:"config",appId:i,commands:[c]}},click:ta,press:ta,longpress:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"longpress requires a target"};let r=tc(t,n);return r?{kind:"commands",commands:[{longPressOn:r}],warnings:(function(e){let[t,n,r]=e.positionals,o=tg(t)&&tg(n)?r:n;return o&&tg(o)?[Number(o)]:[]})(e).map(ti)}:{kind:"unsupported",message:"longpress target is not Maestro-compatible"}},fill:function(e){let[t,n]=e.positionals;if(!t||void 0===n)return{kind:"unsupported",message:"fill requires a target and text"};let r=tc(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"}},type:function(e){var t;let[n]=e.positionals;if(void 0===n)return{kind:"unsupported",message:"type requires text"};let r=0!==(t=n).length&&[...t].every(e=>"\b"===e)?t.length:null;return null!==r?{kind:"commands",commands:[{eraseText:r}]}:{kind:"commands",commands:[{inputText:n}]}},keyboard:function(e){let[t]=e.positionals;return"dismiss"===t?{kind:"commands",commands:["hideKeyboard"]}:"enter"===t||"return"===t?{kind:"commands",commands:[{pressKey:"Enter"}]}:{kind:"unsupported",message:`keyboard ${t??""}`.trim()}},back:()=>({kind:"commands",commands:["back"]}),wait:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"wait requires a target or duration"};if(tg(t))return{kind:"commands",commands:[{waitForAnimationToEnd:{timeout:Number(t)}}],warnings:["wait <ms> exports as waitForAnimationToEnd and may return before the full duration"]};if("text"===t&&n)return{kind:"commands",commands:[{extendedWaitUntil:{visible:n,timeout:tf(e,17e3)}}]};let r=td(t);return r?{kind:"commands",commands:[{extendedWaitUntil:{visible:r,timeout:tf(e,17e3)}}]}:{kind:"unsupported",message:"wait selector is not Maestro-compatible"}},find:function(e){let[t,n,r]=e.positionals;return"text"===t&&n&&r?"exists"===r?{kind:"commands",commands:[{assertVisible:n}]}:"missing"===r||"not-exists"===r?{kind:"commands",commands:[{assertNotVisible:n}]}:{kind:"unsupported",message:`find text assertion "${r}" is unsupported`}:{kind:"unsupported",message:"only find text <query> exists|missing exports to Maestro"}},screenshot:function(e){let[t]=e.positionals;return t?{kind:"commands",commands:[{takeScreenshot:t}]}:{kind:"unsupported",message:"screenshot requires an output path"}},scroll:function(e){let[t]=e.positionals;return t&&"down"!==t?{kind:"unsupported",message:`scroll ${t} is not exported yet`}:{kind:"commands",commands:["scroll"]}},swipe:function(e){var t,n;let r,o=function(e){let[t,n,r,o,s]=e.positionals;if(tg(t)&&tg(n)&&tg(r)&&tg(o))return{start:R(t,n),end:R(r,o),...s&&tg(s)?{duration:Number(s)}:{}}}(e);if(!o)return{kind:"unsupported",message:"only coordinate swipe exports to Maestro"};let s=(t=e,Number.isInteger(r=t.flags?.count??1)&&r>=1?r:null);if(null===s)return{kind:"unsupported",message:"swipe count must be a positive integer"};let a=(n=e,n.flags?.pauseMs!==void 0?"swipe --pause-ms has no Maestro equivalent":n.flags?.pattern&&"one-way"!==n.flags.pattern?"swipe ping-pong pattern has no Maestro equivalent":void 0);return a?{kind:"unsupported",message:a}:{kind:"commands",commands:Array.from({length:s},()=>({swipe:o}))}}};function ta(e){var t,n,r,o,s;let a,i,[l,c]=e.positionals;if(!l)return{kind:"unsupported",message:`${e.command} requires a target`};let d=tc(l,c);if(!d)return{kind:"unsupported",message:"tap target is not Maestro-compatible"};let u=(a=(n=t=e,n.flags?.jitterPx!==void 0?"tap --jitter-px has no Maestro equivalent":n.flags?.clickButton&&"primary"!==n.flags.clickButton?`tap --button ${n.flags.clickButton} has no Maestro equivalent`:void 0))?{ok:!1,message:a}:{ok:!0,options:(r=t,i={},"number"==typeof r.flags?.count&&r.flags.count>1&&(i.repeat=r.flags.count),"number"==typeof r.flags?.intervalMs&&r.flags.intervalMs>0&&(i.delay=r.flags.intervalMs),i)};return u.ok?e.flags?.doubleTap===!0?{kind:"commands",commands:[{doubleTapOn:d}],warnings:tl(e,"doubleTapOn")}:"number"==typeof e.flags?.holdMs?{kind:"commands",commands:[{longPressOn:d}],warnings:[ti(e.flags.holdMs),...tl(e,"longPressOn")]}:{kind:"commands",commands:[(o=d,0===Object.keys(s=u.options).length?{tapOn:o}:"string"==typeof o?{tapOn:{text:o,...s}}:o&&"object"==typeof o&&!Array.isArray(o)?{tapOn:{...o,...s}}:{tapOn:o})]}:{kind:"unsupported",message:u.message}}function ti(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function tl(e,t){let n=[];return"number"==typeof e.flags?.count&&e.flags.count>1&&n.push(`tap --count ${e.flags.count} is not represented by Maestro ${t}`),"number"==typeof e.flags?.intervalMs&&e.flags.intervalMs>0&&n.push(`tap --interval-ms ${e.flags.intervalMs} is not represented by Maestro ${t}`),n}function tc(e,t){return tg(e)&&tg(t)?{point:R(e,t)}:e.startsWith("@")?null:td(e)}function td(e){let t;try{t=ei(e)}catch{return e.includes("=")||e.includes("||")?null:e}let n=function(e){if(e.length<=1)return null;let t=e.flatMap(e=>1===e.terms.length&&tr.has(e.terms[0].key)?[e.terms[0].value]:[]);if(t.length!==e.length||0===t.length)return null;let n=t[0];return"string"!=typeof n?null:t.every(e=>e===n)?n:null}(t.selectors);return null!==n?n:1!==t.selectors.length?null:function(e){let t={};for(let o of e.terms){var n,r;if(n=t,r=o,tr.has(r.key)?"string"!=typeof r.value||!!n.id||!!n.text||!!n.label||(n[r.key]=r.value,!!0):!to.has(r.key)||"boolean"!=typeof r.value||(n[r.key]=r.value,!!0))return null}return Object.keys(t).length>0?t:null}(t.selectors[0])}function tu(e,t,n,r){for(let o of t??[])e.warnings.push({line:r,action:tm(n),message:o})}function tf(e,t){let n=e.positionals.at(-1);return n&&tg(n)?Number(n):t}function tm(e){return[e.command,...e.positionals??[]].join(" ").trim()}function tp(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function tg(e){return void 0!==e&&Number.isFinite(Number(e))}let th=async e=>{let{positionals:t}=e;return"export"!==t[0]?function({positionals:e,flags:t}){if(e.length>1)throw new f("INVALID_ARGS","replay accepts exactly one input path: replay <path>");if(void 0!==t.replayExportFormat||void 0!==t.out)throw new f("INVALID_ARGS","replay --format/--out are only supported with replay export.");return!1}(e):await tw(e)};async function tw({positionals:e,flags:n}){let o;var s,a=e,i=n;if(a.length>2)throw new f("INVALID_ARGS","replay export accepts exactly one input path: replay export <file.ad>");if(i.replayUpdate)throw new f("INVALID_ARGS","replay export does not support --update.");if(i.replayMaestro)throw new f("INVALID_ARGS","replay export reads .ad files; omit --maestro.");if(i.replayEnv?.length)throw new f("INVALID_ARGS","replay export does not evaluate --env substitutions.");let l=i.replayExportFormat??"maestro";if("maestro"!==l)throw new f("INVALID_ARGS",`Unsupported replay export format: ${l}`);let c=e[1];if(!c)throw new f("INVALID_ARGS","replay export requires an input path.");let d=P(c),u=function(e,t={}){var n,r,o,s;let a={config:(n=t.metadata,n?.env&&Object.keys(n.env).length>0?{env:n.env}:{}),warnings:[],unsupported:[]},i=[];for(let[n,o]of e.entries()){let e=t.actionLines?.[n]??n+1,s=(r=o,ts[r.command]?.(r)??{kind:"unsupported",message:`${r.command} has no Maestro equivalent`});switch(s.kind){case"commands":i.push(...s.commands),tu(a,s.warnings,o,e);break;case"config":(function(e,t,n,r){if(!e.config.appId){e.config.appId=t;return}e.config.appId!==t&&e.unsupported.push({line:r,action:tm(n),message:`multiple app ids cannot be represented in one Maestro config (${e.config.appId} vs ${t})`})})(a,s.appId,o,e),i.push(...s.commands),tu(a,s.warnings,o,e);break;case"unsupported":a.unsupported.push({line:e,action:tm(o),message:s.message})}}if(a.unsupported.length>0)throw new f("INVALID_ARGS",`Cannot export replay to Maestro YAML: unsupported .ad action ${a.unsupported.map(e=>`line ${e.line} (${e.action}): ${e.message}`).join("; ")}.`,{unsupported:a.unsupported});return{yaml:(o=a.config,s=i,b(Object.keys(o).length>0?[o,s]:[s])),warnings:a.warnings}}((o=U(s=t.readFileSync(d,"utf8"))).actions,{actionLines:o.actionLines,metadata:E(s)}),m="string"==typeof n.out?P(n.out):void 0;for(let e of(m&&(t.mkdirSync(r.dirname(m),{recursive:!0}),t.writeFileSync(m,u.yaml)),u.warnings))process.stderr.write(`Warning: line ${e.line}: ${e.message}
|
|
13
|
-
`);return
|
|
14
|
-
`)
|
|
15
|
-
`),process.exit(0));let
|
|
16
|
-
`),process.exit(0));let t=
|
|
17
|
-
`),process.exit(1)}
|
|
18
|
-
`),process.exit(1));let{command:
|
|
19
|
-
`),!0}({command:er,positionals:es,flags:q,daemonPaths:K}))return;if(B=er,"auth"!==B&&"connection"!==B&&(q=(await eM({command:er,flags:q,stateDir:K.baseDir,env:process.env})).flags),q.remoteConfig&&(L=er,!tE.has(L))){let t=eo(a(q,r),{transport:n.sendToDaemon}),o=await ek({command:er,flags:q,client:t,runtime:r,batchSteps:e,forceRuntimePrepare:function(e){for(let t of tR)if(e.has(t))return!0;return!1}(el)});q=o.flags,r=o.runtime}x={command:er,flags:q,runtime:r,explicitFlagKeys:el,hadConnectionDefaults:!!F},!("open"===x.command&&!x.runtime&&!x.flags.bundleUrl&&!x.flags.metroHost&&!x.flags.metroPort&&!x.flags.remoteConfig&&!x.hadConnectionDefaults&&((M=x.explicitFlagKeys).has("daemonBaseUrl")||M.has("daemonTransport")||M.has("tenant")||M.has("sessionIsolation")||M.has("runId")||M.has("leaseId")||M.has("leaseBackend")))||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.\n");let i=q.daemonBaseUrl;ec=!ei||q.json||i?null:function(e){try{let n=t.existsSync(e)?t.statSync(e).size:0,r=!1,o=setInterval(()=>{if(!r&&t.existsSync(e))try{let r=t.statSync(e);if(r.size<n&&(n=0),r.size<=n)return;let o=t.openSync(e,"r");try{let e=Buffer.alloc(r.size-n);t.readSync(o,e,0,e.length,n),n=r.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{t.closeSync(o)}}catch{}},200);return()=>{r=!0,clearInterval(o)}}catch{return null}}(K.logPath);let l=eo(a(q,r),{transport:function(e){let{command:t,flags:n,transport:r}=e;return"test"!==t||n.json?r:async e=>await r({...e,meta:{...e.meta,requestProgress:"replay-test"}})}({command:er,flags:q,transport:n.sendToDaemon})});if("batch"===er){if(!e)throw new f("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,input:j.lockPolicy&&void 0===G.platform?{...e.input}:tN(e.input,{policyOverrides:q,configuredPlatform:q.platform,configuredSession:q.session,inheritedPlatform:q.platform})}));if(await t_({command:er,positionals:es,flags:{...q,batchSteps:t},client:l}))return}else if("runtime"===er)throw new f("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 t_({command:er,positionals:es,flags:q,client:l}))return;throw new f("INVALID_ARGS",`Unknown command: ${er}`)}catch(r){let e=d(r),n=u(e,{diagnosticId:g().diagnosticId,logPath:h({force:!0})??void 0});if("close"===er&&"COMMAND_FAILED"===(O=e).code&&(O.details?.kind==="daemon_startup_failed"||O.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof O.details?.infoPath||"string"==typeof O.details?.lockPath))){q.json&&k({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(q.json)k({success:!1,error:n});else if(C(n,{showDetails:ei}),ei)try{let e=K.logPath;if(t.existsSync(e)){let n=t.readFileSync(e,"utf8").split("\n"),r=n.slice(Math.max(0,n.length-200)).join("\n");r.trim().length>0&&process.stderr.write(`
|
|
10
|
+
`)}}function e1(e,t){(e?.stderr??process.stderr).write(t)}function e3(e,t){if(!e)return!1;let n=Date.parse(e);return!Number.isFinite(n)||n<=(t?.()??Date.now())}function e8(e){return"string"==typeof e&&e.trim().length>0}async function e2(e){await new Promise(t=>setTimeout(t,e))}async function e4(e){let o=await eH({stateDir:e.stateDir,flags:e.flags,env:e.env,io:{env:e.env,fetch:e.fetchImpl}}),s=await e5({cloudBaseUrl:o.cloudBaseUrl,accessToken:o.accessToken,fetchImpl:e.fetchImpl}),a=function(e){try{return l(e)}catch(n){let t=d(n);throw new f("COMMAND_FAILED","Cloud connection profile returned invalid remote config.",{generatedConfigPath:e.configPath,cause:t.message},t)}}({configPath:function(e){var o;let s=function e(t){return Array.isArray(t)?t.map(e):t&&"object"==typeof t?Object.fromEntries(Object.entries(t).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([t,n])=>[t,e(n)])):t}(e.profile),a=r.join(e.stateDir,"remote-connections","generated");t.mkdirSync(a,{recursive:!0,mode:448});let i=r.join(a,`cloud-${(o=s,n.createHash("sha256").update(JSON.stringify(o)).digest("hex").slice(0,16))}.json`);t.writeFileSync(i,`${JSON.stringify(s,null,2)}
|
|
11
|
+
`,{mode:384});try{t.chmodSync(i,384)}catch{}return i}({stateDir:e.stateDir,profile:s}),cwd:e.cwd,env:e.env});return{flags:{...eU(a.profile),...e.flags,remoteConfig:a.resolvedPath,daemonAuthToken:o.accessToken},remoteConfigPath:a.resolvedPath}}async function e5(e){let t=e.fetchImpl??fetch,n=await t(new URL("/api/control-plane/connection-profile",e.cloudBaseUrl),{method:"GET",headers:{authorization:`Bearer ${e.accessToken}`},signal:AbortSignal.timeout(15e3)});var r=await eV(n,{invalidJsonMessage:`Cloud connection profile endpoint returned invalid JSON (${n.status}).`,rejectedMessage:"Cloud connection profile endpoint rejected the request."});if(!r||"object"!=typeof r||Array.isArray(r))throw new f("COMMAND_FAILED","Cloud connection profile response is invalid.");let o=r.connection;if(!o||"object"!=typeof o)throw new f("COMMAND_FAILED","Cloud connection profile response is missing profile.");if(void 0!==o.remoteConfigProfile){var s=o.remoteConfigProfile;if(!s||"object"!=typeof s||Array.isArray(s))throw new f("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is invalid.");if(0===Object.keys(s).length)throw new f("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is empty.");return s}throw new f("COMMAND_FAILED","Cloud connection profile did not include remoteConfigProfile.")}function e6(e,t,n){var r;if(e.json)return void D({success:!0,data:t});let o=n?.();o&&(r=o,process.stdout.write(r.endsWith("\n")?r:`${r}
|
|
12
|
+
`))}let e9=async({flags:e,client:t})=>{var r,o,s,a;let i=v(e.stateDir).baseDir,c=e.remoteConfig?function(e){if(!e.remoteConfig)throw new f("INVALID_ARGS","connect requires --remote-config <path>.");let t=l({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await e4({flags:e,stateDir:i,cwd:process.cwd(),env:process.env}),d=c.flags,u=d.tenant,m=d.runId;if(!u)throw new f("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!m)throw new f("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!d.daemonBaseUrl)throw new f("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let p=d.session?null:eS({stateDir:i}),g=d.session??p?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${n.randomBytes(3).toString("hex")}`;if(!eh({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${n.randomBytes(2).toString("hex")}`}(i),h=ey(c.remoteConfigPath),w=ev(d),I=p?.session===g?p:eh({stateDir:i,session:g});if(I&&(r=I,o={flags:d,session:g,remoteConfigPath:c.remoteConfigPath,remoteConfigHash:h,desiredLeaseBackend:ex(d),daemon:w},r.remoteConfigPath!==o.remoteConfigPath||r.remoteConfigHash!==o.remoteConfigHash||r.session!==o.session||r.tenant!==o.flags.tenant||r.runId!==o.flags.runId||void 0!==o.desiredLeaseBackend&&r.leaseBackend!==o.desiredLeaseBackend||void 0!==o.flags.platform&&r.platform!==o.flags.platform||void 0!==o.flags.target&&r.target!==o.flags.target||(s=r.daemon,a=o.daemon,(s?.baseUrl??void 0)!==(a?.baseUrl??void 0)||(s?.transport??void 0)!==(a?.transport??void 0)||(s?.serverMode??void 0)!==(a?.serverMode??void 0)))&&!d.force)throw new f("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:g,remoteConfig:I.remoteConfigPath});let y=new Date().toISOString(),A={version:1,session:g,remoteConfigPath:c.remoteConfigPath,remoteConfigHash:h,daemon:w,tenant:u,runId:m,leaseId:I&&!d.force?I.leaseId:void 0,leaseBackend:I&&!d.force?I.leaseBackend:ex(d),platform:d.platform??(I&&!d.force?I.platform:void 0),target:d.target??(I&&!d.force?I.target:void 0),runtime:I&&!d.force?I.runtime:void 0,metro:I&&!d.force?I.metro:void 0,connectedAt:I&&!d.force?I.connectedAt:y,updatedAt:y};ew({stateDir:i,state:A}),I&&d.force&&(await eT(I.metro),await eL({stateDir:i,state:I}),await eB(t,I));let _=tr(A),S=function(e,t){if(!t.runtime&&(eM(e)||ts(t.remoteConfigPath)))return to(t.remoteConfigPath)}(d,A);return e6(d,ta(A,S),()=>[`Connected remote session "${g}" tenant "${u}" run "${m}" ${A.leaseId?`lease ${A.leaseId}`:"lease pending"}`,_?.message,S?.message].filter(e=>!!e).join("\n")),!0},e7=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=tt(e);if(!o)return tn(e,n),!0;let s=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await eT(o.metro),await eL({stateDir:r,state:o});let a=!1;if(o.leaseId)try{a=(await t.leases.release({tenant:o.tenant,runId:o.runId,leaseId:o.leaseId})).released}catch{}return eI({stateDir:r,session:s}),e6(e,{connected:!1,session:s,released:a},()=>`Disconnected remote session "${s}".`),!0},te=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new f("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=tt(t);if(!r)return tn(t,n),!0;let o=tr(r),s=function(e){if(!e.runtime&&ts(e.remoteConfigPath))return to(e.remoteConfigPath)}(r);return e6(t,ta(r,s),()=>[`Connected remote session "${r.session}".`,`tenant=${r.tenant} runId=${r.runId} leaseId=${r.leaseId??"pending"} backend=${r.leaseBackend??"pending"}`,`remoteConfig=${r.remoteConfigPath}`,r.runtime?"metro=prepared":"metro=not-prepared",o?.message,s?.message].filter(e=>!!e).join("\n")),!0};function tt(e){let t=e.session??"default",n=v(e.stateDir).baseDir;return{session:t,stateDir:n,state:eh({stateDir:n,session:t})??(e.session?null:eS({stateDir:n}))}}function tn(e,t){e6(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function tr(e){if(!e.leaseId)return{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."+(void 0===e.platform&&void 0===e.leaseBackend?" Add --platform ios|android if the profile does not set a platform.":"")}}function to(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 ts(e){try{let t=l({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function ta(e,t){let r=tr(e);return{connected:!0,session:e.session,tenant:e.tenant,runId:e.runId,leaseAllocated:!!e.leaseId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,platform:e.platform,target:e.target,remoteConfig:e.remoteConfigPath,remoteConfigHash:e.remoteConfigHash,daemonBaseUrlFingerprint:function(e){if(e)return n.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...r?{leasePreparation:r}:{},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let ti=async({positionals:e,flags:n})=>{let r=e[0]??"status",o=v(n.stateDir).baseDir;if("status"===r){var s;let e,t=(e=eq({stateDir:(s={stateDir:o}).stateDir}))?{authenticated:!0,source:"cli-session",sessionId:e.id,cloudBaseUrl:e.cloudBaseUrl,workspaceId:e.workspaceId,accountId:e.accountId,name:e.name,createdAt:e.createdAt,expiresAt:e.expiresAt,expired:e3(e.expiresAt,s.now)}:{authenticated:!1,source:"none"};return e6(n,t,()=>{var e;return(e=t).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("\n"):"Not authenticated."}),!0}if("login"===r){let e=await eF({stateDir:o,flags:n,commandLabel:"agent-device auth login"});return e6(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("logout"===r){let e,r=(e=eJ({stateDir:o}.stateDir),!!t.existsSync(e)&&(t.rmSync(e,{force:!0}),!0));return e6(n,{authenticated:!1,removed:r},()=>r?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new f("INVALID_ARGS","auth accepts only: status, login, logout")},tl=new Set(["id","text","label"]),tc=new Set(["enabled","selected"]),td={open:function(e){var t,n,r;let o,s,a,[i,l]=e.positionals;if(!i)return{kind:"unsupported",message:"open requires an app id or URL"};if(tI(i))return{kind:"commands",commands:[{openLink:i}]};let c=(t=e,n=i,(a=(r=t,o=r.flags?.launchArgs,s={},r.flags?.relaunch===!0&&(s.stopApp=!0),r.flags?.clearAppState===!0&&(s.clearState=!0),Array.isArray(o)&&o.length>0&&(s.launchArguments=o),Object.keys(s).length>0?s:void 0))?{launchApp:{appId:n,...a}}:"launchApp");return l&&tI(l)?{kind:"config",appId:i,commands:[c,{openLink:l}]}:l?{kind:"unsupported",message:"open with a non-URL second argument is unsupported"}:{kind:"config",appId:i,commands:[c]}},click:tu,press:tu,longpress:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"longpress requires a target"};let r=tp(t,n);return r?{kind:"commands",commands:[{longPressOn:r}],warnings:(function(e){let[t,n,r]=e.positionals,o=ty(t)&&ty(n)?r:n;return o&&ty(o)?[Number(o)]:[]})(e).map(tf)}:{kind:"unsupported",message:"longpress target is not Maestro-compatible"}},fill:function(e){let[t,n]=e.positionals;if(!t||void 0===n)return{kind:"unsupported",message:"fill requires a target and text"};let r=tp(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"}},type:function(e){var t;let[n]=e.positionals;if(void 0===n)return{kind:"unsupported",message:"type requires text"};let r=0!==(t=n).length&&[...t].every(e=>"\b"===e)?t.length:null;return null!==r?{kind:"commands",commands:[{eraseText:r}]}:{kind:"commands",commands:[{inputText:n}]}},keyboard:function(e){let[t]=e.positionals;return"dismiss"===t?{kind:"commands",commands:["hideKeyboard"]}:"enter"===t||"return"===t?{kind:"commands",commands:[{pressKey:"Enter"}]}:{kind:"unsupported",message:`keyboard ${t??""}`.trim()}},back:()=>({kind:"commands",commands:["back"]}),wait:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"wait requires a target or duration"};if(ty(t))return{kind:"commands",commands:[{waitForAnimationToEnd:{timeout:Number(t)}}],warnings:["wait <ms> exports as waitForAnimationToEnd and may return before the full duration"]};if("text"===t&&n)return{kind:"commands",commands:[{extendedWaitUntil:{visible:n,timeout:tw(e,17e3)}}]};let r=tg(t);return r?{kind:"commands",commands:[{extendedWaitUntil:{visible:r,timeout:tw(e,17e3)}}]}:{kind:"unsupported",message:"wait selector is not Maestro-compatible"}},find:function(e){let[t,n,r]=e.positionals;return"text"===t&&n&&r?"exists"===r?{kind:"commands",commands:[{assertVisible:n}]}:"missing"===r||"not-exists"===r?{kind:"commands",commands:[{assertNotVisible:n}]}:{kind:"unsupported",message:`find text assertion "${r}" is unsupported`}:{kind:"unsupported",message:"only find text <query> exists|missing exports to Maestro"}},screenshot:function(e){let[t]=e.positionals;return t?{kind:"commands",commands:[{takeScreenshot:t}]}:{kind:"unsupported",message:"screenshot requires an output path"}},scroll:function(e){let[t]=e.positionals;return t&&"down"!==t?{kind:"unsupported",message:`scroll ${t} is not exported yet`}:{kind:"commands",commands:["scroll"]}},swipe:function(e){var t,n;let r,o=function(e){let[t,n,r,o,s]=e.positionals;if(ty(t)&&ty(n)&&ty(r)&&ty(o))return{start:R(t,n),end:R(r,o),...s&&ty(s)?{duration:Number(s)}:{}}}(e);if(!o)return{kind:"unsupported",message:"only coordinate swipe exports to Maestro"};let s=(t=e,Number.isInteger(r=t.flags?.count??1)&&r>=1?r:null);if(null===s)return{kind:"unsupported",message:"swipe count must be a positive integer"};let a=(n=e,n.flags?.pauseMs!==void 0?"swipe --pause-ms has no Maestro equivalent":n.flags?.pattern&&"one-way"!==n.flags.pattern?"swipe ping-pong pattern has no Maestro equivalent":void 0);return a?{kind:"unsupported",message:a}:{kind:"commands",commands:Array.from({length:s},()=>({swipe:o}))}}};function tu(e){var t,n,r,o,s;let a,i,[l,c]=e.positionals;if(!l)return{kind:"unsupported",message:`${e.command} requires a target`};let d=tp(l,c);if(!d)return{kind:"unsupported",message:"tap target is not Maestro-compatible"};let u=(a=(n=t=e,n.flags?.jitterPx!==void 0?"tap --jitter-px has no Maestro equivalent":n.flags?.clickButton&&"primary"!==n.flags.clickButton?`tap --button ${n.flags.clickButton} has no Maestro equivalent`:void 0))?{ok:!1,message:a}:{ok:!0,options:(r=t,i={},"number"==typeof r.flags?.count&&r.flags.count>1&&(i.repeat=r.flags.count),"number"==typeof r.flags?.intervalMs&&r.flags.intervalMs>0&&(i.delay=r.flags.intervalMs),i)};return u.ok?e.flags?.doubleTap===!0?{kind:"commands",commands:[{doubleTapOn:d}],warnings:tm(e,"doubleTapOn")}:"number"==typeof e.flags?.holdMs?{kind:"commands",commands:[{longPressOn:d}],warnings:[tf(e.flags.holdMs),...tm(e,"longPressOn")]}:{kind:"commands",commands:[(o=d,0===Object.keys(s=u.options).length?{tapOn:o}:"string"==typeof o?{tapOn:{text:o,...s}}:o&&"object"==typeof o&&!Array.isArray(o)?{tapOn:{...o,...s}}:{tapOn:o})]}:{kind:"unsupported",message:u.message}}function tf(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function tm(e,t){let n=[];return"number"==typeof e.flags?.count&&e.flags.count>1&&n.push(`tap --count ${e.flags.count} is not represented by Maestro ${t}`),"number"==typeof e.flags?.intervalMs&&e.flags.intervalMs>0&&n.push(`tap --interval-ms ${e.flags.intervalMs} is not represented by Maestro ${t}`),n}function tp(e,t){return ty(e)&&ty(t)?{point:R(e,t)}:e.startsWith("@")?null:tg(e)}function tg(e){let t;try{t=N(e)}catch{return e.includes("=")||e.includes("||")?null:e}let n=function(e){if(e.length<=1)return null;let t=e.flatMap(e=>1===e.terms.length&&tl.has(e.terms[0].key)?[e.terms[0].value]:[]);if(t.length!==e.length||0===t.length)return null;let n=t[0];return"string"!=typeof n?null:t.every(e=>e===n)?n:null}(t.selectors);return null!==n?n:1!==t.selectors.length?null:function(e){let t={};for(let o of e.terms){var n,r;if(n=t,r=o,tl.has(r.key)?"string"!=typeof r.value||!!n.id||!!n.text||!!n.label||(n[r.key]=r.value,!!0):!tc.has(r.key)||"boolean"!=typeof r.value||(n[r.key]=r.value,!!0))return null}return Object.keys(t).length>0?t:null}(t.selectors[0])}function th(e,t,n,r){for(let o of t??[])e.warnings.push({line:r,action:tv(n),message:o})}function tw(e,t){let n=e.positionals.at(-1);return n&&ty(n)?Number(n):t}function tv(e){return[e.command,...e.positionals??[]].join(" ").trim()}function tI(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function ty(e){return void 0!==e&&Number.isFinite(Number(e))}let tA=async e=>{let{positionals:t}=e;return"export"!==t[0]?function({positionals:e,flags:t}){if(e.length>1)throw new f("INVALID_ARGS","replay accepts exactly one input path: replay <path>");if(void 0!==t.replayExportFormat||void 0!==t.out)throw new f("INVALID_ARGS","replay --format/--out are only supported with replay export.");return!1}(e):await t_(e)};async function t_({positionals:e,flags:n}){let o;var s,a=e,i=n;if(a.length>2)throw new f("INVALID_ARGS","replay export accepts exactly one input path: replay export <file.ad>");if(i.replayUpdate)throw new f("INVALID_ARGS","replay export does not support --update.");if(i.replayMaestro)throw new f("INVALID_ARGS","replay export reads .ad files; omit --maestro.");if(i.replayEnv?.length)throw new f("INVALID_ARGS","replay export does not evaluate --env substitutions.");let l=i.replayExportFormat??"maestro";if("maestro"!==l)throw new f("INVALID_ARGS",`Unsupported replay export format: ${l}`);let c=e[1];if(!c)throw new f("INVALID_ARGS","replay export requires an input path.");let d=P(c),u=function(e,t={}){var n,r,o,s;let a={config:(n=t.metadata,n?.env&&Object.keys(n.env).length>0?{env:n.env}:{}),warnings:[],unsupported:[]},i=[];for(let[n,o]of e.entries()){let e=t.actionLines?.[n]??n+1,s=(r=o,td[r.command]?.(r)??{kind:"unsupported",message:`${r.command} has no Maestro equivalent`});switch(s.kind){case"commands":i.push(...s.commands),th(a,s.warnings,o,e);break;case"config":(function(e,t,n,r){if(!e.config.appId){e.config.appId=t;return}e.config.appId!==t&&e.unsupported.push({line:r,action:tv(n),message:`multiple app ids cannot be represented in one Maestro config (${e.config.appId} vs ${t})`})})(a,s.appId,o,e),i.push(...s.commands),th(a,s.warnings,o,e);break;case"unsupported":a.unsupported.push({line:e,action:tv(o),message:s.message})}}if(a.unsupported.length>0)throw new f("INVALID_ARGS",`Cannot export replay to Maestro YAML: unsupported .ad action ${a.unsupported.map(e=>`line ${e.line} (${e.action}): ${e.message}`).join("; ")}.`,{unsupported:a.unsupported});return{yaml:(o=a.config,s=i,U(Object.keys(o).length>0?[o,s]:[s])),warnings:a.warnings}}((o=b(s=t.readFileSync(d,"utf8"))).actions,{actionLines:o.actionLines,metadata:E(s)}),m="string"==typeof n.out?P(n.out):void 0;for(let e of(m&&(t.mkdirSync(r.dirname(m),{recursive:!0}),t.writeFileSync(m,u.yaml)),u.warnings))process.stderr.write(`Warning: line ${e.line}: ${e.message}
|
|
13
|
+
`);return e6(n,{format:n.replayExportFormat??"maestro",sourcePath:d,...m?{path:m}:{yaml:u.yaml},warnings:u.warnings},()=>m??u.yaml),!0}let tS={...O,...L,...B,...V,...H,...$,...q,...W,...j,...K,...x,...F,...z,...M};async function tC(e){return(await tD(e)).result}async function tD(e){var t,n,r;let o=(t=e.command,n=e.positionals,r=e.flags,tS[t](n,r)),s=await Z(e.client,e.command,o);return{result:s,cliOutput:k({name:e.command,input:o,result:s})}}let tk={connect:e9,disconnect:e7,connection:te,auth:ti,replay:tA,screenshot:async({positionals:e,flags:t,client:n})=>{let r=await tC({client:n,command:"screenshot",positionals:e,flags:t});return e6(t,{path:r.path,...r.overlayRefs?{overlayRefs:r.overlayRefs}:{}},()=>r.overlayRefs?`Annotated ${r.overlayRefs.length} refs onto ${r.path}`:r.path),!0},diff:async({positionals:e,flags:t,client:n})=>{var r;if("snapshot"===e[0]){let r=await tC({client:n,command:"diff",positionals:e,flags:t});return e6(t,r,()=>_(r)),!0}if("screenshot"!==e[0])return!1;let o=t.baseline;if(!o||"string"!=typeof o)throw new f("INVALID_ARGS","diff screenshot requires --baseline <path>");let s=P(o),a="string"==typeof t.out?P(t.out):void 0,i=e[1];if(e.length>2)throw new f("INVALID_ARGS","diff screenshot accepts at most one current screenshot path");let l=Q({backend:(r=n,{platform:function(e){switch(e.platform){case"android":case"linux":case"macos":return e.platform;default:return"ios"}}(t),captureScreenshot:async(e,t,n)=>{let o=await r.capture.screenshot({path:t,session:e.session,overlayRefs:n?.overlayRefs,fullscreen:n?.fullscreen,stabilize:n?.stabilize,surface:n?.surface});return{path:o.path,...o.overlayRefs?{overlayRefs:o.overlayRefs}:{}}}}),artifacts:Y(),sessions:{get:e=>({name:e}),set:()=>{}},policy:X()}),c=await l.capture.diffScreenshot({session:t.session,baseline:{kind:"path",path:s},current:i?{kind:"path",path:P(i)}:{kind:"live"},...a?{out:{kind:"path",path:a}}:{},threshold:function(e){if(null!=e&&""!==e)return Number(e)}(t.threshold),overlayRefs:t.overlayRefs,surface:t.surface});return e6(t,c,()=>S(c)),!0}};async function tN(e){let t={...e.flags},n=tk[e.command];return!!(n&&await n({...e,flags:t}))||!!ee(e.command)&&await tU({...e,command:e.command,flags:t})}async function tU(e){let{runGenericClientBackedCommand:t}=await import("./generic.js");return await t(e)}function tb(e,t,n){return n||(e.push(t),"")}async function tR(e,t,n){let{flags:r}=t,o=function(e){var t;if(!e?.metroProxyBaseUrl||"android-instance"!==(t=e.leaseBackend)&&"ios-instance"!==t)return null;let n=[],r={serverBaseUrl:tb(n,"metroProxyBaseUrl",e.metroProxyBaseUrl),bearerToken:tb(n,"metroBearerToken",e.metroBearerToken),tenantId:tb(n,"tenant",e.tenant),runId:tb(n,"runId",e.runId),leaseId:tb(n,"leaseId",e.leaseId)};if(n.length>0)throw new f("INVALID_ARGS",`react-devtools remote bridge requires ${n.join(", ")}.`,{missing:n});return r}(r);if(!o)return n();let s=t.stateDir??process.cwd(),a=t.session??r?.session??"default",i=r?.remoteConfig??`${o.tenantId}:${o.runId}:${o.leaseId}`;if("stop"===e[0])try{return await n()}finally{await eg({projectRoot:t.cwd??process.cwd(),stateDir:s,profileKey:i,consumerKey:a})}return await ep({projectRoot:t.cwd??process.cwd(),stateDir:s,serverBaseUrl:o.serverBaseUrl,bearerToken:o.bearerToken,bridgeScope:{tenantId:o.tenantId,runId:o.runId,leaseId:o.leaseId},session:a,profileKey:i,consumerKey:a,env:t.env??process.env}),await n()}async function tE(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,o=await tR(e,t,async()=>(await y("npm",["exec","--yes","--package","agent-react-devtools@0.4.0","--","agent-react-devtools",...e],{cwd:n,env:r,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode);var s,a=t.flags;return 0!==o&&"wait"===(s=e)[0]&&s.includes("--connected")&&"ios-instance"===a?.leaseBackend&&process.stderr.write("Hint: Remote iOS React DevTools connects during JavaScript startup.\nIf 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`.\n"),o}function tP(e,t={}){let n=tT(t),r={...e};return n.defaultPlatform&&void 0===r.platform&&(r.platform=n.defaultPlatform),r}function tT(e){var t,n,r,o;let s,a=e.env??process.env,i=e.inheritedPlatform??e.configuredPlatform??function(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("ios"===t||"android"===t||"apple"===t)return t;throw new f("INVALID_ARGS",`Invalid AGENT_DEVICE_PLATFORM: ${e}. Use ios, android, or apple.`)}}(a.AGENT_DEVICE_PLATFORM),l="string"==typeof(t=e.configuredSession??a.AGENT_DEVICE_SESSION)&&t.trim().length>0;return{defaultPlatform:i,lockPolicy:(n=e.policyOverrides,r=a,o=l,(s=n?.sessionLock??n?.sessionLockConflicts??function(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("reject"===t||"strip"===t)return t;throw new f("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}(r.AGENT_DEVICE_SESSION_LOCK))||(n?.sessionLocked===!0||o?"reject":void 0))}}let tL={sendToDaemon:eu},tB=new Set(["launchUrl","kind","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),tx=new Set(["connect","connection","close","disconnect","metro","session"]);async function tM(e,n=tL){let o=m(),s=ec(),a=function(e){try{let t=ea(e);return tO(t.command??"",t.providedFlags)}catch{return e.includes("--debug")||e.includes("-v")||e.includes("--verbose")}}(e),i=e.includes("--json"),I=function(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("--session"===n){let n=e[t+1]?.trim();if(n&&!n.startsWith("-"))return n;break}}return null}(e)??process.env.AGENT_DEVICE_SESSION??"default";await p({session:I,requestId:o,command:e[0],debug:a},async()=>{var m,p,I,y,A,_,S,k,N,U,b,R,E,L,B,x,M;let O,$,V,j,K,H,F;try{let n,o,s,a,i,c,d,u;m={cwd:process.cwd(),env:process.env},n=ea(e),o=m?.env??process.env,s=m?.cwd??process.cwd(),y=n.command,a=null!==y&&(p={remoteConfig:n.flags.remoteConfig,cwd:s,env:o}).remoteConfig?{...eU(l({configPath:p.remoteConfig,cwd:p.cwd,env:p.env}).profile),remoteConfig:p.remoteConfig}:{},d=et((i=(I={command:n.command,cwd:s,cliFlags:n.flags,env:o}).env??process.env,c=et({},function(e){let n={};for(let r of e)et(n,function(e,n){let r,o;if(!t.existsSync(e)){if(n)throw new f("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{r=t.readFileSync(e,"utf8")}catch(t){throw new f("INVALID_ARGS",`Failed to read config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}try{o=JSON.parse(r)}catch(t){throw new f("INVALID_ARGS",`Invalid JSON in config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}if(!o||"object"!=typeof o||Array.isArray(o))throw new f("INVALID_ARGS",`Config file must contain a JSON object: ${e}`);return function(e,t){let n={};for(let[r,o]of Object.entries(e)){if("installSource"===r){n.installSource=G(o,t);continue}let e=eo(r);if(!e)throw new f("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new f("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);n[r]=en(e,o,t,r)}return n}(o,`config file ${e}`)}(r.path,r.required));return n}((A=I.cwd,_=I.cliFlags.config,S=i,(u=_??S.AGENT_DEVICE_CONFIG)?[{path:(k=u,N=A,U=S,P(k,{cwd:N,env:U})),required:!0}]:[{path:(b=S,r.join(T("~",{env:b}),".agent-device","config.json")),required:!1},{path:r.resolve(A,"agent-device.json"),required:!1}]))),et(c,function(e,t){let n={};for(let r of er(t)){if("installSource"===r.key)continue;let t=r.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(n[r.key]=en(r,t.value,`environment variable ${t.name}`,t.name))}return n}(i,I.command))),a),O={...el(n,{strictFlags:m?.strictFlags,defaultFlags:d}),providedFlags:n.providedFlags}}catch(t){w({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=u(t,{diagnosticId:g().diagnosticId,logPath:h({force:!0})??void 0});i?D({success:!1,error:e}):C(e,{showDetails:a}),process.exit(1);return}for(let e of O.warnings)process.stderr.write(`Warning: ${e}
|
|
14
|
+
`);O.flags.version&&(process.stdout.write(`${s}
|
|
15
|
+
`),process.exit(0));let q="help"===O.command,z=O.flags.help;if(q||z){q&&O.positionals.length>1&&(C(new f("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=q?O.positionals[0]:O.command;e||(process.stdout.write(`${es()}
|
|
16
|
+
`),process.exit(0));let t=ei(e);t&&(process.stdout.write(t),process.exit(0)),C(new f("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${es()}
|
|
17
|
+
`),process.exit(1)}O.command||(process.stdout.write(`${es()}
|
|
18
|
+
`),process.exit(1));let{command:W,positionals:Z}=O,Y=tO(W,O.providedFlags),X=new Set(O.providedFlags.map(e=>e.key));try{V=($=tT({policyOverrides:O.flags,configuredPlatform:O.flags.platform,configuredSession:O.flags.session})).lockPolicy?{...O.flags}:tP(O.flags,{policyOverrides:O.flags,configuredPlatform:O.flags.platform,configuredSession:O.flags.session}),j=v(V.stateDir),K=V.session??"default",R={command:W,explicitFlagKeys:X,stateDir:j.baseDir,session:K,remoteConfig:V.remoteConfig,hasResolvedSession:void 0!==V.session},F=(H="connect"===R.command||"connection"===R.command?null:function(e){let t=e.validateRemoteConfigHash??!0,n=e.remoteConfig?c({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,r=eh(e)??(e.allowActiveFallback?eS({stateDir:e.stateDir}):null);if(!r||n&&r.remoteConfigPath!==n)return null;if(t&&ey(r.remoteConfigPath)!==r.remoteConfigHash)throw new f("INVALID_ARGS","Active remote connection config changed. Run agent-device connect --force to refresh it.",{remoteConfig:r.remoteConfigPath});let o=function(e,t){try{return l({configPath:e.remoteConfigPath,cwd:t.cwd,env:t.env}).profile}catch(e){if(!1===t.validateRemoteConfigHash)return{};throw e}}(r,e);return{runtime:r.runtime,flags:{...o,remoteConfig:r.remoteConfigPath,daemonBaseUrl:r.daemon?.baseUrl??o.daemonBaseUrl,daemonTransport:r.daemon?.transport??o.daemonTransport,daemonServerMode:r.daemon?.serverMode??o.daemonServerMode,tenant:r.tenant,sessionIsolation:"tenant",runId:r.runId,leaseId:r.leaseId,leaseBackend:r.leaseBackend,session:r.session,platform:r.platform??o.platform,target:r.target??o.target}}}({stateDir:R.stateDir,session:R.session,remoteConfig:R.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!R.explicitFlagKeys.has("session")&&(!R.remoteConfig||"disconnect"===R.command||!R.hasResolvedSession),validateRemoteConfigHash:"disconnect"!==R.command}))?function(e,t,n){let r={...e};for(let[e,o]of Object.entries(t))void 0!==o&&(n.has(e)||(r[e]=o));return r}(V,H.flags,X):V}catch(t){let e=u(d(t),{diagnosticId:g().diagnosticId,logPath:h({force:!0})??void 0});O.flags.json?D({success:!1,error:e}):C(e,{showDetails:Y}),process.exit(1);return}let Q=null;try{let e;if("react-devtools"===W){let e=await tE(Z,{flags:F,stateDir:j.baseDir,session:F.session??K,cwd:process.cwd(),env:process.env});process.exit(e);return}ef({command:W,currentVersion:s,stateDir:j.baseDir,flags:F});let r=H?.runtime,a=(e,t)=>({session:e.session,requestId:o,stateDir:e.stateDir,daemonBaseUrl:e.daemonBaseUrl,daemonAuthToken:e.daemonAuthToken,daemonTransport:e.daemonTransport,daemonServerMode:e.daemonServerMode,tenant:e.tenant,sessionIsolation:e.sessionIsolation,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,runtime:t,lockPolicy:$.lockPolicy,lockPlatform:$.defaultPlatform,cwd:process.cwd(),debug:Y});if("batch"===W){if(Z.length>0)throw new f("INVALID_ARGS","batch does not accept positional arguments.");e=function(e){let n,r,o,s="";if(e.steps)s=e.steps;else if(e.stepsFile)try{s=t.readFileSync(e.stepsFile,"utf8")}catch(n){let t=n instanceof Error?n.message:String(n);throw new f("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}var a,i=s;try{o=JSON.parse(i)}catch{throw new f("INVALID_ARGS","Batch steps must be valid JSON.")}if(!Array.isArray(o)||0===o.length)throw new f("INVALID_ARGS","Batch steps must be a non-empty JSON array.");return a=o,n=!1,r=a.map((e,t)=>{var r,o,s,a,i,l;let c;if(r=e,null!==r&&"object"==typeof r&&!Array.isArray(r)&&"input"in r&&!("positionals"in r)&&!("flags"in r))return e;let d=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new f("INVALID_ARGS",`Invalid batch step ${t}.`);var n=e,r=t;let o=Object.keys(n).filter(e=>!["command","positionals","flags","runtime"].includes(e));if(o.length>0)throw new f("INVALID_ARGS",`Batch step ${r} has unknown legacy field(s): ${o.join(", ")}.`);let s=function(e,t){let n="string"==typeof e?e.trim().toLowerCase():"";if(!n)throw new f("INVALID_ARGS",`Batch step ${t} requires command.`);if(J(n))return n;throw new f("INVALID_ARGS",`Batch step ${t} command is not available through command batch: ${String(e)}`)}(e.command,t),a=function(e,t){if(void 0!==e){if(!Array.isArray(e)||e.some(e=>"string"!=typeof e))throw new f("INVALID_ARGS",`Batch step ${t} positionals must contain only strings.`);return e}}(e.positionals,t),i=function(e,t){if(void 0!==e){if(!e||"object"!=typeof e||Array.isArray(e))throw new f("INVALID_ARGS",`Batch step ${t} flags must be an object.`);return e}}(e.flags,t);return{command:s,...void 0===a?{}:{positionals:a},...void 0===i?{}:{flags:i},...void 0===e.runtime?{}:{runtime:e.runtime}}}(e,t+1);return n=!0,c=(s=(o=d).command,a=o.positionals??[],l=o.flags,i={json:!1,help:!1,version:!1,...l},tS[s](a,i)),{command:o.command,input:c,...void 0===o.runtime?{}:{runtime:o.runtime}}}),n&&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.\n'),r}(V)}if(E=W,"auth"!==E&&"connection"!==E&&(F=(await ej({command:W,flags:F,stateDir:j.baseDir,env:process.env})).flags),F.remoteConfig&&(L=W,!tx.has(L))){let t=ed(a(F,r),{transport:n.sendToDaemon}),o=await eE({command:W,flags:F,client:t,runtime:r,batchSteps:e,forceRuntimePrepare:function(e){for(let t of tB)if(e.has(t))return!0;return!1}(X)});F=o.flags,r=o.runtime}B={command:W,flags:F,runtime:r,explicitFlagKeys:X,hadConnectionDefaults:!!H},!("open"===B.command&&!B.runtime&&!B.flags.bundleUrl&&!B.flags.metroHost&&!B.flags.metroPort&&!B.flags.remoteConfig&&!B.hadConnectionDefaults&&((x=B.explicitFlagKeys).has("daemonBaseUrl")||x.has("daemonTransport")||x.has("tenant")||x.has("sessionIsolation")||x.has("runId")||x.has("leaseId")||x.has("leaseBackend")))||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.\n");let i=F.daemonBaseUrl;Q=!Y||F.json||i?null:function(e){try{let n=t.existsSync(e)?t.statSync(e).size:0,r=!1,o=setInterval(()=>{if(!r&&t.existsSync(e))try{let r=t.statSync(e);if(r.size<n&&(n=0),r.size<=n)return;let o=t.openSync(e,"r");try{let e=Buffer.alloc(r.size-n);t.readSync(o,e,0,e.length,n),n=r.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{t.closeSync(o)}}catch{}},200);return()=>{r=!0,clearInterval(o)}}catch{return null}}(j.logPath);let l=ed(a(F,r),{transport:function(e){let{command:t,flags:n,transport:r}=e;return"test"!==t||n.json?r:async e=>await r({...e,meta:{...e.meta,requestProgress:"replay-test"}})}({command:W,flags:F,transport:n.sendToDaemon})});if("batch"===W){if(!e)throw new f("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,input:$.lockPolicy&&void 0===V.platform?{...e.input}:tP(e.input,{policyOverrides:F,configuredPlatform:F.platform,configuredSession:F.session,inheritedPlatform:F.platform})}));if(await tN({command:W,positionals:Z,flags:{...F,batchSteps:t},client:l}))return}else if("runtime"===W)throw new f("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 tN({command:W,positionals:Z,flags:F,client:l}))return;throw new f("INVALID_ARGS",`Unknown command: ${W}`)}catch(r){let e=d(r),n=u(e,{diagnosticId:g().diagnosticId,logPath:h({force:!0})??void 0});if("close"===W&&"COMMAND_FAILED"===(M=e).code&&(M.details?.kind==="daemon_startup_failed"||M.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof M.details?.infoPath||"string"==typeof M.details?.lockPath))){F.json&&D({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(F.json)D({success:!1,error:n});else if(C(n,{showDetails:Y}),Y)try{let e=j.logPath;if(t.existsSync(e)){let n=t.readFileSync(e,"utf8").split("\n"),r=n.slice(Math.max(0,n.length-200)).join("\n");r.trim().length>0&&process.stderr.write(`
|
|
20
19
|
[daemon log]
|
|
21
20
|
${r}
|
|
22
|
-
`)}}catch{}
|
|
21
|
+
`)}}catch{}Q&&Q(),process.exit(1)}finally{Q&&Q()}})}function tO(e,t){return t.some(t=>"verbose"===t.key&&("--debug"===t.token||"-v"===t.token||"test"!==e))}e(process.argv[1]??"").href===import.meta.url&&tM(process.argv.slice(2)).catch(e=>{C(u(d(e)),{showDetails:!0}),process.exit(1)});export{tM as runCli,tD as runCliCommandWithOutput,e6 as writeCommandOutput};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{interactionCommandDefinitions as _,batchCommandDefinition as n}from"./6133.js";import{clientCommandDefinitions as r}from"./5611.js";let a=new Map([..._,...r,n].map(_=>[_.name,_]));async function m(_,n,r){var m;return await (m=n,a.get(m)).invoke(_,r)}export{m as runCommand};
|
package/dist/src/contracts.d.ts
CHANGED
|
@@ -99,6 +99,58 @@ export declare type DaemonServerMode = (typeof DAEMON_SERVER_MODES)[number];
|
|
|
99
99
|
|
|
100
100
|
export declare type DaemonTransportPreference = (typeof DAEMON_TRANSPORT_PREFERENCES)[number];
|
|
101
101
|
|
|
102
|
+
export declare type DebugSymbolsCrashFrame = {
|
|
103
|
+
index: number;
|
|
104
|
+
image: string;
|
|
105
|
+
address: string;
|
|
106
|
+
symbol?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export declare type DebugSymbolsCrashSummary = {
|
|
110
|
+
format: 'ips' | 'text';
|
|
111
|
+
appName?: string;
|
|
112
|
+
bundleId?: string;
|
|
113
|
+
version?: string;
|
|
114
|
+
incident?: string;
|
|
115
|
+
timestamp?: string;
|
|
116
|
+
exceptionType?: string;
|
|
117
|
+
exceptionCodes?: string;
|
|
118
|
+
terminationReason?: string;
|
|
119
|
+
crashedThread?: number;
|
|
120
|
+
topFrames: DebugSymbolsCrashFrame[];
|
|
121
|
+
findings: string[];
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export declare type DebugSymbolsImage = {
|
|
125
|
+
name: string;
|
|
126
|
+
uuid: string;
|
|
127
|
+
arch?: string;
|
|
128
|
+
dsymPath: string;
|
|
129
|
+
binaryPath: string;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export declare type DebugSymbolsOptions = {
|
|
133
|
+
action?: 'symbols';
|
|
134
|
+
artifact: string;
|
|
135
|
+
dsym?: string;
|
|
136
|
+
searchPath?: string;
|
|
137
|
+
out?: string;
|
|
138
|
+
cwd?: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export declare type DebugSymbolsResult = {
|
|
142
|
+
kind: 'debugSymbols';
|
|
143
|
+
platform: 'apple';
|
|
144
|
+
artifactPath: string;
|
|
145
|
+
outPath: string;
|
|
146
|
+
crash: DebugSymbolsCrashSummary;
|
|
147
|
+
matchedImages: DebugSymbolsImage[];
|
|
148
|
+
symbolicatedFrames: number;
|
|
149
|
+
skippedImages: number;
|
|
150
|
+
warnings?: string[];
|
|
151
|
+
message: string;
|
|
152
|
+
};
|
|
153
|
+
|
|
102
154
|
export declare function defaultHintForCode(code: string): string | undefined;
|
|
103
155
|
|
|
104
156
|
export declare type JsonRpcId = string | number | null;
|
package/dist/src/contracts.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{DAEMON_LOCK_POLICIES,DAEMON_SERVER_MODES,DAEMON_TRANSPORT_PREFERENCES,LEASE_BACKENDS,NETWORK_INCLUDE_MODES,SESSION_ISOLATION_MODES,daemonCommandRequestSchema,daemonRuntimeSchema,jsonRpcRequestSchema,leaseAllocateSchema,leaseHeartbeatSchema,leaseReleaseSchema}from"./9616.js";export{
|
|
1
|
+
export{DAEMON_LOCK_POLICIES,DAEMON_SERVER_MODES,DAEMON_TRANSPORT_PREFERENCES,LEASE_BACKENDS,NETWORK_INCLUDE_MODES,SESSION_ISOLATION_MODES,centerOfRect,daemonCommandRequestSchema,daemonRuntimeSchema,jsonRpcRequestSchema,leaseAllocateSchema,leaseHeartbeatSchema,leaseReleaseSchema}from"./9616.js";export{defaultHintForCode,normalizeError}from"./9152.js";
|
package/dist/src/find.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{context_contextFromFlags as
|
|
1
|
+
import{context_contextFromFlags as t,setSessionSnapshot as e,captureSnapshot as n,dispatchCommand as r,errorResponse as a,ensureDeviceReady as o,getActiveAndroidSnapshotFreshness as i,resolveTargetDevice as s,stripInternalInteractionFlags as l}from"./2415.js";import{findBestMatchesByLocator as c,parseFindArgs as f}from"./7556.js";import{dispatchFindReadOnlyViaRuntime as u,readTextForNode as d}from"./selector-runtime.js";import{resolveActionableTouchResolution as p,isSparseSnapshotQualityVerdict as h,isSnapshotNodeInteractionBlocked as g,resolveActionableTouchNode as _}from"./6133.js";import{centerOfRect as y}from"./9616.js";import{sleep as m}from"./4829.js";import{extractNodeText as w}from"./7847.js";async function A(t){var r,d,g,m;let A,{req:E,sessionName:U,logPath:P,sessionStore:O,invoke:H}=t,$=E.command;if("find"!==$)return null;let q=E.positionals??[];if(0===q.length)return a("INVALID_ARGS","find requires a locator or text");let{locator:B,query:Q,action:G,value:V,timeoutMs:T}=f(q);if(!Q)return a("INVALID_ARGS","find requires a value");if(E.flags?.findFirst&&E.flags?.findLast)return a("INVALID_ARGS","find accepts only one of --first or --last");let j=await u({req:E,sessionName:U,logPath:P,sessionStore:O});if(j)return j;let z=O.get(U),J="exists"===(r=G)||"wait"===r||"get_text"===r||"get_attrs"===r;if(!z&&!J)return a("SESSION_NOT_FOUND","No active session. Run open first.");let W=z?.device??await s(E.flags??{});z||await o(W);let X="click"===(d=G)||"focus"===d||"fill"===d||"type"===d,Y=L(B)&&!X?Q:void 0,Z=function(t){let{device:r,session:a,req:o,logPath:s,locator:l,query:c,scope:f,interactiveOnly:u}=t,{sessionStore:d,sessionName:p}=t,g=0,_=null,y=async(t,e)=>{let{snapshot:i}=await n({device:r,session:a,flags:{...o.flags,snapshotInteractiveOnly:e},outPath:o.flags?.out,logPath:s,snapshotScope:t});return i};return async()=>{var t;let n=Date.now();if(_&&n-g<750&&!i(a))return _;let r=await y(f,u);u&&!(t=r).snapshotQuality&&"xctest"===t.backend&&1===t.nodes.length&&t.nodes[0]?.type==="Application"?r=await N({capture:y,locator:l,query:c,scope:f}):u&&h(r.snapshotQuality)&&L(l)&&(r=await k({capture:y,query:c,snapshot:r}));let o={nodes:r.nodes,truncated:r.truncated,backend:r.backend,snapshotQuality:r.snapshotQuality};return g=n,_=o,a&&!h(r.snapshotQuality)&&(e(a,r),d.set(p,a)),o}}({device:W,session:z,req:E,logPath:P,locator:B,query:Q,scope:Y,interactiveOnly:X,sessionStore:O,sessionName:U}),tt={req:E,sessionName:U,logPath:P,sessionStore:O,invoke:H,session:z,device:W,command:$,locator:B,query:Q,publicFlags:{...l(E.flags)??{}}};if("wait"===G)return x(tt,Z,B,Q,T);let te=await Z();if(h(te.snapshotQuality))return S(te.snapshotQuality);let{nodes:tn}=te,tr=function(t){let{nodes:e,locator:n,query:r,requiresRect:o,flags:i}=t,s=c(o?e.filter(t=>!C(t,e[0])):e,n,r,{requireRect:o});if(o&&(s.matches=function(t,e){var n,r;let a=e[0]?.rect;if(!a)return t;let o=t.filter(t=>{if(!t.rect)return!1;let e=y(t.rect);return e.x>=a.x&&e.x<=a.x+a.width&&e.y>=a.y&&e.y<=a.y+a.height});return n=o.length>0?o:t,r=e,n.length<2?n:n.map((t,e)=>({node:t,index:e,score:function(t,e){var n,r;let a=p(e,t);if("covered"===a.reason)return 0;let o=(n=a,r=e[0],n.node.rect?"semantic-target"===n.reason||"same-rect-descendant"===n.reason?4:2*!("hittable-ancestor"!==n.reason||C(n.node,r)):0);return o>0?o:t.hittable&&t.rect&&!C(t,e[0])?3:+!!t.rect}(t,r)})).sort((t,e)=>e.score!==t.score?e.score-t.score:v(t.node)-v(e.node)||t.index-e.index).map(t=>t.node)}(s.matches,e)),o&&s.matches.length>1){var l,f,u,d,h;let t=(l=s.matches,f=i,f?.findFirst?[l[0]]:f?.findLast?[l[l.length-1]]:null);if(!t){let t;return{ok:!1,response:(u=s.matches,d=n,h=r,t=u.slice(0,8).map(t=>{let e=w(t)||t.label||t.identifier||t.type||"";return`@${t.ref}${e?`(${e})`:""}`}),a("AMBIGUOUS_MATCH",`find matched ${u.length} elements for ${d} "${h}". Use a more specific locator or selector.`,{locator:d,query:h,matches:u.length,candidates:t}))}}s.matches=t}let g=s.matches[0]??null;return g?{ok:!0,node:g}:{ok:!1,response:a("COMMAND_FAILED","find did not match any element")}}({nodes:tn,locator:B,query:Q,requiresRect:X,flags:E.flags});if(!tr.ok)return tr.response;let ta=tr.node,to=X?C(A=_(g=tn,m=ta),g[0])&&m.rect?m:A:ta,ti=`@${to.ref}`,ts={node:ta,resolvedNode:to,ref:ti,nodes:tn,actionFlags:{...E.flags??{},noRecord:!0}},tl={exists:()=>M(tt),get_text:()=>I(tt,ts),get_attrs:()=>D(tt,ts),click:()=>R(tt,ts),fill:()=>F(tt,ts,V),focus:()=>K(tt,ts),type:()=>b(tt,ts,V)}[G];return tl?tl():null}async function k(t){let{capture:e,query:n,snapshot:r}=t;try{return await e(n,!1)}catch{return r}}async function N(t){let{capture:e,locator:n,query:r,scope:a}=t;try{return await e(a,!1)}catch(t){if(!L(n))throw t;return await e(r,!1)}}function S(t){return a("COMMAND_FAILED","find could not read the current accessibility tree",{reason:t.reason,hint:"The snapshot quality verdict is sparse. Use screenshot as visual truth, navigate with coordinates if needed, then retry find after reaching a readable screen."})}function v(t){return t.rect?t.rect.width*t.rect.height:1/0}function C(t,e){var n,r;if(!e?.rect||!t.rect)return!1;let a=t.type?.toLowerCase()??"";return(!!a.includes("application")||!!a.includes("window"))&&(n=t.rect,r=e.rect,n.x===r.x&&n.y===r.y&&n.width===r.width&&n.height===r.height)}async function x(t,e,n,r,o){let i,{req:s,sessionStore:l,session:f,command:u,publicFlags:d}=t,p=o??1e4,g=Date.now();for(;Date.now()-g<p;){let{nodes:t,snapshotQuality:a}=await e();if(h(a)){i=a,await m(300);continue}if(c(t,n,r,{requireRect:!1}).matches[0])return f&&l.recordAction(f,{command:u,positionals:s.positionals??[],flags:d,result:{found:!0,waitedMs:Date.now()-g}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-g}};await m(300)}return i?S(i):a("COMMAND_FAILED","find wait timed out")}async function M(t){let{req:e,sessionStore:n,session:r,command:a,publicFlags:o}=t;return r&&n.recordAction(r,{command:a,positionals:e.positionals??[],flags:o,result:{found:!0}}),{ok:!0,data:{found:!0}}}async function I(e,n){let{req:r,sessionStore:a,session:o,command:i,device:s,logPath:l,publicFlags:c}=e,f=await d({device:s,node:n.node,flags:r.flags,appBundleId:o?.appBundleId,traceOutPath:o?.trace?.outPath,surface:o?.surface,contextFromFlags:(e,n,r)=>t(l,e,n,r)});return o&&a.recordAction(o,{command:i,positionals:r.positionals??[],flags:c,result:{ref:n.ref,action:"get text",text:f}}),{ok:!0,data:{ref:n.ref,text:f,node:n.node}}}async function D(t,e){let{req:n,sessionStore:r,session:a,command:o,publicFlags:i}=t;return a&&r.recordAction(a,{command:o,positionals:n.positionals??[],flags:i,result:{ref:e.ref,action:"get attrs"}}),{ok:!0,data:{ref:e.ref,node:e.node}}}async function R(t,e){let{req:n,sessionName:r,sessionStore:a,session:o,invoke:i,command:s,locator:l,query:c,publicFlags:f}=t,u=await i({token:n.token,session:r,command:"click",positionals:[e.ref],flags:e.actionFlags});if(!u.ok)return u;let d=e.resolvedNode.rect?y(e.resolvedNode.rect):e.node.rect?y(e.node.rect):null,p={ref:e.ref,locator:l,query:c};return d&&(p.x=d.x,p.y=d.y),o&&a.recordAction(o,{command:s,positionals:n.positionals??[],flags:f,result:{ref:e.ref,action:"click",locator:l,query:c}}),{ok:!0,data:p}}async function F(t,e,n){let{req:r,sessionName:o,sessionStore:i,session:s,invoke:l,command:c,publicFlags:f}=t;if(!n)return a("INVALID_ARGS","find fill requires text");let u=await l({token:r.token,session:o,command:"fill",positionals:[e.ref,n],flags:e.actionFlags});return u.ok&&s&&i.recordAction(s,{command:c,positionals:r.positionals??[],flags:f,result:{ref:e.ref,action:"fill"}}),u}async function K(t,e){let n=await E(t,e);return n.ok&&U(t,e,"focus"),n}async function b(e,n,o){let{req:i,device:s,logPath:l,session:c}=e;if(!o)return a("INVALID_ARGS","find type requires text");let f=await E(e,n);if(!f.ok)return f;let u=await r(s,"type",[o],i.flags?.out,{...t(l,i.flags,c?.appBundleId,c?.trace?.outPath)});return U(e,n,"type"),{ok:!0,data:u??{ref:n.ref}}}async function E(e,n){var o;let i,{req:s,device:l,logPath:c,session:f}=e,u=(i=[(o=n).resolvedNode,o.node].find(g))?a("COMMAND_FAILED",`Matched element ${o.ref} is covered by another visible element and cannot be focused safely`,{ref:`@${i.ref}`,interactionBlocked:i.interactionBlocked,hint:"Use a different visible target, scroll it clear of the overlay, or inspect with snapshot/screenshot before retrying."}):null;if(u)return u;let d=n.resolvedNode.rect?y(n.resolvedNode.rect):null;return d?{ok:!0,data:await r(l,"focus",[String(d.x),String(d.y)],s.flags?.out,{...t(c,s.flags,f?.appBundleId,f?.trace?.outPath)})??{ref:n.ref}}:a("COMMAND_FAILED","matched element has no bounds")}function U(t,e,n){let{req:r,sessionStore:a,session:o,command:i,publicFlags:s}=t;o&&a.recordAction(o,{command:i,positionals:r.positionals??[],flags:s,result:{ref:e.ref,action:n}})}function L(t){return"role"!==t}export{parseFindArgs}from"./7556.js";export{A as handleFindCommands};
|
package/dist/src/generic.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import t from"node:fs";import e from"node:path";import{formatDurationSeconds as r}from"./9542.js";import{AppError as s}from"./9152.js";import{printJson as n}from"./
|
|
1
|
+
import t from"node:fs";import e from"node:path";import{formatDurationSeconds as r}from"./9542.js";import{AppError as s}from"./9152.js";import{printJson as n}from"./cli-output.js";import{runCliCommandWithOutput as i,writeCommandOutput as o}from"./cli.js";import{readCommandMessage as a}from"./6133.js";function u(s){var n,i;if("skipped"===s.status)return[];let o=(n=s).artifactsDir?e.join(n.artifactsDir,`attempt-${n.attempts}`,"replay-timing.ndjson"):void 0;if(!o)return[];let a=function(e){try{return t.readFileSync(e,"utf8").split(/\r?\n/).filter(t=>t.trim().length>0).flatMap(t=>{try{let e=JSON.parse(t);return c(e)?[e]:[]}catch{return[]}})}catch{return[]}}(o);if(0===a.length)return[];let u=[],m=[];for(let t of a){if("replay_action_start"===(i=t).type&&d(i)&&f(i,"line")&&l(i,"command")&&(void 0===i.positionals||Array.isArray(i.positionals))){u.push(t);continue}(function(t){var e;return["replay_action_stop"===t.type&&d(t)&&f(t,"line")&&l(t,"command"),void 0===(e=t).ok||"boolean"==typeof e.ok,f(t,"durationMs"),l(t,"errorCode"),void 0===t.resultTiming||c(t.resultTiming)].every(Boolean)})(t)&&m.push({stop:t,start:function(t,e){let r=e.command,s=t.findIndex(t=>t.step===e.step&&(void 0===r||void 0===t.command||t.command===r));if(!(s<0))return t.splice(s,1)[0]}(u,t)})}return 0===m.length?[]:[s.attempts>1?`steps (attempt ${s.attempts}):`:"steps:",...m.map(({stop:t,start:e})=>{var s,n,i,o,a,u;let d,f,l;return s=t,n=e,d=!1===s.ok?"[FAIL] ":!0===s.ok?"":"[info] ",` ${d}${i=n,o=s,[function(t){if(!t)return"unknown";if(!t.startsWith("__maestro"))return t;let e=t.slice(9);return e.length>0?e[0].toLowerCase()+e.slice(1):t}(i?.command??o.command),...(i?.positionals??[]).map(p)].join(" ")}${a=s,u=n,(l=["number"==typeof(f=u?.line??a.line)?`line ${f}`:"","number"==typeof a.durationMs?r(a.durationMs):"",a.errorCode??"",a.resultTiming?`timing ${JSON.stringify(a.resultTiming)}`:""].filter(Boolean)).length>0?` (${l.join(", ")})`:""}`})]}function d(t){return"number"==typeof t.step}function f(t,e){return void 0===t[e]||"number"==typeof t[e]}function l(t,e){return void 0===t[e]||"string"==typeof t[e]}function p(t){return"string"==typeof t?JSON.stringify(t):"number"==typeof t||"boolean"==typeof t?String(t):JSON.stringify(t)}function c(t){return!!t&&"object"==typeof t&&!Array.isArray(t)}function m(t){var r,s;let n,i,o,a=t.attempts>1?` after ${t.attempts} attempts`:"",d=y(t);for(let u of(process.stdout.write(`FAIL ${(n=h(r=t),i=e.basename(r.file),o=n&&n.length>0?`${JSON.stringify(n)} in ${i}`:i,`${o}${M(r)}`)}${a}${d}
|
|
2
2
|
`),process.stdout.write(` ${t.error?.message??"Unknown test failure"}
|
|
3
3
|
`),[A((s=t).error),w(s,"artifacts"),C(s.error,"log"),b(s.error,"diagnostic")].filter(k)))process.stdout.write(` ${u}
|
|
4
4
|
`);for(let e of u(t))process.stdout.write(` ${e}
|
|
5
|
-
`)}function $(t){return"passed"===t.status&&t.attempts>1}function g(t){let r=h(t),s=r&&r.length>0?JSON.stringify(r):e.basename(t.file);return`${s}${M(t)}`}function h(t){let e=t.title?.trim();return e&&e.length>0?e:void 0}function y(t){if("passed"===t.status&&t.attempts>1)return v(t);if("failed"===t.status&&t.attempts>1&&t.durationMs>0)return` (total ${r(t.durationMs)})`;let e="passed"===t.status&&"number"==typeof t.finalAttemptDurationMs?t.finalAttemptDurationMs:t.durationMs;return e>0?` (${r(e)})`:""}function v(t){let e=["number"==typeof t.finalAttemptDurationMs?`passed attempt ${r(t.finalAttemptDurationMs)}`:"",t.durationMs>0?`total ${r(t.durationMs)}`:""].filter(Boolean);return e.length>0?` (${e.join(", ")})`:""}function M(t){if(!("shardIndex"in t)||"number"!=typeof t.shardIndex)return"";let e="number"==typeof t.shardCount?t.shardCount:"?",r="string"==typeof t.deviceId?` ${t.deviceId}`:"";return` [shard ${t.shardIndex+1}/${e}${r}]`}function _(t,e,r={}){r.includeMessage&&t.push(`errorMessage: ${e.message}`),I(t,A(e)),I(t,b(e,"diagnosticId")),I(t,C(e,"logPath")),!1!==r.includeDetails&&S(t,e,r.detailsIndent)}function S(t,e,r){let s=e.details?JSON.stringify(e.details,null,r):void 0;s&&t.push(`details: ${s}`)}function w(t,e){return"artifactsDir"in t&&t.artifactsDir?`${e}: ${t.artifactsDir}`:void 0}function A(t){return t.hint?`hint: ${t.hint}`:void 0}function b(t,e){return t.diagnosticId?`${e}: ${t.diagnosticId}`:void 0}function C(t,e){return t.logPath?`${e}: ${t.logPath}`:void 0}function I(t,e){e&&t.push(e)}function k(t){return void 0!==t}function
|
|
6
|
-
`}(n),"utf8")}catch(e){let t=e instanceof Error?e.message:String(e);throw new s("COMMAND_FAILED",`Failed to write JUnit report to ${r}: ${t}`)}}(
|
|
5
|
+
`)}function $(t){return"passed"===t.status&&t.attempts>1}function g(t){let r=h(t),s=r&&r.length>0?JSON.stringify(r):e.basename(t.file);return`${s}${M(t)}`}function h(t){let e=t.title?.trim();return e&&e.length>0?e:void 0}function y(t){if("passed"===t.status&&t.attempts>1)return v(t);if("failed"===t.status&&t.attempts>1&&t.durationMs>0)return` (total ${r(t.durationMs)})`;let e="passed"===t.status&&"number"==typeof t.finalAttemptDurationMs?t.finalAttemptDurationMs:t.durationMs;return e>0?` (${r(e)})`:""}function v(t){let e=["number"==typeof t.finalAttemptDurationMs?`passed attempt ${r(t.finalAttemptDurationMs)}`:"",t.durationMs>0?`total ${r(t.durationMs)}`:""].filter(Boolean);return e.length>0?` (${e.join(", ")})`:""}function M(t){if(!("shardIndex"in t)||"number"!=typeof t.shardIndex)return"";let e="number"==typeof t.shardCount?t.shardCount:"?",r="string"==typeof t.deviceId?` ${t.deviceId}`:"";return` [shard ${t.shardIndex+1}/${e}${r}]`}function _(t,e,r={}){r.includeMessage&&t.push(`errorMessage: ${e.message}`),I(t,A(e)),I(t,b(e,"diagnosticId")),I(t,C(e,"logPath")),!1!==r.includeDetails&&S(t,e,r.detailsIndent)}function S(t,e,r){let s=e.details?JSON.stringify(e.details,null,r):void 0;s&&t.push(`details: ${s}`)}function w(t,e){return"artifactsDir"in t&&t.artifactsDir?`${e}: ${t.artifactsDir}`:void 0}function A(t){return t.hint?`hint: ${t.hint}`:void 0}function b(t,e){return t.diagnosticId?`${e}: ${t.diagnosticId}`:void 0}function C(t,e){return t.logPath?`${e}: ${t.logPath}`:void 0}function I(t,e){e&&t.push(e)}function k(t){return void 0!==t}function D(t){return"passed"!==t.status?[]:(t.warnings??[]).map(t=>`warning: ${t}`)}function j(t){return(Math.max(0,t)/1e3).toFixed(3)}function x(t){return t.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}async function N({command:d,positionals:f,flags:l,client:p}){var c,A,b,C,k;let{result:P,cliOutput:F}=await i({client:p,command:d,positionals:f,flags:l});if(F){c=l,A=F,!c.json&&A.stderr&&process.stderr.write(A.stderr),o(c,c.json?A.jsonData??A.data:A.data,()=>A.text)}else{let i=(b=d,C=l,k=P,"test"===b?function(i){let{suite:o,json:a,verbose:d,reportJunit:f}=i;return(f&&function(r,n){let i=e.dirname(r);try{t.mkdirSync(i,{recursive:!0}),t.writeFileSync(r,function(t){let r=['<?xml version="1.0" encoding="UTF-8"?>',"<testsuites>",` <testsuite name="agent-device replay suite" tests="${t.total}" failures="${t.failed}" skipped="${t.skipped}" time="${j(t.durationMs)}">`];for(let s of t.tests)r.push(...function(t){let r=x(`${h(t)??e.basename(t.file)}${M(t)}`),s=x(`${"."===e.dirname(t.file)?t.file:e.dirname(t.file)}${M(t)}`),n=x(t.file),i=j(t.durationMs),o=[` <testcase classname="${s}" name="${r}" file="${n}" time="${i}">`];"failed"===t.status?o.push(` <failure message="${x(t.error.message)}">${x(function(t){let e=[t.error.message];return _(e,t.error,{includeDetails:!1}),I(e,w(t,"artifactsDir")),S(e,t.error,2),e.join("\n")}(t))}</failure>`):"skipped"===t.status&&o.push(` <skipped message="${x(t.message)}" />`);let a=function(t){let e=[`status: ${t.status}`,`durationMs: ${t.durationMs}`];return function(t,e){var r,s,n,i;for(let r of(I(t,"attempts"in e?`attempts: ${e.attempts}`:void 0),I(t,"session"in e?`session: ${e.session}`:void 0),I(t,"replayed"in e?`replayed: ${e.replayed}`:void 0),I(t,"healed"in e?`healed: ${e.healed}`:void 0),D(e)))t.push(r);I(t,w(e,"artifactsDir")),r=t,s=e,"shardIndex"in s&&"number"==typeof s.shardIndex&&(r.push(`shardIndex: ${s.shardIndex}`),I(r,"number"==typeof s.shardCount?`shardCount: ${s.shardCount}`:void 0),I(r,"string"==typeof s.deviceId?`deviceId: ${s.deviceId}`:void 0)),"failed"===e.status&&(n=t,i=e,n.push(`errorCode: ${i.error.code}`),_(n,i.error,{includeMessage:!0})),I(t,$(e)?"flaky: true":void 0)}(e,t),e.join("\n")}(t);return a&&o.push(` <system-out>${x(a)}</system-out>`),o.push(" </testcase>"),o}(s));return r.push(" </testsuite>"),r.push("</testsuites>"),`${r.join("\n")}
|
|
6
|
+
`}(n),"utf8")}catch(e){let t=e instanceof Error?e.message:String(e);throw new s("COMMAND_FAILED",`Failed to write JUnit report to ${r}: ${t}`)}}(f,o),a)?(n({success:!0,data:o}),+(o.failed>0)):function(t,e={}){let s=t.tests.filter($);if(e.verbose)for(let e of t.tests)!function(t){var e;if("failed"===t.status)return m(t);let r=y(t);for(let s of(process.stdout.write(`${"passed"===(e=t).status?"PASS":"skipped"===e.status?"SKIP":"INFO"} ${g(t)}${r}
|
|
7
7
|
`),"skipped"===t.status&&process.stdout.write(` ${t.message??"skipped"}
|
|
8
|
-
`),
|
|
8
|
+
`),D(t)))process.stdout.write(` ${s}
|
|
9
9
|
`);for(let e of u(t))process.stdout.write(` ${e}
|
|
10
10
|
`)}(e);else for(let e of t.tests)!function(t){if("failed"===t.status)return m(t);if("passed"===t.status)for(let e of(process.stdout.write(`PASS ${g(t)}${y(t)}
|
|
11
|
-
`),
|
|
11
|
+
`),D(t)))process.stdout.write(` ${e}
|
|
12
12
|
`)}(e);let n="number"==typeof t.durationMs?t.durationMs:void 0,i=s.length>0?`, ${s.length} flaky`:"",o=void 0!==n?` in ${r(n)}`:"";return process.stdout.write(`Test summary: ${t.passed} passed, ${t.failed} failed${i}${o}
|
|
13
13
|
`),function(t){if(0!==t.length)for(let e of(process.stdout.write("Flaky tests:\n"),t))for(let t of(process.stdout.write(` PASS ${g(e)} after ${e.attempts} attempts${v(e)}
|
|
14
14
|
`),e.attemptFailures??[])){let e="number"==typeof t.durationMs?` (${r(t.durationMs)})`:"";process.stdout.write(` attempt ${t.attempt} failed${e}: ${t.message}
|