agent-device 0.17.8 → 0.17.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +18 -0
  2. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.8.apk → agent-device-android-multitouch-helper-0.17.10.apk} +0 -0
  3. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.10.apk.sha256 +1 -0
  4. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.8.manifest.json → agent-device-android-multitouch-helper-0.17.10.manifest.json} +4 -4
  5. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.8.apk → agent-device-android-snapshot-helper-0.17.10.apk} +0 -0
  6. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.10.apk.sha256 +1 -0
  7. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.8.manifest.json → agent-device-android-snapshot-helper-0.17.10.manifest.json} +6 -6
  8. package/dist/src/1404.js +1 -0
  9. package/dist/src/2133.js +1 -1
  10. package/dist/src/2577.js +1 -1
  11. package/dist/src/2948.js +30 -1
  12. package/dist/src/4428.js +1 -1
  13. package/dist/src/587.js +1 -1
  14. package/dist/src/7394.js +5 -5
  15. package/dist/src/8184.js +1 -1
  16. package/dist/src/8358.js +1 -1
  17. package/dist/src/9581.js +2 -2
  18. package/dist/src/9722.js +36 -36
  19. package/dist/src/9836.js +1 -1
  20. package/dist/src/9919.js +5 -5
  21. package/dist/src/android.js +3 -3
  22. package/dist/src/apple.js +1 -1
  23. package/dist/src/apps.js +1 -1
  24. package/dist/src/cli-help.js +93 -27
  25. package/dist/src/cli-output.js +1 -4
  26. package/dist/src/cli.js +18 -18
  27. package/dist/src/command-surface.js +1 -1
  28. package/dist/src/find.js +1 -1
  29. package/dist/src/generic.js +5 -5
  30. package/dist/src/index.d.ts +12 -0
  31. package/dist/src/input-actions.js +1 -1
  32. package/dist/src/input-actions~1.js +1 -1
  33. package/dist/src/interaction.js +1 -1
  34. package/dist/src/internal/bin.js +1 -1
  35. package/dist/src/react-native.js +1 -1
  36. package/dist/src/record-trace-recording.js +1 -1
  37. package/dist/src/selector-runtime.js +1 -1
  38. package/dist/src/selectors.js +1 -1
  39. package/dist/src/server.js +1 -1
  40. package/dist/src/session.js +7 -7
  41. package/dist/src/snapshot.js +1 -1
  42. package/dist/src/web.js +1 -1
  43. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +92 -4
  44. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
  45. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +130 -0
  46. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +4 -2
  47. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +18 -0
  48. package/package.json +3 -3
  49. package/server.json +2 -2
  50. package/skills/agent-device/SKILL.md +1 -0
  51. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.8.apk.sha256 +0 -1
  52. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.8.apk.sha256 +0 -1
  53. package/dist/src/6311.js +0 -27
  54. package/dist/src/7244.js +0 -1
  55. package/dist/src/9873.js +0 -1
package/dist/src/cli.js CHANGED
@@ -1,15 +1,15 @@
1
- import{pathToFileURL as e}from"node:url";import t from"node:fs";import n,{randomBytes as r,randomUUID as o}from"node:crypto";import s from"node:path";import a from"node:http";import{Readable as i}from"node:stream";import{pipeline as l}from"node:stream/promises";import{resolveRemoteConfigProfile as c,resolveRemoteConfigPath as d,REMOTE_CONFIG_FIELD_SPECS as u,parseSourceValue as f,buildPrimaryEnvVarName as m}from"./4723.js";import{isClientBackedCliCommandName as p,listCliCommandNames as g}from"./2133.js";import{getCliCommandSchema as h,applyCommandDefaults as w,getCommandSchema as v}from"./9581.js";import{asAppError as y,normalizeError as I,AppError as A}from"./733.js";import{buildCommandUsageText as S,buildUsageText as _}from"./cli-help.js";import{ensureCompanionTunnel as k,stopCompanionTunnel as D}from"./8275.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as C}from"./4069.js";import{createRequestId as N,withDiagnosticsScope as b,getDiagnosticsMeta as R,flushDiagnosticsToSessionFile as U,emitDiagnostic as E}from"./432.js";import{buildDaemonHealthPayload as x,resolveDaemonPaths as T}from"./8358.js";import{stopMetroTunnel as P}from"./metro.js";import{runCmdStreaming as L,runCmd as B}from"./8875.js";import{formatSnapshotDiffText as $,formatScreenshotDiffText as M,printHumanError as O,printJson as V}from"./6311.js";import{setupManagedAgentBrowser as G,localCommandPolicy as j,doctorManagedAgentBrowser as K,timingSafeStringEqual as H,createAgentDevice as F}from"./2577.js";import{ensureDaemon as q,sendToDaemon as J,createAgentDeviceClient as W,resolveClientSettings as z}from"./9919.js";import{parseSelectorChain as Z}from"./9836.js";import{stringifyMaestroYamlDocuments as Y,parseReplayScriptDetailed as X,formatMaestroPoint as Q,readReplayScriptMetadata as ee}from"./4428.js";import{resolveUserPath as et,expandUserHomePath as en}from"./9612.js";import{interactionCliReaders as er,observabilityCliReaders as eo,parseInstallSourceConfig as es,getFlagDefinition as ea,gestureCliReaders as ei,reactNativeCliReaders as el,getFlagDefinitions as ec,captureCliReaders as ed,GLOBAL_FLAG_KEYS as eu,replayCliReaders as ef,batchCliReaders as em,appCliReaders as ep,selectorCliReaders as eg,recordingCliReaders as eh,systemCliReaders as ew,perfCliReaders as ev}from"./9873.js";import{isCommandName as ey,metroCliReaders as eI,debuggingCliReaders as eA}from"./2948.js";import{formatCliOutput as eS}from"./cli-output.js";import{runCommand as e_}from"./command-surface.js";import{createLocalArtifactAdapter as ek}from"./314.js";import{readVersion as eD}from"./7244.js";import{maybeRunUpgradeNotifier as eC}from"./5448.js";function eN(e,t){for(let[n,r]of Object.entries(t))void 0!==r&&(e[n]=r);return e}let eb=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),eR=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),eU=function(){let e=new Map;for(let t of ec()){let n=e.get(t.key);n?n.push(t):e.set(t.key,[t])}let t=new Map;for(let e of eu)t.set(e,new Set(["*"]));for(let e of g()){let n=h(e);for(let r of[...n.allowedFlags??[],...n.supportedFlags??[]]){let n=t.get(r);n&&n.has("*")||(n?n.add(e):t.set(r,new Set([e])))}}return[...e.entries()].map(([e,n])=>({key:e,flagDefinitions:n,config:{enabled:!eb.has(e),key:e},env:{names:eR.has(e)?[]:[m(e)]},supportsCommand(n){let r=t.get(e);return!!r&&(!!r.has("*")||!!n&&r.has(n))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),eE=new Map(eU.map(e=>[e.key,e]));function ex(e,t){return eE.get(e)?.supportsCommand(t)??!1}function eT(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let n=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===n.type){let t=n.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...n,setValue:void 0,enumValues:t}}return n}function eP(e){let t={json:!1,help:!1,version:!1},n=null,r=[],o=[],s=!0;for(let c=0;c<e.length;c+=1){var a,i,l;let d=e[c];if(s&&"--"===d){s=!1;continue}if(!s){n?r.push(d):n=eM(d);continue}let u=d.startsWith("--"),f=d.startsWith("-")&&d.length>1;if(!u&&!f){n?r.push(d):n=eM(d);continue}let[m,p]=u?eL(d):[d,void 0];if(a=n,"-c"===m&&("snapshot"===a||"diff"===a))continue;let g=function(e,t){let n=ec().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??ea(e);if(t){let e=n.find(e=>ex(e.key,t));if(e)return e}return ea(e)}(m,n);if(i=n,l=g,"react-devtools"===i&&(!l||!ex(l.key,i))){r.push(d);continue}if(!g){if(function(e,t,n){var r;if(r=n,!/^-\d+(\.\d+)?$/.test(r)||!e)return!1;let o=v(e);if(!o||o.allowsExtraPositionals)return!0;let s=o.positionalArgs??[];return 0!==s.length&&(t.length<s.length||s.some(e=>e.includes("?")))}(n,r,d)){n?r.push(d):n=d;continue}throw new A("INVALID_ARGS",`Unknown flag: ${m}`)}let h=function(e,t,n,r){if(void 0!==e.setValue){if(void 0!==n)throw new A("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==n)throw new A("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==n){if(0===n.trim().length)throw new A("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:n,consumeNext:!1}}return void 0===r||e$(r)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(r)?{value:!0,consumeNext:!1}:{value:r,consumeNext:!0}}let o=n??r;if(void 0===o||void 0===n&&e$(o))throw new A("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:o,consumeNext:void 0===n};if("enum"===e.type){if(!e.enumValues?.includes(o))throw new A("INVALID_ARGS",`Invalid ${eB(t)}: ${o}`);return{value:o,consumeNext:void 0===n}}let s=Number(o);if(!Number.isFinite(s)||"number"==typeof e.min&&s<e.min||"number"==typeof e.max&&s>e.max)throw new A("INVALID_ARGS",`Invalid ${eB(t)}: ${o}`);return{value:Math.floor(s),consumeNext:void 0===n}}(g,m,p,e[c+1]);h.consumeNext&&(c+=1);let w=t[g.key];if(g.multiple){let e=Array.isArray(w)?[...w,h.value]:void 0===w?[h.value]:[w,h.value];t[g.key]=e}else t[g.key]=h.value;o.push({key:g.key,token:m})}return{command:n,positionals:r,flags:t,warnings:[],providedFlags:o}}function eL(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function eB(e){return e.replace(/^-+/,"")}function e$(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?eL(e):[e,void 0];return void 0!==ea(t)}function eM(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}let eO={slug:"react-devtools-companion",runArg:C,displayName:"React DevTools companion"};async function eV(e){return await k({...e,definition:eO,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 D({...e,definition:eO})}function ej(e){var n;let r,o=eJ(e);if(!t.existsSync(o))return null;try{r=JSON.parse(t.readFileSync(o,"utf8"))}catch(t){return eX(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:(eX(e),null)}function eK(e){let n=eJ({stateDir:e.stateDir,session:e.state.session});t.mkdirSync(s.dirname(n),{recursive:!0}),eY(n,e.state),eY(eW(e.stateDir),{session:e.state.session})}function eH(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 eF(e){t.rmSync(eJ(e),{force:!0});let n=eW(e.stateDir);eZ(e.stateDir)===e.session&&t.rmSync(n,{force:!0})}function eq(e){try{return n.createHash("sha256").update(t.readFileSync(e)).digest("hex")}catch(t){throw new A("INVALID_ARGS",`Remote config file not found: ${e}`,{cause:t instanceof Error?t.message:String(t)})}}function eJ(e){return s.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 eW(e){return s.join(e,"remote-connections",".active-session.json")}function ez(e){let t=eZ(e.stateDir);return t?ej({stateDir:e.stateDir,session:t}):null}function eZ(e){let n=eW(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 eY(e,n){t.writeFileSync(e,`${JSON.stringify(n,null,2)}
2
- `,{encoding:"utf8",mode:384}),t.chmodSync(e,384)}function eX(e,t){E({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eF(e)}let eQ=u.map(e=>e.key);function e0(e){let t={};for(let n of eQ){let r=e[n];void 0!==r&&(t[n]=r)}return t}let e1=new Set(["connect","connection","close","disconnect","metro","session"]),e3=new Set(["open"]);async function e8(e){let t,n,{command:r,flags:o,client:s}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let a=T(o.stateDir).baseDir,i=c({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),l={...e0(i.profile),...o,remoteConfig:i.resolvedPath},d=ej({stateDir:a,session:l.session??"default"});if(d&&d.remoteConfigPath!==i.resolvedPath)throw new A("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 A("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new A("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new A("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:eq(t),daemon:eH(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??e6(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(l,i.resolvedPath),f={...l,session:u.session},m=function(e,t){if(e)return te(e,t)?e:void 0}(u.runtime,f.platform)??e.runtime,p=u,g=!d;if(h=r,!e1.has(h)){let e=u.leaseBackend??function(e,t){let n=e6(e);if(n)return n;throw new A("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var h,w,v,y,I,S=u,_=o,k=e;if(S.leaseBackend&&S.leaseBackend!==k)throw new A("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&&_.platform&&S.platform!==_.platform)throw new A("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&&_.target&&S.target!==_.target)throw new A("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 tt(s,p,e);f.leaseId=t.leaseId,f.leaseBackend=e,f.platform=p.platform??f.platform,f.target=p.target??f.target,(p.leaseId!==t.leaseId||p.leaseBackend!==e)&&(p={...p,leaseId:t.leaseId,leaseBackend:e,platform:p.platform??o.platform,target:p.target??o.target,updatedAt:new Date().toISOString()},g=!0)}if(w=r,v=e.batchSteps,(e3.has(w)||"batch"===w&&v&&v.some(e=>{let t=e.command.trim().toLowerCase();return e3.has(t)&&void 0===e.runtime}))&&e9(f)&&(!p.leaseId&&f.leaseId&&(p={...p,leaseId:f.leaseId,leaseBackend:f.leaseBackend}),e.forceRuntimePrepare||!m||!te(m,f.platform))){if(!p.leaseId)throw new A("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await e2(f,s,u.remoteConfigPath,u.session,{tenantId:u.tenant,runId:u.runId,leaseId:p.leaseId});m=e.runtime;let o=(y=p.metro,I=e.cleanup,y?.projectRoot!==I?.projectRoot||y?.profileKey!==I?.profileKey||y?.consumerKey!==I?.consumerKey);t=o?p.metro:void 0,n=o?e.cleanup:void 0,p={...p,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},g=!0}if(g)try{eK({stateDir:a,state:p})}catch(e){throw await e4(n),e}return await e4(t),{flags:{...f,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??f.platform,target:p.target??f.target},runtime:m}}async function e2(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new A("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new A("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 A("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 e4(e){if(e)try{await P(e)}catch{}}async function e5(e){try{await eG({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function e7(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 e6(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function e9(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function te(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function tt(e,t,n){if(t.leaseId&&t.leaseBackend===n){let r=await tn(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 tn(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 A&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}async function tr(e,t){let n=await e.text(),r={};if(n.trim().length>0)try{r=JSON.parse(n)}catch(n){throw new A("COMMAND_FAILED",t.invalidJsonMessage,{status:e.status},n instanceof Error?n:void 0)}if(!e.ok)throw new A("UNAUTHORIZED",t.rejectedMessage,{status:e.status,response:r});return r}async function to(e){return await ts({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:"connect"===e.command&&!e.flags.noLogin,env:e.env})}async function ts(e){let t=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:"none"};if(ty(e.flags.daemonAuthToken))return{flags:e.flags,source:"flag"};if(ty(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||ty(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 td({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 A("UNAUTHORIZED","Remote daemon authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});throw tp(e.command,t)}let r=await ti({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:"login"}}async function ta(e){let t=e.env??e.io?.env??process.env;if(ty(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:tg(t)};if(ty(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:t.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:tg(t)};let n=await td({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 A("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 ti({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 ti(e){let n,r,o,a=e.env??e.io?.env??process.env,i=(d=a,u=e.io,n=u?.stdinIsTTY??process.stdin.isTTY,r=u?.stdoutIsTTY??process.stdout.isTTY,"true"!==(f=d).CI&&"true"!==f.GITHUB_ACTIONS&&"true"!==f.BUILDKITE&&n&&r?(m=d).SSH_TTY||m.SSH_CONNECTION||"true"===m.CODESPACES||m.GITPOD_WORKSPACE_ID||"true"===m.REMOTE_CONTAINERS?"device-code":"local-browser":"non-interactive");if("non-interactive"===i)throw tp(e.commandLabel??"agent-device connect",a);let l=tg(a),c=await tm({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,f,m,p,g,h=c;if(!ty(h.deviceCode)||!ty(h.userCode)||!ty(h.verificationUri))throw new A("COMMAND_FAILED","Cloud auth start returned an unusable response.");let w=c.verificationUriComplete??c.verificationUri,v="local-browser"===i?c.verificationUri:(p=c.verificationUri,g=c.userCode,(o=new URL(p)).searchParams.set("user_code",g),o.toString());"local-browser"===i?(tw(e.io,`Opening ${c.verificationUri}...
3
- `),await th(w,e.io)):tw(e.io,`Open this URL on your machine:
1
+ import{pathToFileURL as e}from"node:url";import t from"node:fs";import n,{randomBytes as r,randomUUID as o}from"node:crypto";import s from"node:path";import a from"node:http";import{Readable as i}from"node:stream";import{pipeline as l}from"node:stream/promises";import{resolveRemoteConfigProfile as c,resolveRemoteConfigPath as d,REMOTE_CONFIG_FIELD_SPECS as u,parseSourceValue as f,buildPrimaryEnvVarName as m}from"./4723.js";import{isClientBackedCliCommandName as p,listCliCommandNames as g}from"./2133.js";import{getCliCommandSchema as h,applyCommandDefaults as w,getCommandSchema as v}from"./9581.js";import{asAppError as y,normalizeError as I,AppError as A}from"./733.js";import{buildCommandUsageText as S,buildUsageText as _}from"./cli-help.js";import{ensureCompanionTunnel as k,stopCompanionTunnel as D}from"./8275.js";import{REACT_DEVTOOLS_COMPANION_RUN_ARG as C}from"./4069.js";import{createRequestId as N,withDiagnosticsScope as b,getDiagnosticsMeta as R,flushDiagnosticsToSessionFile as U,emitDiagnostic as x}from"./432.js";import{buildDaemonHealthPayload as E,resolveDaemonPaths as T}from"./8358.js";import{stopMetroTunnel as P}from"./metro.js";import{runCmdStreaming as L,runCmd as B}from"./8875.js";import{formatSnapshotDiffText as $,isCommandName as M,GLOBAL_FLAG_KEYS as O,printHumanError as V,getFlagDefinition as G,parseInstallSourceConfig as j,listCommandFamilyCliReaders as H,formatScreenshotDiffText as K,printJson as F,getFlagDefinitions as q}from"./2948.js";import{setupManagedAgentBrowser as J,localCommandPolicy as W,doctorManagedAgentBrowser as z,timingSafeStringEqual as Z,createAgentDevice as Y}from"./2577.js";import{buildDaemonHttpAuthHeaders as X,sendToDaemon as Q,ensureDaemon as ee,createAgentDeviceClient as et,buildDaemonHttpBaseUrl as en,buildDaemonHttpUrl as er,resolveClientSettings as eo,DAEMON_HTTP_BASE_PATH as es}from"./9919.js";import"./9836.js";import{stringifyMaestroYamlDocuments as ea,parseReplayScriptDetailed as ei,formatMaestroPoint as el,readReplayScriptMetadata as ec}from"./4428.js";import{resolveUserPath as ed,expandUserHomePath as eu}from"./9612.js";import{formatCliOutput as ef}from"./cli-output.js";import{runCommand as em}from"./command-surface.js";import{createLocalArtifactAdapter as ep}from"./314.js";import{readVersion as eg}from"./1404.js";import{maybeRunUpgradeNotifier as eh}from"./5448.js";import{parseSelectorChain as ew}from"./587.js";function ev(e,t){for(let[n,r]of Object.entries(t))void 0!==r&&(e[n]=r);return e}let ey=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),eI=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),eA=function(){let e=new Map;for(let t of q()){let n=e.get(t.key);n?n.push(t):e.set(t.key,[t])}let t=new Map;for(let e of O)t.set(e,new Set(["*"]));for(let e of g()){let n=h(e);for(let r of[...n.allowedFlags??[],...n.supportedFlags??[]]){let n=t.get(r);n&&n.has("*")||(n?n.add(e):t.set(r,new Set([e])))}}return[...e.entries()].map(([e,n])=>({key:e,flagDefinitions:n,config:{enabled:!ey.has(e),key:e},env:{names:eI.has(e)?[]:[m(e)]},supportsCommand(n){let r=t.get(e);return!!r&&(!!r.has("*")||!!n&&r.has(n))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),eS=new Map(eA.map(e=>[e.key,e]));function e_(e,t){return eS.get(e)?.supportsCommand(t)??!1}function ek(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let n=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===n.type){let t=n.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...n,setValue:void 0,enumValues:t}}return n}function eD(e){let t={json:!1,help:!1,version:!1},n=null,r=[],o=[],s=!0;for(let c=0;c<e.length;c+=1){var a,i,l;let d=e[c];if(s&&"--"===d){s=!1;continue}if(!s){n?r.push(d):n=eR(d);continue}if("cdp"===n){r.push(d);continue}let u=d.startsWith("--"),f=d.startsWith("-")&&d.length>1;if(!u&&!f){n?r.push(d):n=eR(d);continue}let[m,p]=u?eC(d):[d,void 0];if(a=n,"-c"===m&&("snapshot"===a||"diff"===a))continue;let g=function(e,t){let n=q().filter(t=>t.names.includes(e));if(n.length<=1)return n[0]??G(e);if(t){let e=n.find(e=>e_(e.key,t));if(e)return e}return G(e)}(m,n);if(i=n,l=g,"react-devtools"===i&&(!l||!e_(l.key,i))){r.push(d);continue}if(!g){if(function(e,t,n){var r;if(r=n,!/^-\d+(\.\d+)?$/.test(r)||!e)return!1;let o=v(e);if(!o||o.allowsExtraPositionals)return!0;let s=o.positionalArgs??[];return 0!==s.length&&(t.length<s.length||s.some(e=>e.includes("?")))}(n,r,d)){n?r.push(d):n=d;continue}throw new A("INVALID_ARGS",`Unknown flag: ${m}`)}let h=function(e,t,n,r){if(void 0!==e.setValue){if(void 0!==n)throw new A("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==n)throw new A("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==n){if(0===n.trim().length)throw new A("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:n,consumeNext:!1}}return void 0===r||eb(r)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(r)?{value:!0,consumeNext:!1}:{value:r,consumeNext:!0}}let o=n??r;if(void 0===o||void 0===n&&eb(o))throw new A("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:o,consumeNext:void 0===n};if("enum"===e.type){if(!e.enumValues?.includes(o))throw new A("INVALID_ARGS",`Invalid ${eN(t)}: ${o}`);return{value:o,consumeNext:void 0===n}}let s=Number(o);if(!Number.isFinite(s)||"number"==typeof e.min&&s<e.min||"number"==typeof e.max&&s>e.max)throw new A("INVALID_ARGS",`Invalid ${eN(t)}: ${o}`);return{value:Math.floor(s),consumeNext:void 0===n}}(g,m,p,e[c+1]);h.consumeNext&&(c+=1);let w=t[g.key];if(g.multiple){let e=Array.isArray(w)?[...w,h.value]:void 0===w?[h.value]:[w,h.value];t[g.key]=e}else t[g.key]=h.value;o.push({key:g.key,token:m})}return{command:n,positionals:r,flags:t,warnings:[],providedFlags:o}}function eC(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function eN(e){return e.replace(/^-+/,"")}function eb(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?eC(e):[e,void 0];return void 0!==G(t)}function eR(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}let eU={slug:"react-devtools-companion",runArg:C,displayName:"React DevTools companion"};async function ex(e){return await k({...e,definition:eU,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 eE(e){return await D({...e,definition:eU})}function eT(e){var n;let r,o=eM(e);if(!t.existsSync(o))return null;try{r=JSON.parse(t.readFileSync(o,"utf8"))}catch(t){return eH(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:(eH(e),null)}function eP(e){let n=eM({stateDir:e.stateDir,session:e.state.session});t.mkdirSync(s.dirname(n),{recursive:!0}),ej(n,e.state),ej(eO(e.stateDir),{session:e.state.session})}function eL(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 eB(e){t.rmSync(eM(e),{force:!0});let n=eO(e.stateDir);eG(e.stateDir)===e.session&&t.rmSync(n,{force:!0})}function e$(e){try{return n.createHash("sha256").update(t.readFileSync(e)).digest("hex")}catch(t){throw new A("INVALID_ARGS",`Remote config file not found: ${e}`,{cause:t instanceof Error?t.message:String(t)})}}function eM(e){return s.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 eO(e){return s.join(e,"remote-connections",".active-session.json")}function eV(e){let t=eG(e.stateDir);return t?eT({stateDir:e.stateDir,session:t}):null}function eG(e){let n=eO(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 ej(e,n){t.writeFileSync(e,`${JSON.stringify(n,null,2)}
2
+ `,{encoding:"utf8",mode:384}),t.chmodSync(e,384)}function eH(e,t){x({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eB(e)}let eK=u.map(e=>e.key);function eF(e){let t={};for(let n of eK){let r=e[n];void 0!==r&&(t[n]=r)}return t}let eq=new Set(["connect","connection","close","disconnect","metro","session"]),eJ=new Set(["open"]);async function eW(e){let t,n,{command:r,flags:o,client:s}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let a=T(o.stateDir).baseDir,i=c({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),l={...eF(i.profile),...o,remoteConfig:i.resolvedPath},d=eT({stateDir:a,session:l.session??"default"});if(d&&d.remoteConfigPath!==i.resolvedPath)throw new A("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 A("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new A("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new A("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:e$(t),daemon:eL(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??eQ(e),platform:e.platform,target:e.target,connectedAt:n,updatedAt:n}}(l,i.resolvedPath),f={...l,session:u.session},m=function(e,t){if(e)return e1(e,t)?e:void 0}(u.runtime,f.platform)??e.runtime,p=u,g=!d;if(h=r,!eq.has(h)){let e=u.leaseBackend??function(e,t){let n=eQ(e);if(n)return n;throw new A("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var h,w,v,y,I,S=u,_=o,k=e;if(S.leaseBackend&&S.leaseBackend!==k)throw new A("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&&_.platform&&S.platform!==_.platform)throw new A("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&&_.target&&S.target!==_.target)throw new A("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 e3(s,p,e);f.leaseId=t.leaseId,f.leaseBackend=e,f.platform=p.platform??f.platform,f.target=p.target??f.target,(p.leaseId!==t.leaseId||p.leaseBackend!==e)&&(p={...p,leaseId:t.leaseId,leaseBackend:e,platform:p.platform??o.platform,target:p.target??o.target,updatedAt:new Date().toISOString()},g=!0)}if(w=r,v=e.batchSteps,(eJ.has(w)||"batch"===w&&v&&v.some(e=>{let t=e.command.trim().toLowerCase();return eJ.has(t)&&void 0===e.runtime}))&&e0(f)&&(!p.leaseId&&f.leaseId&&(p={...p,leaseId:f.leaseId,leaseBackend:f.leaseBackend}),e.forceRuntimePrepare||!m||!e1(m,f.platform))){if(!p.leaseId)throw new A("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await ez(f,s,u.remoteConfigPath,u.session,{tenantId:u.tenant,runId:u.runId,leaseId:p.leaseId});m=e.runtime;let o=(y=p.metro,I=e.cleanup,y?.projectRoot!==I?.projectRoot||y?.profileKey!==I?.profileKey||y?.consumerKey!==I?.consumerKey);t=o?p.metro:void 0,n=o?e.cleanup:void 0,p={...p,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},g=!0}if(g)try{eP({stateDir:a,state:p})}catch(e){throw await eZ(n),e}return await eZ(t),{flags:{...f,session:p.session,leaseId:p.leaseId,leaseBackend:p.leaseBackend,platform:p.platform??f.platform,target:p.target??f.target},runtime:m}}async function ez(e,t,n,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new A("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new A("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 A("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 eZ(e){if(e)try{await P(e)}catch{}}async function eY(e){try{await eE({projectRoot:process.cwd(),stateDir:e.stateDir,profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function eX(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 eQ(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function e0(e){let t=e.metroKind;return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||t)}function e1(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function e3(e,t,n){if(t.leaseId&&t.leaseBackend===n){let r=await e8(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 e8(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 A&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}async function e2(e,t){let n=await e.text(),r={};if(n.trim().length>0)try{r=JSON.parse(n)}catch(n){throw new A("COMMAND_FAILED",t.invalidJsonMessage,{status:e.status},n instanceof Error?n:void 0)}if(!e.ok)throw new A("UNAUTHORIZED",t.rejectedMessage,{status:e.status,response:r});return r}async function e4(e){return await e5({command:e.command,flags:e.flags,stateDir:e.stateDir,allowInteractiveLogin:"connect"===e.command&&!e.flags.noLogin,env:e.env})}async function e5(e){let t=e.env??e.io?.env??process.env;if(!e.flags.daemonBaseUrl)return{flags:e.flags,source:"none"};if(td(e.flags.daemonAuthToken))return{flags:e.flags,source:"flag"};if(td(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||td(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 tt({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 A("UNAUTHORIZED","Remote daemon authentication is required.",{hint:"Run agent-device auth login, unset --no-login, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN."});throw ts(e.command,t)}let r=await e6({stateDir:e.stateDir,flags:e.flags,env:t,io:e.io});return{flags:{...e.flags,daemonAuthToken:r.accessToken},source:"login"}}async function e7(e){let t=e.env??e.io?.env??process.env;if(td(e.flags.daemonAuthToken))return{accessToken:e.flags.daemonAuthToken,cloudBaseUrl:ta(t)};if(td(t.AGENT_DEVICE_DAEMON_AUTH_TOKEN))return{accessToken:t.AGENT_DEVICE_DAEMON_AUTH_TOKEN,cloudBaseUrl:ta(t)};let n=await tt({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 A("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 e6({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 e6(e){let n,r,o,a=e.env??e.io?.env??process.env,i=(d=a,u=e.io,n=u?.stdinIsTTY??process.stdin.isTTY,r=u?.stdoutIsTTY??process.stdout.isTTY,"true"!==(f=d).CI&&"true"!==f.GITHUB_ACTIONS&&"true"!==f.BUILDKITE&&n&&r?(m=d).SSH_TTY||m.SSH_CONNECTION||"true"===m.CODESPACES||m.GITPOD_WORKSPACE_ID||"true"===m.REMOTE_CONTAINERS?"device-code":"local-browser":"non-interactive");if("non-interactive"===i)throw ts(e.commandLabel??"agent-device connect",a);let l=ta(a),c=await to({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,f,m,p,g,h=c;if(!td(h.deviceCode)||!td(h.userCode)||!td(h.verificationUri))throw new A("COMMAND_FAILED","Cloud auth start returned an unusable response.");let w=c.verificationUriComplete??c.verificationUri,v="local-browser"===i?c.verificationUri:(p=c.verificationUri,g=c.userCode,(o=new URL(p)).searchParams.set("user_code",g),o.toString());"local-browser"===i?(tl(e.io,`Opening ${c.verificationUri}...
3
+ `),await ti(w,e.io)):tl(e.io,`Open this URL on your machine:
4
4
  ${v}
5
5
 
6
6
  Waiting for approval for 10 minutes...
7
- `);let y=await tf({cloudBaseUrl:l,deviceCode:c.deviceCode,expiresIn:c.expiresIn,interval:c.interval,fetchImpl:e.io?.fetch,now:e.io?.now}),I=y.cliSession?.refreshCredential??y.cliSession?.refreshToken;if(!ty(y.accessToken)||!ty(I))throw new A("UNAUTHORIZED","Device authorization did not return CLI credentials.");let S=new Date(e.io?.now?.()??Date.now()).toISOString(),_={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:I,createdAt:S,expiresAt:y.cliSession?.expiresAt};return function(e){let n=tc(e.stateDir);t.mkdirSync(s.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:_}),{accessToken:y.accessToken,expiresAt:y.expiresAt,session:_}}function tl(e){let n=tc(e.stateDir);if(!t.existsSync(n))return null;try{let e=JSON.parse(t.readFileSync(n,"utf8"));if(1!==e.version||!ty(e.id)||!ty(e.cloudBaseUrl)||!ty(e.refreshCredential)||!ty(e.createdAt))return null;return e}catch{return null}}function tc(e){return s.join(e,"auth","cli-session.json")}async function td(e){let t=tl({stateDir:e.stateDir});return!t||tv(t.expiresAt,e.io?.now)?null:{accessToken:(await tu({session:t,flags:e.flags,env:e.env,io:e.io})).accessToken,cloudBaseUrl:tg(e.env,t.cloudBaseUrl)}}async function tu(e){let t=tg(e.env,e.session.cloudBaseUrl),n=await tm({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(ty(n.accessToken))return{accessToken:n.accessToken,expiresAt:n.expiresAt};if("revoked"===n.status||"revoked"===n.error)throw new A("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 A("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 tf(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 tm({baseUrl:e.cloudBaseUrl,pathName:"/api/control-plane/device-auth/poll",body:{deviceCode:e.deviceCode},fetchImpl:e.fetchImpl});if("approved"===t.status||ty(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 A("UNAUTHORIZED","Device authorization was not approved.",{status:t.status,error:t.error});await tI(o)}throw new A("TIMEOUT","Device authorization expired before approval.")}async function tm(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 tr(n,{invalidJsonMessage:`Cloud auth endpoint returned invalid JSON (${n.status}).`,rejectedMessage:"Cloud auth endpoint rejected the request."})}function tp(e,t){let n=tg(t);return new A("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 tg(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 A("INVALID_ARGS","Invalid AGENT_DEVICE_CLOUD_BASE_URL.",{cloudBaseUrl:n},e instanceof Error?e:void 0)}}async function th(e,t){if(t?.openBrowser)return void await t.openBrowser(e);let n=process.platform;try{"darwin"===n?await B("open",[e],{allowFailure:!0,timeoutMs:5e3}):"win32"===n?await B("cmd",["/c","start","",e],{allowFailure:!0,timeoutMs:5e3}):await B("xdg-open",[e],{allowFailure:!0,timeoutMs:5e3})}catch{tw(t,`Open this URL on your machine:
7
+ `);let y=await tr({cloudBaseUrl:l,deviceCode:c.deviceCode,expiresIn:c.expiresIn,interval:c.interval,fetchImpl:e.io?.fetch,now:e.io?.now}),I=y.cliSession?.refreshCredential??y.cliSession?.refreshToken;if(!td(y.accessToken)||!td(I))throw new A("UNAUTHORIZED","Device authorization did not return CLI credentials.");let S=new Date(e.io?.now?.()??Date.now()).toISOString(),_={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:I,createdAt:S,expiresAt:y.cliSession?.expiresAt};return function(e){let n=te(e.stateDir);t.mkdirSync(s.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:_}),{accessToken:y.accessToken,expiresAt:y.expiresAt,session:_}}function e9(e){let n=te(e.stateDir);if(!t.existsSync(n))return null;try{let e=JSON.parse(t.readFileSync(n,"utf8"));if(1!==e.version||!td(e.id)||!td(e.cloudBaseUrl)||!td(e.refreshCredential)||!td(e.createdAt))return null;return e}catch{return null}}function te(e){return s.join(e,"auth","cli-session.json")}async function tt(e){let t=e9({stateDir:e.stateDir});return!t||tc(t.expiresAt,e.io?.now)?null:{accessToken:(await tn({session:t,flags:e.flags,env:e.env,io:e.io})).accessToken,cloudBaseUrl:ta(e.env,t.cloudBaseUrl)}}async function tn(e){let t=ta(e.env,e.session.cloudBaseUrl),n=await to({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(td(n.accessToken))return{accessToken:n.accessToken,expiresAt:n.expiresAt};if("revoked"===n.status||"revoked"===n.error)throw new A("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 A("UNAUTHORIZED","Failed to refresh CLI session.",{hint:"Run agent-device auth login again, or set AGENT_DEVICE_DAEMON_AUTH_TOKEN.",status:n.status,error:n.error})}async function tr(e){let 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 to({baseUrl:e.cloudBaseUrl,pathName:"/api/control-plane/device-auth/poll",body:{deviceCode:e.deviceCode},fetchImpl:e.fetchImpl});if("approved"===t.status||td(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 A("UNAUTHORIZED","Device authorization was not approved.",{status:t.status,error:t.error});await tu(o)}throw new A("TIMEOUT","Device authorization expired before approval.")}async function to(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 e2(n,{invalidJsonMessage:`Cloud auth endpoint returned invalid JSON (${n.status}).`,rejectedMessage:"Cloud auth endpoint rejected the request."})}function ts(e,t){let n=ta(t);return new A("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 ta(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 A("INVALID_ARGS","Invalid AGENT_DEVICE_CLOUD_BASE_URL.",{cloudBaseUrl:n},e instanceof Error?e:void 0)}}async function ti(e,t){if(t?.openBrowser)return void await t.openBrowser(e);let n=process.platform;try{"darwin"===n?await B("open",[e],{allowFailure:!0,timeoutMs:5e3}):"win32"===n?await B("cmd",["/c","start","",e],{allowFailure:!0,timeoutMs:5e3}):await B("xdg-open",[e],{allowFailure:!0,timeoutMs:5e3})}catch{tl(t,`Open this URL on your machine:
9
9
  ${e}
10
- `)}}function tw(e,t){(e?.stderr??process.stderr).write(t)}function tv(e,t){if(!e)return!1;let n=Date.parse(e);return!Number.isFinite(n)||n<=(t?.()??Date.now())}function ty(e){return"string"==typeof e&&e.trim().length>0}async function tI(e){await new Promise(t=>setTimeout(t,e))}async function tA(e){let r=await ta({stateDir:e.stateDir,flags:e.flags,env:e.env,io:{env:e.env,fetch:e.fetchImpl}}),o=await tS({cloudBaseUrl:r.cloudBaseUrl,accessToken:r.accessToken,fetchImpl:e.fetchImpl}),a=function(e){try{return c(e)}catch(n){let t=y(n);throw new A("COMMAND_FAILED","Cloud connection profile returned invalid remote config.",{generatedConfigPath:e.configPath,cause:t.message},t)}}({configPath:function(e){var r;let o=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=s.join(e.stateDir,"remote-connections","generated");t.mkdirSync(a,{recursive:!0,mode:448});let i=s.join(a,`cloud-${(r=o,n.createHash("sha256").update(JSON.stringify(r)).digest("hex").slice(0,16))}.json`);t.writeFileSync(i,`${JSON.stringify(o,null,2)}
11
- `,{mode:384});try{t.chmodSync(i,384)}catch{}return i}({stateDir:e.stateDir,profile:o}),cwd:e.cwd,env:e.env});return{flags:{...e0(a.profile),...e.flags,remoteConfig:a.resolvedPath,daemonAuthToken:r.accessToken},remoteConfigPath:a.resolvedPath}}async function tS(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 tr(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 A("COMMAND_FAILED","Cloud connection profile response is invalid.");let o=r.connection;if(!o||"object"!=typeof o)throw new A("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 A("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is invalid.");if(0===Object.keys(s).length)throw new A("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is empty.");return s}throw new A("COMMAND_FAILED","Cloud connection profile did not include remoteConfigProfile.")}function t_(e,t,n){var r;if(e.json)return void V({success:!0,data:t});let o=n?.();o&&(r=o,process.stdout.write(r.endsWith("\n")?r:`${r}
12
- `))}let tk=async({flags:e,client:t})=>{var r,o,s,a;let i=T(e.stateDir).baseDir,l=e.remoteConfig?function(e){if(!e.remoteConfig)throw new A("INVALID_ARGS","connect requires --remote-config <path>.");let t=c({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await tA({flags:e,stateDir:i,cwd:process.cwd(),env:process.env}),d=l.flags,u=d.tenant,f=d.runId;if(!u)throw new A("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!f)throw new A("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!d.daemonBaseUrl)throw new A("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let m=d.session?null:ez({stateDir:i}),p=d.session??m?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${n.randomBytes(3).toString("hex")}`;if(!ej({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${n.randomBytes(2).toString("hex")}`}(i),g=eq(l.remoteConfigPath),h=eH(d),w=m?.session===p?m:ej({stateDir:i,session:p});if(w&&(r=w,o={flags:d,session:p,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:g,desiredLeaseBackend:e6(d),daemon:h},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 A("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:p,remoteConfig:w.remoteConfigPath});let v=new Date().toISOString(),y={version:1,session:p,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:g,daemon:h,tenant:u,runId:f,leaseId:w&&!d.force?w.leaseId:void 0,leaseBackend:w&&!d.force?w.leaseBackend:e6(d),platform:d.platform??(w&&!d.force?w.platform:void 0),target:d.target??(w&&!d.force?w.target:void 0),runtime:w&&!d.force?w.runtime:void 0,metro:w&&!d.force?w.metro:void 0,connectedAt:w&&!d.force?w.connectedAt:v,updatedAt:v};eK({stateDir:i,state:y}),w&&d.force&&(await e4(w.metro),await e5({stateDir:i,state:w}),await e7(t,w));let I=tR(y),S=function(e,t){if(!t.runtime&&(e9(e)||tE(t.remoteConfigPath)))return tU(t.remoteConfigPath)}(d,y);return t_(d,tx(y,S),()=>[`Connected remote session "${p}" tenant "${u}" run "${f}" ${y.leaseId?`lease ${y.leaseId}`:"lease pending"}`,I?.message,S?.message].filter(e=>!!e).join("\n")),!0},tD=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=tN(e);if(!o)return tb(e,n),!0;let s=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await e4(o.metro),await e5({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 eF({stateDir:r,session:s}),t_(e,{connected:!1,session:s,released:a},()=>`Disconnected remote session "${s}".`),!0},tC=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new A("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=tN(t);if(!r)return tb(t,n),!0;let o=tR(r),s=function(e){if(!e.runtime&&tE(e.remoteConfigPath))return tU(e.remoteConfigPath)}(r);return t_(t,tx(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 tN(e){let t=e.session??"default",n=T(e.stateDir).baseDir;return{session:t,stateDir:n,state:ej({stateDir:n,session:t})??(e.session?null:ez({stateDir:n}))}}function tb(e,t){t_(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 tU(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=c({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function tx(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 tT=async({positionals:e,flags:n})=>{let r=e[0]??"status",o=T(n.stateDir).baseDir;if("status"===r){var s;let e,t=(e=tl({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:tv(e.expiresAt,s.now)}:{authenticated:!1,source:"none"};return t_(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 ti({stateDir:o,flags:n,commandLabel:"agent-device auth login"});return t_(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=tc({stateDir:o}.stateDir),!!t.existsSync(e)&&(t.rmSync(e,{force:!0}),!0));return t_(n,{authenticated:!1,removed:r},()=>r?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new A("INVALID_ARGS","auth accepts only: status, login, logout")},tP="/agent-device/",tL=["content-type","x-artifact-type","x-artifact-filename"],tB=["content-type","content-disposition","x-request-id"];async function t$(e,t,n){var r,o,s,a,i,l,c;let d,u,f,m="/agent-device"===(d=new URL(e.url??"/","http://127.0.0.1").pathname)?"/":d.startsWith(tP)?`/${d.slice(tP.length)}`:d;if("GET"===e.method&&"/health"===m)return void await tM(t,n);if(r=m,o=e.method,"/rpc"===r||"/upload"===r?"POST"!==o:!r.startsWith("/artifacts/")||"GET"!==o){t.statusCode=404,t.end("Not found");return}("/rpc"===m&&(f=(await tK(e,n.maxRpcBodyBytes)).toString("utf8")),s=e,a=n.clientToken,(u=function(e,t){let n="string"==typeof e.headers.authorization?e.headers.authorization:"";if(n.toLowerCase().startsWith("bearer "))return n.slice(7);let r=e.headers["x-agent-device-token"];if("string"==typeof r)return r;if(t){let e=function(e){try{let t=JSON.parse(e);return"string"==typeof t.params?.token?t.params.token:""}catch{return""}}(t);if(e)return e}return""}(s,f)).length>0&&H(u,a))?await tV({req:e,res:t,route:m,options:n,rpcBody:f}):(i=t,l=m,c=function(e){if(!e)return null;try{return JSON.parse(e).id??null}catch{return null}}(f),(i.statusCode=401,i.setHeader("content-type","application/json"),"/rpc"===l)?i.end(JSON.stringify({jsonrpc:"2.0",id:c,error:{code:-32001,message:"Invalid proxy token",data:I(new A("UNAUTHORIZED","Invalid proxy token"))}})):i.end(JSON.stringify({ok:!1,error:"Invalid proxy token",code:"UNAUTHORIZED"})))}async function tM(e,t){let n=await tO(t);e.statusCode=200,e.setHeader("content-type","application/json"),e.end(JSON.stringify(x("agent-device-proxy",{upstream:n})))}async function tO(e){let t=new URL("health",`${e.upstreamBaseUrl}/`),n=await e.fetchImpl(t,{method:"GET",headers:tj({headers:{}},e.upstreamToken,"/health"),signal:AbortSignal.timeout(e.upstreamTimeoutMs)}),r=await n.text();try{return r?JSON.parse(r):{ok:n.ok,status:n.status}}catch{return{ok:n.ok,status:n.status}}}async function tV(e){var t,n,r;let s,a,c,{req:d,res:u,route:f,options:m,rpcBody:p}=e,g=(t=m.upstreamBaseUrl,n=f,r=d.url??"/",s=new URL(n.replace(/^\//,""),`${t}/`),(a=r.indexOf("?"))>=0&&(s.search=r.slice(a)),s),h=d.method??"GET",w=tj(d,m.upstreamToken,f),v=function(e,t,n,r){if("GET"!==e.method&&"HEAD"!==e.method){var o,s;let a;return"/rpc"===t?(o=n??"",s=r,(a=JSON.parse(o)).params={...a.params??{},token:s},JSON.stringify(a)):e}}(d,f,p,m.upstreamToken),y=await m.fetchImpl(g,{method:h,headers:w,signal:AbortSignal.timeout(m.upstreamTimeoutMs),...v?{body:v,duplex:"half"}:{}});for(let e of(u.statusCode=y.status,tB)){let t=y.headers.get(e);t&&u.setHeader(e,t)}(u.hasHeader("x-request-id")||u.setHeader("x-request-id","string"==typeof(c=d.headers["x-request-id"])&&c.trim()?c.trim().slice(0,128):o()),y.body)?await l(i.fromWeb(y.body),u):u.end()}function tG(e,t){let n=e.trim();if(!n)throw new A("INVALID_ARGS",`Proxy ${t} is required.`);return n}function tj(e,t,n){let r=new Headers;for(let t of tL){let n=e.headers[t];"string"==typeof n&&n.trim()&&r.set(t,n)}return"/rpc"!==n||r.has("content-type")||r.set("content-type","application/json"),r.set("authorization",`Bearer ${t}`),r.set("x-agent-device-token",t),r}async function tK(e,t){let n=[],r=0;for await(let o of e){let e=Buffer.isBuffer(o)?o:Buffer.from(o);if((r+=e.length)>t)throw new A("INVALID_ARGS","Proxy request body is too large.");n.push(e)}return Buffer.concat(n)}let tH=async({positionals:e,flags:t})=>{if(e.length>0)throw new A("INVALID_ARGS","proxy does not accept positional arguments.");let n=await tF(t);return t_(t,n,()=>{var e;return e=n,`agent-device proxy listening on ${e.proxyBaseUrl}
10
+ `)}}function tl(e,t){(e?.stderr??process.stderr).write(t)}function tc(e,t){if(!e)return!1;let n=Date.parse(e);return!Number.isFinite(n)||n<=(t?.()??Date.now())}function td(e){return"string"==typeof e&&e.trim().length>0}async function tu(e){await new Promise(t=>setTimeout(t,e))}async function tf(e){let r=await e7({stateDir:e.stateDir,flags:e.flags,env:e.env,io:{env:e.env,fetch:e.fetchImpl}}),o=await tm({cloudBaseUrl:r.cloudBaseUrl,accessToken:r.accessToken,fetchImpl:e.fetchImpl}),a=function(e){try{return c(e)}catch(n){let t=y(n);throw new A("COMMAND_FAILED","Cloud connection profile returned invalid remote config.",{generatedConfigPath:e.configPath,cause:t.message},t)}}({configPath:function(e){var r;let o=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=s.join(e.stateDir,"remote-connections","generated");t.mkdirSync(a,{recursive:!0,mode:448});let i=s.join(a,`cloud-${(r=o,n.createHash("sha256").update(JSON.stringify(r)).digest("hex").slice(0,16))}.json`);t.writeFileSync(i,`${JSON.stringify(o,null,2)}
11
+ `,{mode:384});try{t.chmodSync(i,384)}catch{}return i}({stateDir:e.stateDir,profile:o}),cwd:e.cwd,env:e.env});return{flags:{...eF(a.profile),...e.flags,remoteConfig:a.resolvedPath,daemonAuthToken:r.accessToken},remoteConfigPath:a.resolvedPath}}async function tm(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 e2(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 A("COMMAND_FAILED","Cloud connection profile response is invalid.");let o=r.connection;if(!o||"object"!=typeof o)throw new A("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 A("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is invalid.");if(0===Object.keys(s).length)throw new A("COMMAND_FAILED","Cloud connection profile remoteConfigProfile is empty.");return s}throw new A("COMMAND_FAILED","Cloud connection profile did not include remoteConfigProfile.")}function tp(e,t,n){var r;if(e.json)return void F({success:!0,data:t});let o=n?.();o&&(r=o,process.stdout.write(r.endsWith("\n")?r:`${r}
12
+ `))}let tg=async({flags:e,client:t})=>{var r,o,s,a;let i=T(e.stateDir).baseDir,l=e.remoteConfig?function(e){if(!e.remoteConfig)throw new A("INVALID_ARGS","connect requires --remote-config <path>.");let t=c({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env});return{flags:e,remoteConfigPath:t.resolvedPath}}(e):await tf({flags:e,stateDir:i,cwd:process.cwd(),env:process.env}),d=l.flags,u=d.tenant,f=d.runId;if(!u)throw new A("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!f)throw new A("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!d.daemonBaseUrl)throw new A("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let m=d.session?null:eV({stateDir:i}),p=d.session??m?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${n.randomBytes(3).toString("hex")}`;if(!eT({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${n.randomBytes(2).toString("hex")}`}(i),g=e$(l.remoteConfigPath),h=eL(d),w=m?.session===p?m:eT({stateDir:i,session:p});if(w&&(r=w,o={flags:d,session:p,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:g,desiredLeaseBackend:eQ(d),daemon:h},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 A("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:p,remoteConfig:w.remoteConfigPath});let v=new Date().toISOString(),y={version:1,session:p,remoteConfigPath:l.remoteConfigPath,remoteConfigHash:g,daemon:h,tenant:u,runId:f,leaseId:w&&!d.force?w.leaseId:void 0,leaseBackend:w&&!d.force?w.leaseBackend:eQ(d),platform:d.platform??(w&&!d.force?w.platform:void 0),target:d.target??(w&&!d.force?w.target:void 0),runtime:w&&!d.force?w.runtime:void 0,metro:w&&!d.force?w.metro:void 0,connectedAt:w&&!d.force?w.connectedAt:v,updatedAt:v};eP({stateDir:i,state:y}),w&&d.force&&(await eZ(w.metro),await eY({stateDir:i,state:w}),await eX(t,w));let I=tI(y),S=function(e,t){if(!t.runtime&&(e0(e)||tS(t.remoteConfigPath)))return tA(t.remoteConfigPath)}(d,y);return tp(d,t_(y,S),()=>[`Connected remote session "${p}" tenant "${u}" run "${f}" ${y.leaseId?`lease ${y.leaseId}`:"lease pending"}`,I?.message,S?.message].filter(e=>!!e).join("\n")),!0},th=async({flags:e,client:t})=>{let{session:n,stateDir:r,state:o}=tv(e);if(!o)return ty(e,n),!0;let s=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await eZ(o.metro),await eY({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 eB({stateDir:r,session:s}),tp(e,{connected:!1,session:s,released:a},()=>`Disconnected remote session "${s}".`),!0},tw=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new A("INVALID_ARGS","connection accepts only: status");let{session:n,state:r}=tv(t);if(!r)return ty(t,n),!0;let o=tI(r),s=function(e){if(!e.runtime&&tS(e.remoteConfigPath))return tA(e.remoteConfigPath)}(r);return tp(t,t_(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 tv(e){let t=e.session??"default",n=T(e.stateDir).baseDir;return{session:t,stateDir:n,state:eT({stateDir:n,session:t})??(e.session?null:eV({stateDir:n}))}}function ty(e,t){tp(e,{connected:!1,session:t},()=>`No remote connection for "${t}".`)}function tI(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 tA(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=c({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function t_(e,t){let r=tI(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 tk=async({positionals:e,flags:n})=>{let r=e[0]??"status",o=T(n.stateDir).baseDir;if("status"===r){var s;let e,t=(e=e9({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:tc(e.expiresAt,s.now)}:{authenticated:!1,source:"none"};return tp(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 e6({stateDir:o,flags:n,commandLabel:"agent-device auth login"});return tp(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=te({stateDir:o}.stateDir),!!t.existsSync(e)&&(t.rmSync(e,{force:!0}),!0));return tp(n,{authenticated:!1,removed:r},()=>r?"Removed stored cloud CLI session.":"No stored cloud CLI session."),!0}throw new A("INVALID_ARGS","auth accepts only: status, login, logout")},tD=`${es}/`,tC=["content-type","x-artifact-type","x-artifact-filename"],tN=["content-type","content-disposition","x-request-id"];async function tb(e,t,n){var r,o,s,a,i,l,c;let d,u,f,m=(d=new URL(e.url??"/","http://127.0.0.1").pathname)===es?"/":d.startsWith(tD)?`/${d.slice(tD.length)}`:d;if("GET"===e.method&&"/health"===m)return void await tR(t,n);if(r=m,o=e.method,"/rpc"===r||"/upload"===r?"POST"!==o:!r.startsWith("/artifacts/")||"GET"!==o){t.statusCode=404,t.end("Not found");return}("/rpc"===m&&(f=(await tP(e,n.maxRpcBodyBytes)).toString("utf8")),s=e,a=n.clientToken,(u=function(e,t){let n="string"==typeof e.headers.authorization?e.headers.authorization:"";if(n.toLowerCase().startsWith("bearer "))return n.slice(7);let r=e.headers["x-agent-device-token"];if("string"==typeof r)return r;if(t){let e=function(e){try{let t=JSON.parse(e);return"string"==typeof t.params?.token?t.params.token:""}catch{return""}}(t);if(e)return e}return""}(s,f)).length>0&&Z(u,a))?await tx({req:e,res:t,route:m,options:n,rpcBody:f}):(i=t,l=m,c=function(e){if(!e)return null;try{return JSON.parse(e).id??null}catch{return null}}(f),(i.statusCode=401,i.setHeader("content-type","application/json"),"/rpc"===l)?i.end(JSON.stringify({jsonrpc:"2.0",id:c,error:{code:-32001,message:"Invalid proxy token",data:I(new A("UNAUTHORIZED","Invalid proxy token"))}})):i.end(JSON.stringify({ok:!1,error:"Invalid proxy token",code:"UNAUTHORIZED"})))}async function tR(e,t){let n=await tU(t);e.statusCode=200,e.setHeader("content-type","application/json"),e.end(JSON.stringify(E("agent-device-proxy",{upstream:n})))}async function tU(e){let t=new URL(er(e.upstreamBaseUrl,"health")),n=await e.fetchImpl(t,{method:"GET",headers:tT({headers:{}},e.upstreamToken,"/health"),signal:AbortSignal.timeout(e.upstreamTimeoutMs)}),r=await n.text();try{return r?JSON.parse(r):{ok:n.ok,status:n.status}}catch{return{ok:n.ok,status:n.status}}}async function tx(e){var t,n,r;let s,a,c,{req:d,res:u,route:f,options:m,rpcBody:p}=e,g=(t=m.upstreamBaseUrl,n=f,r=d.url??"/",s=new URL(er(t,n)),(a=r.indexOf("?"))>=0&&(s.search=r.slice(a)),s),h=d.method??"GET",w=tT(d,m.upstreamToken,f),v=function(e,t,n,r){if("GET"!==e.method&&"HEAD"!==e.method){var o,s;let a;return"/rpc"===t?(o=n??"",s=r,(a=JSON.parse(o)).params={...a.params??{},token:s},JSON.stringify(a)):e}}(d,f,p,m.upstreamToken),y=await m.fetchImpl(g,{method:h,headers:w,signal:AbortSignal.timeout(m.upstreamTimeoutMs),...v?{body:v,duplex:"half"}:{}});for(let e of(u.statusCode=y.status,tN)){let t=y.headers.get(e);t&&u.setHeader(e,t)}(u.hasHeader("x-request-id")||u.setHeader("x-request-id","string"==typeof(c=d.headers["x-request-id"])&&c.trim()?c.trim().slice(0,128):o()),y.body)?await l(i.fromWeb(y.body),u):u.end()}function tE(e,t){let n=e.trim();if(!n)throw new A("INVALID_ARGS",`Proxy ${t} is required.`);return n}function tT(e,t,n){let r=new Headers;for(let t of tC){let n=e.headers[t];"string"==typeof n&&n.trim()&&r.set(t,n)}for(let[e,o]of("/rpc"!==n||r.has("content-type")||r.set("content-type","application/json"),Object.entries(X(t))))r.set(e,o);return r}async function tP(e,t){let n=[],r=0;for await(let o of e){let e=Buffer.isBuffer(o)?o:Buffer.from(o);if((r+=e.length)>t)throw new A("INVALID_ARGS","Proxy request body is too large.");n.push(e)}return Buffer.concat(n)}let tL=async({positionals:e,flags:t})=>{if(e.length>0)throw new A("INVALID_ARGS","proxy does not accept positional arguments.");let n=await tB(t);return tp(t,n,()=>{var e;return e=n,`agent-device proxy listening on ${e.proxyBaseUrl}
13
13
  daemon base URL: ${e.agentDeviceBaseUrl}
14
14
  daemon auth token: ${e.token}
15
15
  treat the daemon auth token as a secret; anyone with it can control the proxied daemon
@@ -17,16 +17,16 @@ upstream local daemon: ${e.upstreamBaseUrl}
17
17
  state dir: ${e.stateDir}
18
18
 
19
19
  Remote client example:
20
- agent-device devices --daemon-base-url ${e.agentDeviceBaseUrl} --daemon-auth-token ${e.token}`}),await new Promise(()=>{}),!0};async function tF(e){var t,n,o,s,i,l;let c,d=z({session:"default",command:"proxy",positionals:[],flags:{stateDir:e.stateDir,daemonBaseUrl:"",daemonTransport:"http",daemonServerMode:"http"}}),u=await q(d),f=function(e){if(!e)throw new A("COMMAND_FAILED","Local daemon HTTP endpoint is unavailable.",{hint:"Retry after cleaning daemon state, or run proxy with a fresh --state-dir."});return`http://127.0.0.1:${e}`}(u.info.httpPort),m=(t=e,t.daemonAuthToken?.trim()||r(32).toString("hex")),p=(c={upstreamBaseUrl:function(e,t){try{let t=new URL(e);if("http:"!==t.protocol&&"https:"!==t.protocol)throw Error("unsupported protocol");return t.toString().replace(/\/+$/,"")}catch(n){throw new A("INVALID_ARGS",`Invalid ${t}`,{[t]:e},n)}}((n={upstreamBaseUrl:f,upstreamToken:u.info.token,clientToken:m}).upstreamBaseUrl,"upstreamBaseUrl"),upstreamToken:tG(n.upstreamToken,"upstreamToken"),clientToken:tG(n.clientToken,"clientToken"),maxRpcBodyBytes:n.maxRpcBodyBytes??1048576,upstreamTimeoutMs:n.upstreamTimeoutMs??3e5,fetchImpl:n.fetchImpl??fetch},a.createServer((e,t)=>{t$(e,t,c).catch(e=>{!function(e,t){if(e.headersSent)return e.destroy(t instanceof Error?t:void 0);let n=I(t);e.statusCode="INVALID_ARGS"===n.code?400:500,e.setHeader("content-type","application/json"),e.end(JSON.stringify({ok:!1,error:n.message,code:n.code}))}(t,e)})})),g=e.proxyHost?.trim()||"127.0.0.1",h=e.proxyPort??0;await (o=p,s=g,i=h,new Promise((e,t)=>{o.once("error",t),o.listen(i,s,()=>{o.off("error",t),e()})}));let w=p.address();if(!w||"string"==typeof w)throw new A("COMMAND_FAILED","Proxy did not bind to a TCP address.");let v=`http://${(l=w.address).includes(":")&&!l.startsWith("[")?`[${l}]`:l}:${w.port}`;return{proxyBaseUrl:v,agentDeviceBaseUrl:`${v}/agent-device`,token:m,upstreamBaseUrl:f,stateDir:d.paths.baseDir}}let tq=new Set(["id","text","label"]),tJ=new Set(["enabled","selected"]),tW={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(t8(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&&t8(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:tz,press:tz,longpress:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"longpress requires a target"};let r=tX(t,n);return r?{kind:"commands",commands:[{longPressOn:r}],warnings:(function(e){let[t,n,r]=e.positionals,o=t2(t)&&t2(n)?r:n;return o&&t2(o)?[Number(o)]:[]})(e).map(tZ)}:{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=tX(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(t2(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:t1(e,17e3)}}]};let r=tQ(t);return r?{kind:"commands",commands:[{extendedWaitUntil:{visible:r,timeout:t1(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(t2(t)&&t2(n)&&t2(r)&&t2(o))return{start:Q(t,n),end:Q(r,o),...s&&t2(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 tz(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=tX(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:tY(e,"doubleTapOn")}:"number"==typeof e.flags?.holdMs?{kind:"commands",commands:[{longPressOn:d}],warnings:[tZ(e.flags.holdMs),...tY(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 tZ(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function tY(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 tX(e,t){return t2(e)&&t2(t)?{point:Q(e,t)}:e.startsWith("@")?null:tQ(e)}function tQ(e){let t;try{t=Z(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&&tq.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,tq.has(r.key)?"string"!=typeof r.value||!!n.id||!!n.text||!!n.label||(n[r.key]=r.value,!!0):!tJ.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 t0(e,t,n,r){for(let o of t??[])e.warnings.push({line:r,action:t3(n),message:o})}function t1(e,t){let n=e.positionals.at(-1);return n&&t2(n)?Number(n):t}function t3(e){return[e.command,...e.positionals??[]].join(" ").trim()}function t8(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function t2(e){return void 0!==e&&Number.isFinite(Number(e))}let t4=async e=>{let{positionals:t}=e;return"export"!==t[0]?function({positionals:e,flags:t}){if(e.length>1)throw new A("INVALID_ARGS","replay accepts exactly one input path: replay <path>");if(void 0!==t.replayExportFormat||void 0!==t.out)throw new A("INVALID_ARGS","replay --format/--out are only supported with replay export.");return!1}(e):await t5(e)};async function t5({positionals:e,flags:n}){let r;var o,a=e,i=n;if(a.length>2)throw new A("INVALID_ARGS","replay export accepts exactly one input path: replay export <file.ad>");if(i.replayUpdate)throw new A("INVALID_ARGS","replay export does not support --update.");if(i.replayMaestro)throw new A("INVALID_ARGS","replay export reads .ad files; omit --maestro.");if(i.replayEnv?.length)throw new A("INVALID_ARGS","replay export does not evaluate --env substitutions.");let l=i.replayExportFormat??"maestro";if("maestro"!==l)throw new A("INVALID_ARGS",`Unsupported replay export format: ${l}`);let c=e[1];if(!c)throw new A("INVALID_ARGS","replay export requires an input path.");let d=et(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,tW[r.command]?.(r)??{kind:"unsupported",message:`${r.command} has no Maestro equivalent`});switch(s.kind){case"commands":i.push(...s.commands),t0(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:t3(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),t0(a,s.warnings,o,e);break;case"unsupported":a.unsupported.push({line:e,action:t3(o),message:s.message})}}if(a.unsupported.length>0)throw new A("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,Y(Object.keys(o).length>0?[o,s]:[s])),warnings:a.warnings}}((r=X(o=t.readFileSync(d,"utf8"))).actions,{actionLines:r.actionLines,metadata:ee(o)}),f="string"==typeof n.out?et(n.out):void 0;for(let e of(f&&(t.mkdirSync(s.dirname(f),{recursive:!0}),t.writeFileSync(f,u.yaml)),u.warnings))process.stderr.write(`Warning: line ${e.line}: ${e.message}
21
- `);return t_(n,{format:n.replayExportFormat??"maestro",sourcePath:d,...f?{path:f}:{yaml:u.yaml},warnings:u.warnings},()=>f??u.yaml),!0}let t7={...ep,...ed,...er,...ei,...eg,...eo,...ev,...eA,...el,...eh,...ef,...ew,...eI,...em};async function t6(e){return(await t9(e)).result}async function t9(e){var t,n,r;let o=(t=e.command,n=e.positionals,r=e.flags,t7[t](n,r)),s=await e_(e.client,e.command,o);return{result:s,cliOutput:eS({name:e.command,input:o,result:s})}}let ne={connect:tk,disconnect:tD,connection:tC,auth:tT,proxy:tH,replay:t4,screenshot:async({positionals:e,flags:t,client:n})=>{let r=await t6({client:n,command:"screenshot",positionals:e,flags:t});return t_(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 t6({client:n,command:"diff",positionals:e,flags:t});return t_(t,r,()=>$(r)),!0}if("screenshot"!==e[0])return!1;let o=t.baseline;if(!o||"string"!=typeof o)throw new A("INVALID_ARGS","diff screenshot requires --baseline <path>");let s=et(o),a="string"==typeof t.out?et(t.out):void 0,i=e[1];if(e.length>2)throw new A("INVALID_ARGS","diff screenshot accepts at most one current screenshot path");let l=F({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:ek(),sessions:{get:e=>({name:e}),set:()=>{}},policy:j()}),c=await l.capture.diffScreenshot({session:t.session,baseline:{kind:"path",path:s},current:i?{kind:"path",path:et(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 t_(t,c,()=>M(c)),!0}};async function nt(e){let t={...e.flags},n=ne[e.command];return!!(n&&await n({...e,flags:t}))||!!p(e.command)&&await nn({...e,command:e.command,flags:t})}async function nn(e){let{runGenericClientBackedCommand:t}=await import("./generic.js");return await t(e)}function nr(e,t,n){return n||(e.push(t),"")}async function no(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:nr(n,"metroProxyBaseUrl",e.metroProxyBaseUrl),bearerToken:nr(n,"metroBearerToken",e.metroBearerToken),tenantId:nr(n,"tenant",e.tenant),runId:nr(n,"runId",e.runId),leaseId:nr(n,"leaseId",e.leaseId)};if(n.length>0)throw new A("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 eV({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 ns(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,o=await no(e,t,async()=>(await L("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}async function na(e,t){var n,r,o,s,a,i,l;switch(e[0]){case"setup":{t.flags.json||process.stdout.write("Setting up managed agent-browser backend (downloads if needed)...\n");let e=await G({stateDir:t.stateDir});return n=t.flags.json,r=e,n?V({success:!0,data:{status:ni(r)}}):process.stdout.write(`Managed web backend installed.
20
+ agent-device devices --daemon-base-url ${e.agentDeviceBaseUrl} --daemon-auth-token ${e.token}`}),await new Promise(()=>{}),!0};async function tB(e){var t,n,o,s,i,l;let c,d=eo({session:"default",command:"proxy",positionals:[],flags:{stateDir:e.stateDir,daemonBaseUrl:"",daemonTransport:"http",daemonServerMode:"http"}}),u=await ee(d),f=function(e){if(!e)throw new A("COMMAND_FAILED","Local daemon HTTP endpoint is unavailable.",{hint:"Retry after cleaning daemon state, or run proxy with a fresh --state-dir."});return`http://127.0.0.1:${e}`}(u.info.httpPort),m=(t=e,t.daemonAuthToken?.trim()||r(32).toString("hex")),p=(c={upstreamBaseUrl:function(e,t){try{let t=new URL(e);if("http:"!==t.protocol&&"https:"!==t.protocol)throw Error("unsupported protocol");return t.toString().replace(/\/+$/,"")}catch(n){throw new A("INVALID_ARGS",`Invalid ${t}`,{[t]:e},n)}}((n={upstreamBaseUrl:f,upstreamToken:u.info.token,clientToken:m}).upstreamBaseUrl,"upstreamBaseUrl"),upstreamToken:tE(n.upstreamToken,"upstreamToken"),clientToken:tE(n.clientToken,"clientToken"),maxRpcBodyBytes:n.maxRpcBodyBytes??1048576,upstreamTimeoutMs:n.upstreamTimeoutMs??3e5,fetchImpl:n.fetchImpl??fetch},a.createServer((e,t)=>{tb(e,t,c).catch(e=>{!function(e,t){if(e.headersSent)return e.destroy(t instanceof Error?t:void 0);let n=I(t);e.statusCode="INVALID_ARGS"===n.code?400:500,e.setHeader("content-type","application/json"),e.end(JSON.stringify({ok:!1,error:n.message,code:n.code}))}(t,e)})})),g=e.proxyHost?.trim()||"127.0.0.1",h=e.proxyPort??0;await (o=p,s=g,i=h,new Promise((e,t)=>{o.once("error",t),o.listen(i,s,()=>{o.off("error",t),e()})}));let w=p.address();if(!w||"string"==typeof w)throw new A("COMMAND_FAILED","Proxy did not bind to a TCP address.");let v=`http://${(l=w.address).includes(":")&&!l.startsWith("[")?`[${l}]`:l}:${w.port}`;return{proxyBaseUrl:v,agentDeviceBaseUrl:en(v),token:m,upstreamBaseUrl:f,stateDir:d.paths.baseDir}}let t$=new Set(["id","text","label"]),tM=new Set(["enabled","selected"]),tO={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(tW(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&&tW(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:tV,press:tV,longpress:function(e){let[t,n]=e.positionals;if(!t)return{kind:"unsupported",message:"longpress requires a target"};let r=tH(t,n);return r?{kind:"commands",commands:[{longPressOn:r}],warnings:(function(e){let[t,n,r]=e.positionals,o=tz(t)&&tz(n)?r:n;return o&&tz(o)?[Number(o)]:[]})(e).map(tG)}:{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=tH(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(tz(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:tq(e,17e3)}}]};let r=tK(t);return r?{kind:"commands",commands:[{extendedWaitUntil:{visible:r,timeout:tq(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(tz(t)&&tz(n)&&tz(r)&&tz(o))return{start:el(t,n),end:el(r,o),...s&&tz(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 tV(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=tH(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:tj(e,"doubleTapOn")}:"number"==typeof e.flags?.holdMs?{kind:"commands",commands:[{longPressOn:d}],warnings:[tG(e.flags.holdMs),...tj(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 tG(e){return`long-press duration exports as Maestro longPressOn; Maestro uses its default long-press duration instead of ${e}ms`}function tj(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 tH(e,t){return tz(e)&&tz(t)?{point:el(e,t)}:e.startsWith("@")?null:tK(e)}function tK(e){let t;try{t=ew(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&&t$.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,t$.has(r.key)?"string"!=typeof r.value||!!n.id||!!n.text||!!n.label||(n[r.key]=r.value,!!0):!tM.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 tF(e,t,n,r){for(let o of t??[])e.warnings.push({line:r,action:tJ(n),message:o})}function tq(e,t){let n=e.positionals.at(-1);return n&&tz(n)?Number(n):t}function tJ(e){return[e.command,...e.positionals??[]].join(" ").trim()}function tW(e){return/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(e)}function tz(e){return void 0!==e&&Number.isFinite(Number(e))}let tZ=async e=>{let{positionals:t}=e;return"export"!==t[0]?function({positionals:e,flags:t}){if(e.length>1)throw new A("INVALID_ARGS","replay accepts exactly one input path: replay <path>");if(void 0!==t.replayExportFormat||void 0!==t.out)throw new A("INVALID_ARGS","replay --format/--out are only supported with replay export.");return!1}(e):await tY(e)};async function tY({positionals:e,flags:n}){let r;var o,a=e,i=n;if(a.length>2)throw new A("INVALID_ARGS","replay export accepts exactly one input path: replay export <file.ad>");if(i.replayUpdate)throw new A("INVALID_ARGS","replay export does not support --update.");if(i.replayMaestro)throw new A("INVALID_ARGS","replay export reads .ad files; omit --maestro.");if(i.replayEnv?.length)throw new A("INVALID_ARGS","replay export does not evaluate --env substitutions.");let l=i.replayExportFormat??"maestro";if("maestro"!==l)throw new A("INVALID_ARGS",`Unsupported replay export format: ${l}`);let c=e[1];if(!c)throw new A("INVALID_ARGS","replay export requires an input path.");let d=ed(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,tO[r.command]?.(r)??{kind:"unsupported",message:`${r.command} has no Maestro equivalent`});switch(s.kind){case"commands":i.push(...s.commands),tF(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:tJ(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),tF(a,s.warnings,o,e);break;case"unsupported":a.unsupported.push({line:e,action:tJ(o),message:s.message})}}if(a.unsupported.length>0)throw new A("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,ea(Object.keys(o).length>0?[o,s]:[s])),warnings:a.warnings}}((r=ei(o=t.readFileSync(d,"utf8"))).actions,{actionLines:r.actionLines,metadata:ec(o)}),f="string"==typeof n.out?ed(n.out):void 0;for(let e of(f&&(t.mkdirSync(s.dirname(f),{recursive:!0}),t.writeFileSync(f,u.yaml)),u.warnings))process.stderr.write(`Warning: line ${e.line}: ${e.message}
21
+ `);return tp(n,{format:n.replayExportFormat??"maestro",sourcePath:d,...f?{path:f}:{yaml:u.yaml},warnings:u.warnings},()=>f??u.yaml),!0}let tX=H();function tQ(e,t,n){let r=tX[e];if(!r)throw Error(`Missing CLI reader for command: ${e}`);return r(t,n)}async function t0(e){return(await t1(e)).result}async function t1(e){let t=tQ(e.command,e.positionals,e.flags),n=await em(e.client,e.command,t);return{result:n,cliOutput:ef({name:e.command,input:t,result:n})}}let t3={connect:tg,disconnect:th,connection:tw,auth:tk,proxy:tL,replay:tZ,screenshot:async({positionals:e,flags:t,client:n})=>{let r=await t0({client:n,command:"screenshot",positionals:e,flags:t});return tp(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 t0({client:n,command:"diff",positionals:e,flags:t});return tp(t,r,()=>$(r)),!0}if("screenshot"!==e[0])return!1;let o=t.baseline;if(!o||"string"!=typeof o)throw new A("INVALID_ARGS","diff screenshot requires --baseline <path>");let s=ed(o),a="string"==typeof t.out?ed(t.out):void 0,i=e[1];if(e.length>2)throw new A("INVALID_ARGS","diff screenshot accepts at most one current screenshot path");let l=Y({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:ep(),sessions:{get:e=>({name:e}),set:()=>{}},policy:W()}),c=await l.capture.diffScreenshot({session:t.session,baseline:{kind:"path",path:s},current:i?{kind:"path",path:ed(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 tp(t,c,()=>K(c)),!0}};async function t8(e){let t={...e.flags},n=t3[e.command];return!!(n&&await n({...e,flags:t}))||!!p(e.command)&&await t2({...e,command:e.command,flags:t})}async function t2(e){let{runGenericClientBackedCommand:t}=await import("./generic.js");return await t(e)}async function t4(e,t={}){return(await L("npm",["exec","--yes","--package","agent-cdp@1.6.0","--","agent-cdp",...e],{cwd:t.cwd??process.cwd(),env:t.env??process.env,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode}function t5(e,t,n){return n||(e.push(t),"")}async function t7(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:t5(n,"metroProxyBaseUrl",e.metroProxyBaseUrl),bearerToken:t5(n,"metroBearerToken",e.metroBearerToken),tenantId:t5(n,"tenant",e.tenant),runId:t5(n,"runId",e.runId),leaseId:t5(n,"leaseId",e.leaseId)};if(n.length>0)throw new A("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 eE({projectRoot:t.cwd??process.cwd(),stateDir:s,profileKey:i,consumerKey:a})}return await ex({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 t6(e,t={}){let n=t.cwd??process.cwd(),r=t.env??process.env,o=await t7(e,t,async()=>(await L("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}async function t9(e,t){var n,r,o,s,a,i,l;switch(e[0]){case"setup":{t.flags.json||process.stdout.write("Setting up managed agent-browser backend (downloads if needed)...\n");let e=await J({stateDir:t.stateDir});return n=t.flags.json,r=e,n?F({success:!0,data:{status:ne(r)}}):process.stdout.write(`Managed web backend installed.
22
22
  agent-browser available at: ${r.binaryPath}
23
- `),0}case"doctor":{let e,n=await K({stateDir:t.stateDir});return o=t.flags.json,s=0===n.exitCode?"Web backend is healthy.":"Web backend doctor reported issues.",a=n,o?V({success:!0,data:"object"==typeof(l=e=(i=a).status)&&null!==l&&"socketDir"in l&&"installDir"in l&&"binaryPath"in l?{...i,status:ni(e)}:i}):process.stdout.write(`${s}
24
- `),n.exitCode}default:throw new A("INVALID_ARGS","web requires setup or doctor")}}function ni(e){let{socketDir:t,...n}=e;return n}function nl(e,t={}){let n=nc(t),r={...e};return n.defaultPlatform&&void 0===r.platform&&(r.platform=n.defaultPlatform),r}function nc(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 A("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 A("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}(r.AGENT_DEVICE_SESSION_LOCK))||(n?.sessionLocked===!0||o?"reject":void 0))}}let nd={sendToDaemon:J},nu=new Set(["launchUrl","kind","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),nf=new Set(["connect","connection","close","disconnect","metro","proxy","session"]);async function nm(e,n=nd){let r=N(),o=eD(),a=function(e){try{let t=eP(e);return np(t.command??"",t.providedFlags)}catch{return e.includes("--debug")||e.includes("-v")||e.includes("--verbose")}}(e),i=e.includes("--json"),l=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 b({session:l,requestId:r,command:e[0],debug:a},async()=>{var l,u,m,p,g,h,v,k,D,C,N,b,x,P,L,B,$;let M,G,j,K,H,F,q;try{let n,r,o,a,i,d,y,I;l={cwd:process.cwd(),env:process.env},n=eP(e),r=l?.env??process.env,o=l?.cwd??process.cwd(),p=n.command,a=null!==p&&(u={remoteConfig:n.flags.remoteConfig,cwd:o,env:r}).remoteConfig?{...e0(c({configPath:u.remoteConfig,cwd:u.cwd,env:u.env}).profile),remoteConfig:u.remoteConfig}:{},y=eN((i=(m={command:n.command,cwd:o,cliFlags:n.flags,env:r}).env??process.env,d=eN({},function(e){let n={};for(let r of e)eN(n,function(e,n){let r,o;if(!t.existsSync(e)){if(n)throw new A("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{r=t.readFileSync(e,"utf8")}catch(t){throw new A("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 A("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 A("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=es(o,t);continue}let e=eE.get(r);if(!e)throw new A("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new A("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);n[r]=f(eT(e),o,t,r)}return n}(o,`config file ${e}`)}(r.path,r.required));return n}((g=m.cwd,h=m.cliFlags.config,v=i,(I=h??v.AGENT_DEVICE_CONFIG)?[{path:(k=I,D=g,C=v,et(k,{cwd:D,env:C})),required:!0}]:[{path:(N=v,s.join(en("~",{env:N}),".agent-device","config.json")),required:!1},{path:s.resolve(g,"agent-device.json"),required:!1}]))),eN(d,function(e,t){var n,r,o;let s={};for(let a of eU.filter(e=>e.config.enabled&&e.supportsCommand(t))){if("installSource"===a.key)continue;let t=a.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(s[a.key]=(n=t.value,r=`environment variable ${t.name}`,o=t.name,f(eT(a),n,r,o)))}return s}(i,m.command))),a),M={...function(e,t){let n=t?.strictFlags??!0,r=[...e.warnings],o=eN({json:!1,help:!1,version:!1},t?.defaultFlags??{});eN(o,e.flags);let s=e.providedFlags.filter(t=>!ex(t.key,e.command));if(s.length>0){var a,i;let t=s.map(e=>e.token),l=(a=e.command,i=t,a?1===i.length?`Flag ${i[0]} is not supported for command ${a}.`:`Flags ${i.join(", ")} are not supported for command ${a}.`:1===i.length?`Flag ${i[0]} requires a command that supports it.`:`Flags ${i.join(", ")} require a command that supports them.`);if(n)throw new A("INVALID_ARGS",l);for(let e of(r.push(l),s))delete o[e.key]}for(let t of Object.keys(o))void 0!==o[t]&&(ex(t,e.command)||delete o[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new A("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),w(e.command,o),"batch"===e.command&&1!=+!!o.steps+ +!!o.stepsFile)throw new A("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:n,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:o,warnings:r})}(n,{strictFlags:l?.strictFlags,defaultFlags:y}),providedFlags:n.providedFlags}}catch(t){E({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=I(t,{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});i?V({success:!1,error:e}):O(e,{showDetails:a}),process.exit(1);return}for(let e of M.warnings)process.stderr.write(`Warning: ${e}
25
- `);M.flags.version&&(process.stdout.write(`${o}
26
- `),process.exit(0));let J="help"===M.command,z=M.flags.help;if(J||z){J&&M.positionals.length>1&&(O(new A("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=J?M.positionals[0]:M.command;e||(process.stdout.write(`${_()}
27
- `),process.exit(0));let t=S(eM(e));t&&(process.stdout.write(t),process.exit(0)),O(new A("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${_()}
28
- `),process.exit(1)}M.command||(process.stdout.write(`${_()}
29
- `),process.exit(1));let{command:Z,positionals:Y}=M,X=np(Z,M.providedFlags),Q=new Set(M.providedFlags.map(e=>e.key));try{j=(G=nc({policyOverrides:M.flags,configuredPlatform:M.flags.platform,configuredSession:M.flags.session})).lockPolicy?{...M.flags}:nl(M.flags,{policyOverrides:M.flags,configuredPlatform:M.flags.platform,configuredSession:M.flags.session}),K=T(j.stateDir),H=j.session??"default",b={command:Z,explicitFlagKeys:Q,stateDir:K.baseDir,session:H,remoteConfig:j.remoteConfig,hasResolvedSession:void 0!==j.session},q=(F="connect"===b.command||"connection"===b.command||"proxy"===b.command?null:function(e){let t=e.validateRemoteConfigHash??!0,n=e.remoteConfig?d({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,r=ej(e)??(e.allowActiveFallback?ez({stateDir:e.stateDir}):null);if(!r||n&&r.remoteConfigPath!==n)return null;if(t&&eq(r.remoteConfigPath)!==r.remoteConfigHash)throw new A("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 c({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:b.stateDir,session:b.session,remoteConfig:b.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!b.explicitFlagKeys.has("session")&&(!b.remoteConfig||"disconnect"===b.command||!b.hasResolvedSession),validateRemoteConfigHash:"disconnect"!==b.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}(j,F.flags,Q):j}catch(t){let e=I(y(t),{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});M.flags.json?V({success:!1,error:e}):O(e,{showDetails:X}),process.exit(1);return}let ee=null;try{let e;if("react-devtools"===Z){let e=await ns(Y,{flags:q,stateDir:K.baseDir,session:q.session??H,cwd:process.cwd(),env:process.env});process.exit(e);return}if("web"===Z){let e=await na(Y,{flags:q,stateDir:K.baseDir});process.exit(e);return}eC({command:Z,currentVersion:o,stateDir:K.baseDir,flags:q});let s=F?.runtime,a=(e,t)=>({session:e.session,requestId:r,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:G.lockPolicy,lockPlatform:G.defaultPlatform,cwd:process.cwd(),debug:X});if("batch"===Z){if(Y.length>0)throw new A("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 A("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}var a,i=s;try{o=JSON.parse(i)}catch{throw new A("INVALID_ARGS","Batch steps must be valid JSON.")}if(!Array.isArray(o)||0===o.length)throw new A("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 A("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 A("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 A("INVALID_ARGS",`Batch step ${t} requires command.`);if(ey(n))return n;throw new A("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 A("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 A("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},t7[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}(j)}if(x=Z,"auth"!==x&&"connection"!==x&&"proxy"!==x&&(q=(await to({command:Z,flags:q,stateDir:K.baseDir,env:process.env})).flags),q.remoteConfig&&(P=Z,!nf.has(P))){let t=W(a(q,s),{transport:n.sendToDaemon}),r=await e8({command:Z,flags:q,client:t,runtime:s,batchSteps:e,forceRuntimePrepare:function(e){for(let t of nu)if(e.has(t))return!0;return!1}(Q)});q=r.flags,s=r.runtime}L={command:Z,flags:q,runtime:s,explicitFlagKeys:Q,hadConnectionDefaults:!!F},!("open"===L.command&&!L.runtime&&!L.flags.bundleUrl&&!L.flags.metroHost&&!L.flags.metroPort&&!L.flags.remoteConfig&&!L.hadConnectionDefaults&&((B=L.explicitFlagKeys).has("daemonBaseUrl")||B.has("daemonTransport")||B.has("tenant")||B.has("sessionIsolation")||B.has("runId")||B.has("leaseId")||B.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;ee=!X||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=W(a(q,s),{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:Z,flags:q,transport:n.sendToDaemon})});if("batch"===Z){if(!e)throw new A("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,input:G.lockPolicy&&void 0===j.platform?{...e.input}:nl(e.input,{policyOverrides:q,configuredPlatform:q.platform,configuredSession:q.session,inheritedPlatform:q.platform})}));if(await nt({command:Z,positionals:Y,flags:{...q,batchSteps:t},client:l,debug:X}))return}else if("runtime"===Z)throw new A("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 nt({command:Z,positionals:Y,flags:q,client:l,debug:X}))return;throw new A("INVALID_ARGS",`Unknown command: ${Z}`)}catch(r){let e=y(r),n=I(e,{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});if("close"===Z&&"COMMAND_FAILED"===($=e).code&&($.details?.kind==="daemon_startup_failed"||$.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof $.details?.infoPath||"string"==typeof $.details?.lockPath))){q.json&&V({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(q.json)V({success:!1,error:n});else if(O(n,{showDetails:X}),X)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(`
23
+ `),0}case"doctor":{let e,n=await z({stateDir:t.stateDir});return o=t.flags.json,s=0===n.exitCode?"Web backend is healthy.":"Web backend doctor reported issues.",a=n,o?F({success:!0,data:"object"==typeof(l=e=(i=a).status)&&null!==l&&"socketDir"in l&&"installDir"in l&&"binaryPath"in l?{...i,status:ne(e)}:i}):process.stdout.write(`${s}
24
+ `),n.exitCode}default:throw new A("INVALID_ARGS","web requires setup or doctor")}}function ne(e){let{socketDir:t,...n}=e;return n}function nt(e,t={}){let n=nn(t),r={...e};return n.defaultPlatform&&void 0===r.platform&&(r.platform=n.defaultPlatform),r}function nn(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 A("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 A("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}(r.AGENT_DEVICE_SESSION_LOCK))||(n?.sessionLocked===!0||o?"reject":void 0))}}let nr={sendToDaemon:Q},no=new Set(["launchUrl","kind","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),ns=new Set(["connect","connection","close","disconnect","metro","proxy","session"]);async function na(e,n=nr){let r=N(),o=eg(),a=function(e){try{let t=eD(e);return ni(t.command??"",t.providedFlags)}catch{return e.includes("--debug")||e.includes("-v")||e.includes("--verbose")}}(e),i=e.includes("--json"),l=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 b({session:l,requestId:r,command:e[0],debug:a},async()=>{var l,u,m,p,g,h,v,k,D,C,N,b,E,P,L,B,$;let O,G,H,K,q,J,W;try{let n,r,o,a,i,d,y,I;l={cwd:process.cwd(),env:process.env},n=eD(e),r=l?.env??process.env,o=l?.cwd??process.cwd(),p=n.command,a=null!==p&&(u={remoteConfig:n.flags.remoteConfig,cwd:o,env:r}).remoteConfig?{...eF(c({configPath:u.remoteConfig,cwd:u.cwd,env:u.env}).profile),remoteConfig:u.remoteConfig}:{},y=ev((i=(m={command:n.command,cwd:o,cliFlags:n.flags,env:r}).env??process.env,d=ev({},function(e){let n={};for(let r of e)ev(n,function(e,n){let r,o;if(!t.existsSync(e)){if(n)throw new A("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{r=t.readFileSync(e,"utf8")}catch(t){throw new A("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 A("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 A("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=j(o,t);continue}let e=eS.get(r);if(!e)throw new A("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new A("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);n[r]=f(ek(e),o,t,r)}return n}(o,`config file ${e}`)}(r.path,r.required));return n}((g=m.cwd,h=m.cliFlags.config,v=i,(I=h??v.AGENT_DEVICE_CONFIG)?[{path:(k=I,D=g,C=v,ed(k,{cwd:D,env:C})),required:!0}]:[{path:(N=v,s.join(eu("~",{env:N}),".agent-device","config.json")),required:!1},{path:s.resolve(g,"agent-device.json"),required:!1}]))),ev(d,function(e,t){var n,r,o;let s={};for(let a of eA.filter(e=>e.config.enabled&&e.supportsCommand(t))){if("installSource"===a.key)continue;let t=a.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(s[a.key]=(n=t.value,r=`environment variable ${t.name}`,o=t.name,f(ek(a),n,r,o)))}return s}(i,m.command))),a),O={...function(e,t){let n=t?.strictFlags??!0,r=[...e.warnings],o=ev({json:!1,help:!1,version:!1},t?.defaultFlags??{});ev(o,e.flags);let s=e.providedFlags.filter(t=>!e_(t.key,e.command));if(s.length>0){var a,i;let t=s.map(e=>e.token),l=(a=e.command,i=t,a?1===i.length?`Flag ${i[0]} is not supported for command ${a}.`:`Flags ${i.join(", ")} are not supported for command ${a}.`:1===i.length?`Flag ${i[0]} requires a command that supports it.`:`Flags ${i.join(", ")} require a command that supports them.`);if(n)throw new A("INVALID_ARGS",l);for(let e of(r.push(l),s))delete o[e.key]}for(let t of Object.keys(o))void 0!==o[t]&&(e_(t,e.command)||delete o[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new A("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),w(e.command,o),"batch"===e.command&&1!=+!!o.steps+ +!!o.stepsFile)throw new A("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...n}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:n,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:o,warnings:r})}(n,{strictFlags:l?.strictFlags,defaultFlags:y}),providedFlags:n.providedFlags}}catch(t){x({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=I(t,{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});i?F({success:!1,error:e}):V(e,{showDetails:a}),process.exit(1);return}for(let e of O.warnings)process.stderr.write(`Warning: ${e}
25
+ `);O.flags.version&&(process.stdout.write(`${o}
26
+ `),process.exit(0));let z="help"===O.command,Z=O.flags.help;if(z||Z){z&&O.positionals.length>1&&(V(new A("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=z?O.positionals[0]:O.command;e||(process.stdout.write(`${_()}
27
+ `),process.exit(0));let t=S(eR(e));t&&(process.stdout.write(t),process.exit(0)),V(new A("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${_()}
28
+ `),process.exit(1)}O.command||(process.stdout.write(`${_()}
29
+ `),process.exit(1));let{command:Y,positionals:X}=O,Q=ni(Y,O.providedFlags),ee=new Set(O.providedFlags.map(e=>e.key));try{H=(G=nn({policyOverrides:O.flags,configuredPlatform:O.flags.platform,configuredSession:O.flags.session})).lockPolicy?{...O.flags}:nt(O.flags,{policyOverrides:O.flags,configuredPlatform:O.flags.platform,configuredSession:O.flags.session}),K=T(H.stateDir),q=H.session??"default",b={command:Y,explicitFlagKeys:ee,stateDir:K.baseDir,session:q,remoteConfig:H.remoteConfig,hasResolvedSession:void 0!==H.session},W=(J="connect"===b.command||"connection"===b.command||"proxy"===b.command?null:function(e){let t=e.validateRemoteConfigHash??!0,n=e.remoteConfig?d({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,r=eT(e)??(e.allowActiveFallback?eV({stateDir:e.stateDir}):null);if(!r||n&&r.remoteConfigPath!==n)return null;if(t&&e$(r.remoteConfigPath)!==r.remoteConfigHash)throw new A("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 c({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:b.stateDir,session:b.session,remoteConfig:b.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!b.explicitFlagKeys.has("session")&&(!b.remoteConfig||"disconnect"===b.command||!b.hasResolvedSession),validateRemoteConfigHash:"disconnect"!==b.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}(H,J.flags,ee):H}catch(t){let e=I(y(t),{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});O.flags.json?F({success:!1,error:e}):V(e,{showDetails:Q}),process.exit(1);return}let en=null;try{let e;if("cdp"===Y){let e=await t4(X,{cwd:process.cwd(),env:process.env});process.exit(e);return}if("react-devtools"===Y){let e=await t6(X,{flags:W,stateDir:K.baseDir,session:W.session??q,cwd:process.cwd(),env:process.env});process.exit(e);return}if("web"===Y){let e=await t9(X,{flags:W,stateDir:K.baseDir});process.exit(e);return}eh({command:Y,currentVersion:o,stateDir:K.baseDir,flags:W});let s=J?.runtime,a=(e,t)=>({session:e.session,requestId:r,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:G.lockPolicy,lockPlatform:G.defaultPlatform,cwd:process.cwd(),debug:Q});if("batch"===Y){if(X.length>0)throw new A("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 A("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}var a,i=s;try{o=JSON.parse(i)}catch{throw new A("INVALID_ARGS","Batch steps must be valid JSON.")}if(!Array.isArray(o)||0===o.length)throw new A("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;let a;if(r=e,null!==r&&"object"==typeof r&&!Array.isArray(r)&&"input"in r&&!("positionals"in r)&&!("flags"in r))return e;let i=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new A("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 A("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 A("INVALID_ARGS",`Batch step ${t} requires command.`);if(M(n))return n;throw new A("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 A("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 A("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,o=i,a=tQ(o.command,o.positionals??[],(s=o.flags,{json:!1,help:!1,version:!1,...s})),{command:o.command,input:a,...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}(H)}if(E=Y,"auth"!==E&&"connection"!==E&&"proxy"!==E&&(W=(await e4({command:Y,flags:W,stateDir:K.baseDir,env:process.env})).flags),W.remoteConfig&&(P=Y,!ns.has(P))){let t=et(a(W,s),{transport:n.sendToDaemon}),r=await eW({command:Y,flags:W,client:t,runtime:s,batchSteps:e,forceRuntimePrepare:function(e){for(let t of no)if(e.has(t))return!0;return!1}(ee)});W=r.flags,s=r.runtime}L={command:Y,flags:W,runtime:s,explicitFlagKeys:ee,hadConnectionDefaults:!!J},!("open"===L.command&&!L.runtime&&!L.flags.bundleUrl&&!L.flags.metroHost&&!L.flags.metroPort&&!L.flags.remoteConfig&&!L.hadConnectionDefaults&&((B=L.explicitFlagKeys).has("daemonBaseUrl")||B.has("daemonTransport")||B.has("tenant")||B.has("sessionIsolation")||B.has("runId")||B.has("leaseId")||B.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=W.daemonBaseUrl;en=!Q||W.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=et(a(W,s),{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:Y,flags:W,transport:n.sendToDaemon})});if("batch"===Y){if(!e)throw new A("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,input:G.lockPolicy&&void 0===H.platform?{...e.input}:nt(e.input,{policyOverrides:W,configuredPlatform:W.platform,configuredSession:W.session,inheritedPlatform:W.platform})}));if(await t8({command:Y,positionals:X,flags:{...W,batchSteps:t},client:l,debug:Q}))return}else if("runtime"===Y)throw new A("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 t8({command:Y,positionals:X,flags:W,client:l,debug:Q}))return;throw new A("INVALID_ARGS",`Unknown command: ${Y}`)}catch(r){let e=y(r),n=I(e,{diagnosticId:R().diagnosticId,logPath:U({force:!0})??void 0});if("close"===Y&&"COMMAND_FAILED"===($=e).code&&($.details?.kind==="daemon_startup_failed"||$.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof $.details?.infoPath||"string"==typeof $.details?.lockPath))){W.json&&F({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(W.json)F({success:!1,error:n});else if(V(n,{showDetails:Q}),Q)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(`
30
30
  [daemon log]
31
31
  ${r}
32
- `)}}catch{}ee&&ee(),process.exit(1)}finally{ee&&ee()}})}function np(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&&nm(process.argv.slice(2)).catch(e=>{O(I(y(e)),{showDetails:!0}),process.exit(1)});export{nm as runCli,t9 as runCliCommandWithOutput,t_ as writeCommandOutput};
32
+ `)}}catch{}en&&en(),process.exit(1)}finally{en&&en()}})}function ni(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&&na(process.argv.slice(2)).catch(e=>{V(I(y(e)),{showDetails:!0}),process.exit(1)});export{na as runCli,t1 as runCliCommandWithOutput,tp as writeCommandOutput};
@@ -1 +1 @@
1
- import{interactionCommandDefinitions as _,batchCommandDefinition as n}from"./9873.js";import{clientCommandDefinitions as r}from"./2948.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};
1
+ import{listCommandFamilyDefinitions as n}from"./2948.js";let a=new Map(n().map(n=>[n.name,n]));async function e(n,e,r){var t;return await (t=e,a.get(t)).invoke(n,r)}export{e as runCommand};
package/dist/src/find.js CHANGED
@@ -1 +1 @@
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"./9722.js";import{findBestMatchesByLocator as c,parseFindArgs as f}from"./587.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"./9873.js";import{centerOfRect as y}from"./4291.js";import{sleep as m}from"./5560.js";import{extractNodeText as w}from"./9836.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"./587.js";export{A as handleFindCommands};
1
+ import{stripInternalInteractionFlags as e,ensureDeviceReady as t,errorResponse as r,dispatchCommand as n,resolveTargetDevice as o,context_contextFromFlags as a}from"./9722.js";import{parseFindSelectorExpression as i,findBestMatchesByLocator as s,parseFindArgs as l}from"./587.js";import{dispatchFindReadOnlyViaRuntime as c,readTextForNode as f,createSelectorCaptureRuntime as u}from"./selector-runtime.js";import{resolveActionableTouchResolution as d,isSparseSnapshotQualityVerdict as p,isSnapshotNodeInteractionBlocked as h,resolveActionableTouchNode as _}from"./2948.js";import{resolveSelectorChain as g,extractNodeText as m}from"./9836.js";import{centerOfRect as y}from"./4291.js";import{sleep as A}from"./5560.js";async function w(n){var a,f,h,A;let w,{req:K,sessionName:b,logPath:U,sessionStore:L,invoke:O}=n,P=K.command;if("find"!==P)return null;let q=K.positionals??[];if(0===q.length)return r("INVALID_ARGS","find requires a locator or text");let{locator:H,query:$,action:B,value:G,timeoutMs:V}=l(q);if(!$)return r("INVALID_ARGS","find requires a value");if(K.flags?.findFirst&&K.flags?.findLast)return r("INVALID_ARGS","find accepts only one of --first or --last");let Q=await c({req:K,sessionName:b,logPath:U,sessionStore:L});if(Q)return Q;let T=L.get(b),j="exists"===(a=B)||"wait"===a||"get_text"===a||"get_attrs"===a;if(!T&&!j)return r("SESSION_NOT_FOUND","No active session. Run open first.");let z=T?.device??await o(K.flags??{});T||await t(z);let J="click"===(f=B)||"focus"===f||"fill"===f||"type"===f,W=i(H,$),X="web"!==z.platform&&!W&&E(H)&&!J?$:void 0,Y=function(e){let{device:t,session:r,req:n,logPath:o,locator:a,query:i,scope:s,interactiveOnly:l}=e,{sessionStore:c,sessionName:f}=e,d=u({device:t,session:r,sessionStore:c,sessionName:f,req:n,logPath:o});return async()=>{let{snapshot:e}=await d.capture({flags:{...n.flags,snapshotInteractiveOnly:l},snapshotScope:s,recovery:l?{legacyIosSparse:{query:i,scope:s,shouldScope:E(a)},sparseVerdictQueryScope:{query:i,shouldScope:E(a)}}:void 0});return{nodes:e.nodes,truncated:e.truncated,backend:e.backend,snapshotQuality:e.snapshotQuality}}}({device:z,session:T,req:K,logPath:U,locator:H,query:$,scope:X,interactiveOnly:J,sessionStore:L,sessionName:b}),Z={req:K,sessionName:b,logPath:U,sessionStore:L,invoke:O,session:T,device:z,command:P,locator:H,query:$,publicFlags:{...e(K.flags)??{}}};if("wait"===B)return v(Z,Y,H,$,V);let ee=await Y();if(p(ee.snapshotQuality))return S(ee.snapshotQuality);let{nodes:et}=ee,er=function(e){let{nodes:t,locator:n,query:o,selectorChain:a,requiresRect:i,flags:l,platform:c}=e,f=i?t.filter(e=>!N(e,t[0])):t;if(a){let e=g(f,a,{platform:c,requireRect:i,requireUnique:!1});return e?{ok:!0,node:e.node}:{ok:!1,response:r("COMMAND_FAILED","find did not match any element")}}let u=s(f,n,o,{requireRect:i});if(i&&(u.matches=function(e,t){var r,n;let o=t[0]?.rect;if(!o)return e;let a=e.filter(e=>{if(!e.rect)return!1;let t=y(e.rect);return t.x>=o.x&&t.x<=o.x+o.width&&t.y>=o.y&&t.y<=o.y+o.height});return r=a.length>0?a:e,n=t,r.length<2?r:r.map((e,t)=>({node:e,index:t,score:function(e,t){var r,n;let o=d(t,e);if("covered"===o.reason)return 0;let a=(r=o,n=t[0],r.node.rect?"semantic-target"===r.reason||"same-rect-descendant"===r.reason?4:2*!("hittable-ancestor"!==r.reason||N(r.node,n)):0);return a>0?a:e.hittable&&e.rect&&!N(e,t[0])?3:+!!e.rect}(e,n)})).sort((e,t)=>t.score!==e.score?t.score-e.score:k(e.node)-k(t.node)||e.index-t.index).map(e=>e.node)}(u.matches,t)),i&&u.matches.length>1){var p,h,_,A,w;let e=(p=u.matches,h=l,h?.findFirst?[p[0]]:h?.findLast?[p[p.length-1]]:null);if(!e){let e;return{ok:!1,response:(_=u.matches,A=n,w=o,e=_.slice(0,8).map(e=>{let t=m(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`}),r("AMBIGUOUS_MATCH",`find matched ${_.length} elements for ${A} "${w}". Use a more specific locator or selector.`,{locator:A,query:w,matches:_.length,candidates:e}))}}u.matches=e}let S=u.matches[0]??null;return S?{ok:!0,node:S}:{ok:!1,response:r("COMMAND_FAILED","find did not match any element")}}({nodes:et,locator:H,query:$,selectorChain:W,requiresRect:J,flags:K.flags,platform:z.platform});if(!er.ok)return er.response;let en=er.node,eo=J?N(w=_(h=et,A=en),h[0])&&A.rect?A:w:en,ea=`@${eo.ref}`,ei={node:en,resolvedNode:eo,ref:ea,nodes:et,actionFlags:{...K.flags??{},noRecord:!0}},es={exists:()=>C(Z),get_text:()=>M(Z,ei),get_attrs:()=>I(Z,ei),click:()=>x(Z,ei),fill:()=>D(Z,ei,G),focus:()=>R(Z,ei),type:()=>F(Z,ei,G)}[B];return es?es():null}function S(e){return r("COMMAND_FAILED","find could not read the current accessibility tree",{reason:e.reason,hint:"The snapshot quality verdict is sparse. Use screenshot as visual truth, navigate with coordinates if needed, then retry find after reaching a readable screen."})}function k(e){return e.rect?e.rect.width*e.rect.height:1/0}function N(e,t){var r,n;if(!t?.rect||!e.rect)return!1;let o=e.type?.toLowerCase()??"";return(!!o.includes("application")||!!o.includes("window"))&&(r=e.rect,n=t.rect,r.x===n.x&&r.y===n.y&&r.width===n.width&&r.height===n.height)}async function v(e,t,n,o,a){let i,{req:l,sessionStore:c,session:f,command:u,publicFlags:d}=e,h=a??1e4,_=Date.now();for(;Date.now()-_<h;){let{nodes:e,snapshotQuality:r}=await t();if(p(r)){i=r,await A(300);continue}if(s(e,n,o,{requireRect:!1}).matches[0])return f&&c.recordAction(f,{command:u,positionals:l.positionals??[],flags:d,result:{found:!0,waitedMs:Date.now()-_}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-_}};await A(300)}return i?S(i):r("COMMAND_FAILED","find wait timed out")}async function C(e){let{req:t,sessionStore:r,session:n,command:o,publicFlags:a}=e;return n&&r.recordAction(n,{command:o,positionals:t.positionals??[],flags:a,result:{found:!0}}),{ok:!0,data:{found:!0}}}async function M(e,t){let{req:r,sessionStore:n,session:o,command:i,device:s,logPath:l,publicFlags:c}=e,u=await f({device:s,node:t.node,flags:r.flags,appBundleId:o?.appBundleId,traceOutPath:o?.trace?.outPath,surface:o?.surface,contextFromFlags:(e,t,r)=>a(l,e,t,r)});return o&&n.recordAction(o,{command:i,positionals:r.positionals??[],flags:c,result:{ref:t.ref,action:"get text",text:u}}),{ok:!0,data:{ref:t.ref,text:u,node:t.node}}}async function I(e,t){let{req:r,sessionStore:n,session:o,command:a,publicFlags:i}=e;return o&&n.recordAction(o,{command:a,positionals:r.positionals??[],flags:i,result:{ref:t.ref,action:"get attrs"}}),{ok:!0,data:{ref:t.ref,node:t.node}}}async function x(e,t){let{req:r,sessionName:n,sessionStore:o,session:a,invoke:i,command:s,locator:l,query:c,publicFlags:f}=e,u=await i({token:r.token,session:n,command:"click",positionals:[t.ref],flags:t.actionFlags});if(!u.ok)return u;let d=t.resolvedNode.rect?y(t.resolvedNode.rect):t.node.rect?y(t.node.rect):null,p={ref:t.ref,locator:l,query:c};return d&&(p.x=d.x,p.y=d.y),a&&o.recordAction(a,{command:s,positionals:r.positionals??[],flags:f,result:{ref:t.ref,action:"click",locator:l,query:c}}),{ok:!0,data:p}}async function D(e,t,n){let{req:o,sessionName:a,sessionStore:i,session:s,invoke:l,command:c,publicFlags:f}=e;if(!n)return r("INVALID_ARGS","find fill requires text");let u=await l({token:o.token,session:a,command:"fill",positionals:[t.ref,n],flags:t.actionFlags});return u.ok&&s&&i.recordAction(s,{command:c,positionals:o.positionals??[],flags:f,result:{ref:t.ref,action:"fill"}}),u}async function R(e,t){let r=await K(e,t);return r.ok&&b(e,t,"focus"),r}async function F(e,t,o){let{req:i,device:s,logPath:l,session:c}=e;if(!o)return r("INVALID_ARGS","find type requires text");let f=await K(e,t);if(!f.ok)return f;let u=await n(s,"type",[o],i.flags?.out,{...a(l,i.flags,c?.appBundleId,c?.trace?.outPath)});return b(e,t,"type"),{ok:!0,data:u??{ref:t.ref}}}async function K(e,t){var o;let i,{req:s,device:l,logPath:c,session:f}=e,u=(i=[(o=t).resolvedNode,o.node].find(h))?r("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=t.resolvedNode.rect?y(t.resolvedNode.rect):null;return d?{ok:!0,data:await n(l,"focus",[String(d.x),String(d.y)],s.flags?.out,{...a(c,s.flags,f?.appBundleId,f?.trace?.outPath)})??{ref:t.ref}}:r("COMMAND_FAILED","matched element has no bounds")}function b(e,t,r){let{req:n,sessionStore:o,session:a,command:i,publicFlags:s}=e;a&&o.recordAction(a,{command:i,positionals:n.positionals??[],flags:s,result:{ref:t.ref,action:r}})}function E(e){return"role"!==e}export{parseFindArgs}from"./587.js";export{w as handleFindCommands};
@@ -1,9 +1,9 @@
1
- import t from"node:fs";import e from"node:path";import{formatDurationSeconds as r,replayTestFailureStepLines as s}from"./9919.js";import{AppError as i}from"./733.js";import{colorize as n,printJson as o,supportsColor as a}from"./6311.js";import{runCliCommandWithOutput as u,writeCommandOutput as d}from"./cli.js";import{readCommandMessage as l}from"./9873.js";function f(t){return"failed"===t.status}function c(t){return"passed"===t.status&&t.attempts>1}function p(t){let r=$(t),s=e.basename(t.file),i=r&&r.length>0?`${JSON.stringify(r)} in ${s}`:s;return`${i}${m(t)}`}function $(t){let e=t.title?.trim();return e&&e.length>0?e:void 0}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 h(t,e,r={}){r.includeMessage&&t.push(`errorMessage: ${e.message}`),w(t,y(e)),w(t,_(e,"diagnosticId")),w(t,M(e,"logPath")),!1!==r.includeDetails&&g(t,e,r.detailsIndent)}function g(t,e,r){let s=e.details?JSON.stringify(e.details,null,r):void 0;s&&t.push(`details: ${s}`)}function v(t,e){return"artifactsDir"in t&&t.artifactsDir?`${e}: ${t.artifactsDir}`:void 0}function y(t){return t.hint?`hint: ${t.hint}`:void 0}function _(t,e){return t.diagnosticId?`${e}: ${t.diagnosticId}`:void 0}function M(t,e){return t.logPath?`${e}: ${t.logPath}`:void 0}function w(t,e){e&&t.push(e)}function C(t){return void 0!==t}function I(t){return(Math.max(0,t)/1e3).toFixed(3)}function b(t){return t.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&apos;")}async function S({command:A,positionals:x,flags:D,client:k,debug:K}){let{result:j,cliOutput:F}=await u({client:k,command:A,positionals:x,flags:D});if(F){var N,P;N=D,P=F,!N.json&&P.stderr&&process.stderr.write(P.stderr),d(N,N.json?P.jsonData??P.data:P.data,()=>P.text)}else{let u=function(u,S,A,x={}){return"test"===u?function(u){let{suite:d,json:l,debug:S,reportJunit:A}=u;return(A&&function(r,s){let n=e.dirname(r);try{t.mkdirSync(n,{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="${I(t.durationMs)}">`];for(let s of t.tests)r.push(...function(t){let r=b(`${$(t)??e.basename(t.file)}${m(t)}`),s=b(`${"."===e.dirname(t.file)?t.file:e.dirname(t.file)}${m(t)}`),i=b(t.file),n=I(t.durationMs),o=[` <testcase classname="${s}" name="${r}" file="${i}" time="${n}">`];"failed"===t.status?o.push(` <failure message="${b(t.error.message)}">${b(function(t){let e=[t.error.message];return h(e,t.error,{includeDetails:!1}),w(e,v(t,"artifactsDir")),g(e,t.error,2),e.join("\n")}(t))}</failure>`):"skipped"===t.status&&o.push(` <skipped message="${b(t.message)}" />`);let a=function(t){let e=[`status: ${t.status}`,`durationMs: ${t.durationMs}`];return function(t,e){var r,s,i,n,o;for(let s of(w(t,"attempts"in e?`attempts: ${e.attempts}`:void 0),w(t,"session"in e?`session: ${e.session}`:void 0),w(t,"replayed"in e?`replayed: ${e.replayed}`:void 0),w(t,"healed"in e?`healed: ${e.healed}`:void 0),r=e,"passed"!==r.status?[]:(r.warnings??[]).map(t=>`warning: ${t}`)))t.push(s);w(t,v(e,"artifactsDir")),s=t,i=e,"shardIndex"in i&&"number"==typeof i.shardIndex&&(s.push(`shardIndex: ${i.shardIndex}`),w(s,"number"==typeof i.shardCount?`shardCount: ${i.shardCount}`:void 0),w(s,"string"==typeof i.deviceId?`deviceId: ${i.deviceId}`:void 0)),"failed"===e.status&&(n=t,o=e,n.push(`errorCode: ${o.error.code}`),h(n,o.error,{includeMessage:!0})),w(t,c(e)?"flaky: true":void 0)}(e,t),e.join("\n")}(t);return a&&o.push(` <system-out>${b(a)}</system-out>`),o.push(" </testcase>"),o}(s));return r.push(" </testsuite>"),r.push("</testsuites>"),`${r.join("\n")}
2
- `}(s),"utf8")}catch(e){let t=e instanceof Error?e.message:String(e);throw new i("COMMAND_FAILED",`Failed to write JUnit report to ${r}: ${t}`)}}(A,d),l)?(o({success:!0,data:d}),+(d.failed>0)):function(t,e={}){var i,o;let u,d,l,$=t.tests.filter(c);return process.stdout.write(`${(i=t,o=$.length,u="number"==typeof i.durationMs?i.durationMs:void 0,d=o>0?`, ${o} flaky`:"",l=void 0!==u?` in ${r(u)}`:"",`Test summary: ${i.passed} passed, ${i.failed} failed${d}${l}`)}
1
+ import t from"node:fs";import e from"node:path";import{formatDurationSeconds as r,replayTestFailureStepLines as s}from"./9919.js";import{AppError as i}from"./733.js";import{colorize as n,supportsColor as o,printJson as a,readCommandMessage as u}from"./2948.js";import{runCliCommandWithOutput as d,writeCommandOutput as l}from"./cli.js";function f(t){return"failed"===t.status}function c(t){return"passed"===t.status&&t.attempts>1}function p(t){let r=$(t),s=e.basename(t.file),i=r&&r.length>0?`${JSON.stringify(r)} in ${s}`:s;return`${i}${m(t)}`}function $(t){let e=t.title?.trim();return e&&e.length>0?e:void 0}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 h(t,e,r={}){r.includeMessage&&t.push(`errorMessage: ${e.message}`),_(t,y(e)),_(t,M(e,"diagnosticId")),_(t,w(e,"logPath")),!1!==r.includeDetails&&g(t,e,r.detailsIndent)}function g(t,e,r){let s=e.details?JSON.stringify(e.details,null,r):void 0;s&&t.push(`details: ${s}`)}function v(t,e){return"artifactsDir"in t&&t.artifactsDir?`${e}: ${t.artifactsDir}`:void 0}function y(t){return t.hint?`hint: ${t.hint}`:void 0}function M(t,e){return t.diagnosticId?`${e}: ${t.diagnosticId}`:void 0}function w(t,e){return t.logPath?`${e}: ${t.logPath}`:void 0}function _(t,e){e&&t.push(e)}function C(t){return void 0!==t}function I(t){return(Math.max(0,t)/1e3).toFixed(3)}function b(t){return t.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&apos;")}async function x({command:A,positionals:S,flags:D,client:k,debug:j}){let{result:F,cliOutput:K}=await d({client:k,command:A,positionals:S,flags:D});if(K){var N,P;N=D,P=K,!N.json&&P.stderr&&process.stderr.write(P.stderr),l(N,N.json?P.jsonData??P.data:P.data,()=>P.text)}else{let d=function(d,x,A,S={}){return"test"===d?function(u){let{suite:d,json:l,debug:x,reportJunit:A}=u;return(A&&function(r,s){let n=e.dirname(r);try{t.mkdirSync(n,{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="${I(t.durationMs)}">`];for(let s of t.tests)r.push(...function(t){let r=b(`${$(t)??e.basename(t.file)}${m(t)}`),s=b(`${"."===e.dirname(t.file)?t.file:e.dirname(t.file)}${m(t)}`),i=b(t.file),n=I(t.durationMs),o=[` <testcase classname="${s}" name="${r}" file="${i}" time="${n}">`];"failed"===t.status?o.push(` <failure message="${b(t.error.message)}">${b(function(t){let e=[t.error.message];return h(e,t.error,{includeDetails:!1}),_(e,v(t,"artifactsDir")),g(e,t.error,2),e.join("\n")}(t))}</failure>`):"skipped"===t.status&&o.push(` <skipped message="${b(t.message)}" />`);let a=function(t){let e=[`status: ${t.status}`,`durationMs: ${t.durationMs}`];return function(t,e){var r,s,i,n,o;for(let s of(_(t,"attempts"in e?`attempts: ${e.attempts}`:void 0),_(t,"session"in e?`session: ${e.session}`:void 0),_(t,"replayed"in e?`replayed: ${e.replayed}`:void 0),_(t,"healed"in e?`healed: ${e.healed}`:void 0),r=e,"passed"!==r.status?[]:(r.warnings??[]).map(t=>`warning: ${t}`)))t.push(s);_(t,v(e,"artifactsDir")),s=t,i=e,"shardIndex"in i&&"number"==typeof i.shardIndex&&(s.push(`shardIndex: ${i.shardIndex}`),_(s,"number"==typeof i.shardCount?`shardCount: ${i.shardCount}`:void 0),_(s,"string"==typeof i.deviceId?`deviceId: ${i.deviceId}`:void 0)),"failed"===e.status&&(n=t,o=e,n.push(`errorCode: ${o.error.code}`),h(n,o.error,{includeMessage:!0})),_(t,c(e)?"flaky: true":void 0)}(e,t),e.join("\n")}(t);return a&&o.push(` <system-out>${b(a)}</system-out>`),o.push(" </testcase>"),o}(s));return r.push(" </testsuite>"),r.push("</testsuites>"),`${r.join("\n")}
2
+ `}(s),"utf8")}catch(e){let t=e instanceof Error?e.message:String(e);throw new i("COMMAND_FAILED",`Failed to write JUnit report to ${r}: ${t}`)}}(A,d),l)?(a({success:!0,data:d}),+(d.failed>0)):function(t,e={}){var i,a;let u,d,l,$=t.tests.filter(c);return process.stdout.write(`${(i=t,a=$.length,u="number"==typeof i.durationMs?i.durationMs:void 0,d=a>0?`, ${a} flaky`:"",l=void 0!==u?` in ${r(u)}`:"",`Test summary: ${i.passed} passed, ${i.failed} failed${d}${l}`)}
3
3
  `),function(t,e={}){if(0!==t.length)for(let r of(process.stdout.write("\n"),process.stdout.write("Failures:\n"),t))process.stdout.write(` ${p(r)}
4
4
  `),function(t,e){let{debug:r,indent:i}=e;for(let e of(process.stdout.write(`${i}${t.error?.message??"Unknown test failure"}
5
- `),[y(t.error),v(t,"artifacts"),M(t.error,"log"),_(t.error,"diagnostic")].filter(C)))process.stdout.write(`${i}${e}
5
+ `),[y(t.error),v(t,"artifacts"),w(t.error,"log"),M(t.error,"diagnostic")].filter(C)))process.stdout.write(`${i}${e}
6
6
  `);if(r)for(let e of s(t))process.stdout.write(`${i}${e}
7
- `)}(r,{debug:e.debug,indent:" "})}(t.tests.filter(f),{debug:e.debug}),function(t){if(0!==t.length)for(let e of(process.stdout.write("\n"),process.stdout.write("Flaky tests:\n"),t))for(let t of(process.stdout.write(` ${a()?n("✓","yellow"):"✓"} ${p(e)} after ${e.attempts} attempts${function(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(", ")})`:""}(e)}
7
+ `)}(r,{debug:e.debug,indent:" "})}(t.tests.filter(f),{debug:e.debug}),function(t){if(0!==t.length)for(let e of(process.stdout.write("\n"),process.stdout.write("Flaky tests:\n"),t))for(let t of(process.stdout.write(` ${o()?n("✓","yellow"):"✓"} ${p(e)} after ${e.attempts} attempts${function(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(", ")})`:""}(e)}
8
8
  `),e.attemptFailures??[])){let e="number"==typeof t.durationMs?` (${r(t.durationMs)})`:"";process.stdout.write(` attempt ${t.attempt} failed${e}: ${t.message}
9
- `)}}($),+(t.failed>0)}(d,{debug:S})}({suite:A,debug:x.debug,json:S.json,reportJunit:S.reportJunit}):(d(S,A,()=>l(A)),0)}(A,D,j,{debug:K});0!==u&&process.exit(u)}return!0}export{S as runGenericClientBackedCommand};
9
+ `)}}($),+(t.failed>0)}(d,{debug:x})}({suite:A,debug:S.debug,json:x.json,reportJunit:x.reportJunit}):(l(x,A,()=>u(A)),0)}(A,D,F,{debug:j});0!==d&&process.exit(d)}return!0}export{x as runGenericClientBackedCommand};
@@ -119,6 +119,7 @@ export declare type AgentDeviceCommandClient = {
119
119
  clipboard: (options: ClipboardCommandOptions) => Promise<ClipboardCommandResult>;
120
120
  reactNative: (options: ReactNativeCommandOptions) => Promise<CommandRequestResult>;
121
121
  prepare: (options: PrepareCommandOptions) => Promise<CommandRequestResult>;
122
+ viewport: (options: ViewportCommandOptions) => Promise<ViewportCommandResult>;
122
123
  };
123
124
 
124
125
  export declare type AgentDeviceDaemonTransport = (req: Omit<DaemonRequest, 'token'>) => Promise<DaemonResponse>;
@@ -1176,6 +1177,7 @@ declare type ScrollOptions_2 = DeviceCommandBaseOptions & {
1176
1177
  direction: ScrollInputDirection;
1177
1178
  amount?: number;
1178
1179
  pixels?: number;
1180
+ durationMs?: number;
1179
1181
  };
1180
1182
  export { ScrollOptions_2 as ScrollOptions }
1181
1183
 
@@ -1374,6 +1376,16 @@ export declare type TypeTextOptions = DeviceCommandBaseOptions & {
1374
1376
  delayMs?: number;
1375
1377
  };
1376
1378
 
1379
+ declare type ViewportCommandOptions = DeviceCommandBaseOptions & {
1380
+ width: number;
1381
+ height: number;
1382
+ };
1383
+
1384
+ declare type ViewportCommandResult = CommandRequestResult & {
1385
+ width: number;
1386
+ height: number;
1387
+ };
1388
+
1377
1389
  export declare type WaitCommandOptions = DeviceCommandBaseOptions & WaitCommandTarget;
1378
1390
 
1379
1391
  export declare type WaitCommandResult = DaemonResponseData & {