agent-device 0.12.9 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/dist/src/1974.js +2 -2
- package/dist/src/320.js +1 -1
- package/dist/src/3918.js +29 -28
- package/dist/src/7651.js +1 -1
- package/dist/src/8564.js +1 -1
- package/dist/src/8656.js +1 -0
- package/dist/src/9076.js +1 -1
- package/dist/src/9542.js +2 -2
- package/dist/src/backend.js +1 -1
- package/dist/src/bin.js +37 -37
- package/dist/src/contracts.d.ts +12 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon.js +18 -15
- package/dist/src/index.d.ts +34 -1
- package/dist/src/metro-companion.js +1 -1
- package/dist/src/metro.d.ts +21 -0
- package/dist/src/metro.js +1 -1
- package/package.json +12 -3
- package/skills/agent-device/SKILL.md +4 -1
- package/skills/agent-device/references/bootstrap-install.md +26 -6
- package/skills/agent-device/references/debugging.md +3 -1
- package/skills/agent-device/references/exploration.md +15 -2
- package/skills/agent-device/references/remote-tenancy.md +39 -19
- package/skills/agent-device/references/verification.md +3 -2
- package/skills/dogfood/SKILL.md +1 -0
- package/skills/react-devtools/SKILL.md +55 -0
- package/skills/react-devtools/references/commands.md +91 -0
- package/skills/react-devtools/references/profiling.md +74 -0
- package/dist/src/3883.js +0 -1
- package/dist/src/4993.js +0 -1
- package/dist/src/8164.js +0 -1
- package/dist/src/9323.js +0 -5
package/dist/src/bin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
let e,t,s,r,o,n,a;import i from"node:path";import{styleText as l}from"node:util";import{pathToFileURL as c}from"node:url";import u from"node:fs";import p from"node:crypto";import{isEnvTruthy as d,SESSION_SURFACES as m,parseDeviceRotation as f,SETTINGS_USAGE_OVERRIDE as g,parseBatchStepsJson as h,parseWaitArgs as y}from"./3918.js";import{resolveRemoteConfigProfile as w,resolveRemoteConfigPath as b,REMOTE_CONFIG_FIELD_SPECS as v,parseSourceValue as k,buildPrimaryEnvVarName as D}from"./remote-config.js";import{asAppError as $,normalizeError as S,AppError as I}from"./9152.js";import{buildMobileSnapshotPresentation as A,formatSnapshotLine as x,displayNodeLabel as L,readCommandMessage as R,buildSnapshotDisplayLines as N}from"./9076.js";import{createRequestId as C,serializeSessionListEntry as _,serializeSnapshotResult as P,serializeCloseResult as O,readVersion as M,getDiagnosticsMeta as E,emitDiagnostic as F,serializeOpenResult as j,serializeDeployResult as T,resolveDaemonPaths as V,withDiagnosticsScope as B,createAgentDevice as U,flushDiagnosticsToSessionFile as G,serializeEnsureSimulatorResult as q,serializeInstallFromSourceResult as H,serializeDevice as K,localCommandPolicy as J}from"./8564.js";import{stopMetroTunnel as z}from"./metro.js";import{resolveUserPath as W,expandUserHomePath as X}from"./3267.js";import{createLocalArtifactAdapter as Y}from"./io.js";import{createAgentDeviceClient as Z,CLIENT_COMMANDS as Q,sendToDaemon as ee}from"./9542.js";import{splitSelectorFromArgs as et}from"./7847.js";import{maybeRunUpgradeNotifier as es}from"./113.js";function er(e,t){for(let[s,r]of Object.entries(t))void 0!==r&&(e[s]=r);return e}let eo=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],en=["snapshotDepth","snapshotScope","snapshotRaw"],ea=[{key:"config",names:["--config"],type:"string",usageLabel:"--config <path>",usageDescription:"Load CLI defaults from a specific config file"},{key:"remoteConfig",names:["--remote-config"],type:"string",usageLabel:"--remote-config <path>",usageDescription:"Load remote host + Metro workflow settings from a specific profile file"},{key:"stateDir",names:["--state-dir"],type:"string",usageLabel:"--state-dir <path>",usageDescription:"Daemon state directory (defaults to ~/.agent-device)"},{key:"daemonBaseUrl",names:["--daemon-base-url"],type:"string",usageLabel:"--daemon-base-url <url>",usageDescription:"Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)"},{key:"daemonAuthToken",names:["--daemon-auth-token"],type:"string",usageLabel:"--daemon-auth-token <token>",usageDescription:"Remote HTTP daemon auth token (sent as request token and bearer header)"},{key:"daemonTransport",names:["--daemon-transport"],type:"enum",enumValues:["auto","socket","http"],usageLabel:"--daemon-transport auto|socket|http",usageDescription:"Daemon client transport preference"},{key:"daemonServerMode",names:["--daemon-server-mode"],type:"enum",enumValues:["socket","http","dual"],usageLabel:"--daemon-server-mode socket|http|dual",usageDescription:"Daemon server mode used when spawning daemon"},{key:"tenant",names:["--tenant"],type:"string",usageLabel:"--tenant <id>",usageDescription:"Tenant scope identifier for isolated daemon sessions"},{key:"sessionIsolation",names:["--session-isolation"],type:"enum",enumValues:["none","tenant"],usageLabel:"--session-isolation none|tenant",usageDescription:"Session isolation strategy (tenant prefixes session namespace)"},{key:"runId",names:["--run-id"],type:"string",usageLabel:"--run-id <id>",usageDescription:"Run identifier used for tenant lease admission checks"},{key:"leaseId",names:["--lease-id"],type:"string",usageLabel:"--lease-id <id>",usageDescription:"Lease identifier bound to tenant/run admission scope"},{key:"leaseBackend",names:["--lease-backend"],type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"],usageLabel:"--lease-backend ios-simulator|ios-instance|android-instance",usageDescription:"Lease backend for remote tenant connection admission"},{key:"force",names:["--force"],type:"boolean",usageLabel:"--force",usageDescription:"Force connection state replacement when reconnecting"},{key:"sessionLock",names:["--session-lock"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock reject|strip",usageDescription:"Lock bound-session device routing for this CLI invocation and nested batch steps"},{key:"sessionLocked",names:["--session-locked"],type:"boolean",usageLabel:"--session-locked",usageDescription:"Deprecated alias for --session-lock reject"},{key:"sessionLockConflicts",names:["--session-lock-conflicts"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock-conflicts reject|strip",usageDescription:"Deprecated alias for --session-lock"},{key:"platform",names:["--platform"],type:"enum",enumValues:["ios","macos","android","linux","apple"],usageLabel:"--platform ios|macos|android|linux|apple",usageDescription:"Platform to target (`apple` aliases the Apple automation backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv","desktop"],usageLabel:"--target mobile|tv|desktop",usageDescription:"Device target class to match"},{key:"device",names:["--device"],type:"string",usageLabel:"--device <name>",usageDescription:"Device name to target"},{key:"udid",names:["--udid"],type:"string",usageLabel:"--udid <udid>",usageDescription:"iOS device UDID"},{key:"serial",names:["--serial"],type:"string",usageLabel:"--serial <serial>",usageDescription:"Android device serial"},{key:"surface",names:["--surface"],type:"enum",enumValues:m,usageLabel:"--surface app|frontmost-app|desktop|menubar",usageDescription:"macOS session surface for open (defaults to app)"},{key:"headless",names:["--headless"],type:"boolean",usageLabel:"--headless",usageDescription:"Boot: launch Android emulator without a GUI window"},{key:"runtime",names:["--runtime"],type:"string",usageLabel:"--runtime <id>",usageDescription:"ensure-simulator: CoreSimulator runtime identifier (e.g. com.apple.CoreSimulator.SimRuntime.iOS-18-0)"},{key:"metroHost",names:["--metro-host"],type:"string",usageLabel:"--metro-host <host>",usageDescription:"Session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"Session-scoped Metro/debug port hint"},{key:"metroProjectRoot",names:["--project-root"],type:"string",usageLabel:"--project-root <path>",usageDescription:"metro prepare: React Native project root (default: cwd)"},{key:"metroKind",names:["--kind"],type:"enum",enumValues:["auto","react-native","expo"],usageLabel:"--kind auto|react-native|expo",usageDescription:"metro prepare: detect or force the Metro launcher kind"},{key:"metroPublicBaseUrl",names:["--public-base-url"],type:"string",usageLabel:"--public-base-url <url>",usageDescription:"metro prepare: public base URL used for direct bundle hints"},{key:"metroProxyBaseUrl",names:["--proxy-base-url"],type:"string",usageLabel:"--proxy-base-url <url>",usageDescription:"metro prepare: optional bridge origin for remote Metro access"},{key:"metroBearerToken",names:["--bearer-token"],type:"string",usageLabel:"--bearer-token <token>",usageDescription:"metro prepare: host bridge bearer token (prefer AGENT_DEVICE_PROXY_TOKEN or AGENT_DEVICE_METRO_BEARER_TOKEN)"},{key:"metroPreparePort",names:["--port"],type:"int",min:1,max:65535,usageLabel:"--port <port>",usageDescription:"metro prepare: local Metro port (default: 8081)"},{key:"metroListenHost",names:["--listen-host"],type:"string",usageLabel:"--listen-host <host>",usageDescription:"metro prepare: host Metro listens on (default: 0.0.0.0)"},{key:"metroStatusHost",names:["--status-host"],type:"string",usageLabel:"--status-host <host>",usageDescription:"metro prepare: host used for local /status polling (default: 127.0.0.1)"},{key:"metroStartupTimeoutMs",names:["--startup-timeout-ms"],type:"int",min:1,usageLabel:"--startup-timeout-ms <ms>",usageDescription:"metro prepare: timeout while waiting for Metro to become ready"},{key:"metroProbeTimeoutMs",names:["--probe-timeout-ms"],type:"int",min:1,usageLabel:"--probe-timeout-ms <ms>",usageDescription:"metro prepare: timeout for /status and proxy bridge calls"},{key:"metroRuntimeFile",names:["--runtime-file"],type:"string",usageLabel:"--runtime-file <path>",usageDescription:"metro prepare: optional file path to persist the JSON result"},{key:"metroNoReuseExisting",names:["--no-reuse-existing"],type:"boolean",usageLabel:"--no-reuse-existing",usageDescription:"metro prepare: always start a fresh Metro process"},{key:"metroNoInstallDeps",names:["--no-install-deps"],type:"boolean",usageLabel:"--no-install-deps",usageDescription:"metro prepare: skip package-manager install when node_modules is missing"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"Session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"Session-scoped deep link / launch URL hint"},{key:"boot",names:["--boot"],type:"boolean",usageLabel:"--boot",usageDescription:"ensure-simulator: boot the simulator after ensuring it exists"},{key:"reuseExisting",names:["--reuse-existing"],type:"boolean",usageLabel:"--reuse-existing",usageDescription:"ensure-simulator: reuse an existing simulator (default: true)"},{key:"iosSimulatorDeviceSet",names:["--ios-simulator-device-set"],type:"string",usageLabel:"--ios-simulator-device-set <path>",usageDescription:"Scope iOS simulator discovery/commands to this simulator device set"},{key:"androidDeviceAllowlist",names:["--android-device-allowlist"],type:"string",usageLabel:"--android-device-allowlist <serials>",usageDescription:"Comma/space separated Android serial allowlist for discovery/selection"},{key:"activity",names:["--activity"],type:"string",usageLabel:"--activity <component>",usageDescription:"Android app launch activity (package/Activity); not for URL opens"},{key:"header",names:["--header"],type:"string",multiple:!0,usageLabel:"--header <name:value>",usageDescription:"install-from-source: repeatable HTTP header for URL downloads"},{key:"session",names:["--session"],type:"string",usageLabel:"--session <name>",usageDescription:"Named session"},{key:"count",names:["--count"],type:"int",min:1,max:200,usageLabel:"--count <n>",usageDescription:"Repeat count for press/swipe series"},{key:"fps",names:["--fps"],type:"int",min:1,max:120,usageLabel:"--fps <n>",usageDescription:"Record: target frames per second (iOS physical device runner)"},{key:"quality",names:["--quality"],type:"int",min:5,max:10,usageLabel:"--quality <5-10>",usageDescription:"Record: scale recording resolution from 5 (50%) through 10 (native resolution)"},{key:"hideTouches",names:["--hide-touches"],type:"boolean",usageLabel:"--hide-touches",usageDescription:"Record: disable touch overlays in the final video"},{key:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{key:"delayMs",names:["--delay-ms"],type:"int",min:0,max:1e4,usageLabel:"--delay-ms <ms>",usageDescription:"Delay between typed characters"},{key:"holdMs",names:["--hold-ms"],type:"int",min:0,max:1e4,usageLabel:"--hold-ms <ms>",usageDescription:"Press hold duration for each iteration"},{key:"jitterPx",names:["--jitter-px"],type:"int",min:0,max:100,usageLabel:"--jitter-px <n>",usageDescription:"Deterministic coordinate jitter radius for press"},{key:"pixels",names:["--pixels"],type:"int",min:1,max:1e5,usageLabel:"--pixels <n>",usageDescription:"Scroll: explicit gesture distance in pixels"},{key:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{key:"clickButton",names:["--button"],type:"enum",enumValues:["primary","secondary","middle"],usageLabel:"--button primary|secondary|middle",usageDescription:"Click: choose mouse button (middle reserved for future macOS support)"},{key:"backMode",names:["--in-app"],type:"enum",enumValues:["in-app","system"],setValue:"in-app",usageLabel:"--in-app",usageDescription:"Back: use app-provided back UI when available"},{key:"backMode",names:["--system"],type:"enum",enumValues:["in-app","system"],setValue:"system",usageLabel:"--system",usageDescription:"Back: use system back input or gesture when available"},{key:"pauseMs",names:["--pause-ms"],type:"int",min:0,max:1e4,usageLabel:"--pause-ms <ms>",usageDescription:"Delay between swipe iterations"},{key:"pattern",names:["--pattern"],type:"enum",enumValues:["one-way","ping-pong"],usageLabel:"--pattern one-way|ping-pong",usageDescription:"Swipe repeat pattern"},{key:"verbose",names:["--debug","--verbose","-v"],type:"boolean",usageLabel:"--debug, --verbose, -v",usageDescription:"Enable debug diagnostics and stream daemon/runner logs"},{key:"json",names:["--json"],type:"boolean",usageLabel:"--json",usageDescription:"JSON output"},{key:"help",names:["--help","-h"],type:"boolean",usageLabel:"--help, -h",usageDescription:"Print help and exit"},{key:"version",names:["--version","-V"],type:"boolean",usageLabel:"--version, -V",usageDescription:"Print version and exit"},{key:"snapshotDiff",names:["--diff"],type:"boolean",usageLabel:"--diff",usageDescription:"Snapshot: show structural diff against the previous session baseline"},{key:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{key:"networkInclude",names:["--include"],type:"enum",enumValues:["summary","headers","body","all"],usageLabel:"--include summary|headers|body|all",usageDescription:"Network: include headers, bodies, or both in output"},{key:"shutdown",names:["--shutdown"],type:"boolean",usageLabel:"--shutdown",usageDescription:"close: shutdown associated iOS simulator after ending session"},{key:"relaunch",names:["--relaunch"],type:"boolean",usageLabel:"--relaunch",usageDescription:"open: terminate app process before launching it"},{key:"restart",names:["--restart"],type:"boolean",usageLabel:"--restart",usageDescription:"logs clear: stop active stream, clear logs, then start streaming again"},{key:"retainPaths",names:["--retain-paths"],type:"boolean",usageLabel:"--retain-paths",usageDescription:"install-from-source: keep materialized artifact paths after install"},{key:"retentionMs",names:["--retention-ms"],type:"int",min:1,usageLabel:"--retention-ms <ms>",usageDescription:"install-from-source: retention TTL for materialized artifact paths"},{key:"noRecord",names:["--no-record"],type:"boolean",usageLabel:"--no-record",usageDescription:"Do not record this action"},{key:"replayUpdate",names:["--update","-u"],type:"boolean",usageLabel:"--update, -u",usageDescription:"Replay: update selectors and rewrite replay file in place"},{key:"failFast",names:["--fail-fast"],type:"boolean",usageLabel:"--fail-fast",usageDescription:"Test: stop the suite after the first failing script"},{key:"timeoutMs",names:["--timeout"],type:"int",min:1,usageLabel:"--timeout <ms>",usageDescription:"Test: maximum wall-clock time per script attempt"},{key:"retries",names:["--retries"],type:"int",min:0,max:3,usageLabel:"--retries <n>",usageDescription:"Test: retry each failed script up to n additional times"},{key:"artifactsDir",names:["--artifacts-dir"],type:"string",usageLabel:"--artifacts-dir <path>",usageDescription:"Test: root directory for suite artifacts"},{key:"reportJunit",names:["--report-junit"],type:"string",usageLabel:"--report-junit <path>",usageDescription:"Test: write a JUnit XML report for the replay suite"},{key:"steps",names:["--steps"],type:"string",usageLabel:"--steps <json>",usageDescription:"Batch: JSON array of steps"},{key:"stepsFile",names:["--steps-file"],type:"string",usageLabel:"--steps-file <path>",usageDescription:"Batch: read steps JSON from file"},{key:"batchOnError",names:["--on-error"],type:"enum",enumValues:["stop"],usageLabel:"--on-error stop",usageDescription:"Batch: stop when a step fails"},{key:"batchMaxSteps",names:["--max-steps"],type:"int",min:1,max:1e3,usageLabel:"--max-steps <n>",usageDescription:"Batch: maximum number of allowed steps"},{key:"appsFilter",names:["--user-installed"],type:"enum",setValue:"user-installed",usageLabel:"--user-installed",usageDescription:"Apps: list user-installed apps"},{key:"appsFilter",names:["--all"],type:"enum",setValue:"all",usageLabel:"--all",usageDescription:"Apps: list all apps (include system/default apps)"},{key:"snapshotInteractiveOnly",names:["-i"],type:"boolean",usageLabel:"-i",usageDescription:"Snapshot: interactive elements only"},{key:"snapshotCompact",names:["-c"],type:"boolean",usageLabel:"-c",usageDescription:"Snapshot: compact output (drop empty structure)"},{key:"snapshotDepth",names:["--depth","-d"],type:"int",min:0,usageLabel:"--depth, -d <depth>",usageDescription:"Snapshot: limit snapshot depth"},{key:"snapshotScope",names:["--scope","-s"],type:"string",usageLabel:"--scope, -s <scope>",usageDescription:"Snapshot: scope snapshot to label/identifier"},{key:"snapshotRaw",names:["--raw"],type:"boolean",usageLabel:"--raw",usageDescription:"Snapshot: raw node output"},{key:"findFirst",names:["--first"],type:"boolean",usageLabel:"--first",usageDescription:"Find: pick the first match when ambiguous"},{key:"findLast",names:["--last"],type:"boolean",usageLabel:"--last",usageDescription:"Find: pick the last match when ambiguous"},{key:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"},{key:"overlayRefs",names:["--overlay-refs"],type:"boolean",usageLabel:"--overlay-refs",usageDescription:"Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide"},{key:"screenshotFullscreen",names:["--fullscreen"],type:"boolean",usageLabel:"--fullscreen",usageDescription:"Screenshot: capture the full screen instead of the app window"},{key:"screenshotMaxSize",names:["--max-size"],type:"int",min:1,usageLabel:"--max-size <px>",usageDescription:"Screenshot: downscale so the longest edge is at most <px>"},{key:"baseline",names:["--baseline","-b"],type:"string",usageLabel:"--baseline, -b <path>",usageDescription:"Diff screenshot: path to baseline image file"},{key:"threshold",names:["--threshold"],type:"string",usageLabel:"--threshold <0-1>",usageDescription:"Diff screenshot: color distance threshold (default 0.1)"}],ei=new Set(["json","config","remoteConfig","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","leaseBackend","sessionLock","sessionLocked","sessionLockConflicts","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),el={boot:{helpDescription:"Ensure target device/simulator is booted and ready",summary:"Boot target device/simulator",positionalArgs:[],allowedFlags:["headless"]},open:{helpDescription:"Boot device/simulator; optionally launch app or deep link URL (macOS also supports --surface app|frontmost-app|desktop|menubar)",summary:"Open an app, deep link or URL, save replays",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","saveScript","relaunch","surface"]},connect:{usageOverride:"connect --remote-config <path> [--tenant <id>] [--run-id <id>] [--lease-backend <backend>] [--force]",helpDescription:"Connect to a remote daemon and save remote session state",summary:"Connect to remote daemon",positionalArgs:[],allowedFlags:["force","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","launchUrl"],skipCapabilityCheck:!0},disconnect:{helpDescription:"Disconnect remote daemon state, stop owned Metro companion, and release lease",summary:"Disconnect remote daemon",positionalArgs:[],allowedFlags:["shutdown"],skipCapabilityCheck:!0},connection:{usageOverride:"connection status",listUsageOverride:"connection status",helpDescription:"Inspect active remote connection state",summary:"Inspect remote connection",positionalArgs:["status"],allowedFlags:[],skipCapabilityCheck:!0},close:{helpDescription:"Close app or just end session",summary:"Close app or end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},reinstall:{helpDescription:"Uninstall + install app from binary path",summary:"Reinstall app from binary path",positionalArgs:["app","path"],allowedFlags:[]},install:{helpDescription:"Install app from binary path without uninstalling first",summary:"Install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},"install-from-source":{helpDescription:"Install app from a URL source through the normal daemon artifact flow",summary:"Install app from a URL source",positionalArgs:["url"],allowedFlags:["header","retainPaths","retentionMs"]},push:{helpDescription:"Simulate push notification payload delivery",summary:"Deliver push payload",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},snapshot:{usageOverride:"snapshot [--diff] [-i] [-c] [-d <depth>] [-s <scope>] [--raw]",helpDescription:"Capture accessibility tree or diff against the previous session baseline",positionalArgs:[],allowedFlags:["snapshotDiff",...eo]},diff:{usageOverride:"diff snapshot | diff screenshot --baseline <path> [current.png] [--out <diff.png>] [--threshold <0-1>] [--overlay-refs]",helpDescription:"Diff accessibility snapshot or compare screenshots pixel-by-pixel",summary:"Diff snapshot or screenshot",positionalArgs:["kind","current?"],allowedFlags:[...eo,"baseline","threshold","out","overlayRefs"]},"ensure-simulator":{helpDescription:"Ensure an iOS simulator exists in a device set (create if missing)",summary:"Ensure iOS simulator exists",positionalArgs:[],allowedFlags:["runtime","boot","reuseExisting"],skipCapabilityCheck:!0},devices:{helpDescription:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},apps:{helpDescription:"List installed apps (includes default/system apps by default)",summary:"List installed apps",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:"all"}},appstate:{helpDescription:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},metro:{usageOverride:"metro prepare (--public-base-url <url> | --proxy-base-url <url>) [--project-root <path>] [--port <port>] [--kind auto|react-native|expo]",listUsageOverride:"metro prepare --public-base-url <url> | --proxy-base-url <url>",helpDescription:"Prepare a local Metro runtime and optionally bridge it through a remote host",summary:"Prepare local Metro runtime",positionalArgs:["prepare"],allowedFlags:["metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",listUsageOverride:"clipboard read | clipboard write <text>",helpDescription:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",helpDescription:"Inspect Android keyboard visibility/type or dismiss the device keyboard",summary:"Inspect or dismiss the device keyboard",positionalArgs:["action?"],allowedFlags:[]},perf:{helpDescription:"Show session performance metrics",summary:"Show performance metrics",positionalArgs:[],allowedFlags:[]},back:{usageOverride:"back [--in-app|--system]",helpDescription:"Navigate back with explicit app or system semantics",summary:"Go back",positionalArgs:[],allowedFlags:["backMode"]},home:{helpDescription:"Go to home screen (where supported)",summary:"Go home",positionalArgs:[],allowedFlags:[]},rotate:{usageOverride:"rotate <portrait|portrait-upside-down|landscape-left|landscape-right>",helpDescription:"Rotate device orientation on iOS and Android",summary:"Rotate device orientation",positionalArgs:["orientation"],allowedFlags:[]},"app-switcher":{helpDescription:"Open app switcher (where supported)",summary:"Open app switcher",positionalArgs:[],allowedFlags:[]},wait:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",helpDescription:"Wait for duration, text, ref, or selector to appear",summary:"Wait for time, text, ref, or selector",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...en]},alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",helpDescription:"Inspect or handle alert (iOS simulator and macOS desktop)",summary:"Inspect or handle iOS/macOS alerts",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",helpDescription:"Tap/click by coordinates, snapshot ref, or selector",summary:"Tap by coordinates, ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap","clickButton",...en]},get:{usageOverride:"get text|attrs <@ref|selector>",helpDescription:"Return element text/attributes by ref or selector",summary:"Get text or attrs by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...en]},replay:{helpDescription:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate"],skipCapabilityCheck:!0},test:{usageOverride:"test <path-or-glob>...",listUsageOverride:"test <path-or-glob>...",helpDescription:"Run one or more .ad scripts as a serial test suite",summary:"Run .ad test suites",positionalArgs:["pathOrGlob"],allowsExtraPositionals:!0,allowedFlags:["replayUpdate","failFast","timeoutMs","retries","artifactsDir","reportJunit"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",listUsageOverride:"batch --steps <json> | --steps-file <path>",helpDescription:"Execute multiple commands in one daemon request",summary:"Run multiple commands",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",helpDescription:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",summary:"Press by coordinates, ref, or selector",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...en]},longpress:{helpDescription:"Long press by coordinates (iOS and Android)",summary:"Long press by coordinates",positionalArgs:["x","y","durationMs?"],allowedFlags:[]},swipe:{helpDescription:"Swipe coordinates with optional repeat pattern",summary:"Swipe coordinates",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{helpDescription:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},type:{helpDescription:"Type text in focused field",positionalArgs:["text"],allowsExtraPositionals:!0,allowedFlags:["delayMs"]},fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",helpDescription:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...en,"delayMs"]},scroll:{usageOverride:"scroll <direction> [amount] [--pixels <n>]",helpDescription:"Scroll in direction (relative amount or explicit pixels)",summary:"Scroll in a direction",positionalArgs:["direction","amount?"],allowedFlags:["pixels"]},pinch:{helpDescription:"Pinch/zoom gesture (Apple simulator or macOS app session)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},screenshot:{helpDescription:"Capture screenshot (macOS app sessions default to the app window; use --fullscreen for full desktop, --max-size to downscale, or --overlay-refs to annotate the image with current refs)",positionalArgs:["path?"],allowedFlags:["out","overlayRefs","screenshotFullscreen","screenshotMaxSize"]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",helpDescription:"Trigger app-defined event hook via deep link template",summary:"Trigger app event hook",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] [--quality <5-10>] [--hide-touches] | record stop",listUsageOverride:"record start [path] | record stop",helpDescription:"Start/stop screen recording",summary:"Start or stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps","quality","hideTouches"]},trace:{usageOverride:"trace start [path] | trace stop [path]",listUsageOverride:"trace start [path] | trace stop",helpDescription:"Start/stop trace log capture",summary:"Start or stop trace capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",helpDescription:"Session app log info, start/stop streaming, diagnostics, and markers",summary:"Manage session app logs",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] [--include summary|headers|body|all] | network log [limit] [summary|headers|body|all] [--include summary|headers|body|all]",helpDescription:"Dump recent HTTP(s) traffic parsed from the session app log",summary:"Show recent HTTP traffic",positionalArgs:["dump|log","limit?","include?"],allowedFlags:["networkInclude"]},find:{usageOverride:"find <locator|text> <action> [value] [--first|--last]",helpDescription:"Find by text/label/value/role/id and run action",summary:"Find an element and act",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw","findFirst","findLast"]},is:{helpDescription:"Assert UI state (visible|hidden|exists|editable|selected|text)",summary:"Assert UI state",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...en]},settings:{usageOverride:g,listUsageOverride:"settings [area] [options]",helpDescription:"Toggle OS settings, appearance, and app permissions (macOS supports only settings appearance <light|dark|toggle> and settings permission <grant|reset> <accessibility|screen-recording|input-monitoring>; wifi|airplane|location remain unsupported on macOS; mobile permission actions use the active session app)",summary:"Change OS settings and app permissions",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",helpDescription:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},ec=new Map,eu=new Map;for(let e of ea){for(let t of e.names)ec.set(t,e);let t=eu.get(e.key);t?t.push(e):eu.set(e.key,[e])}function ep(e){if(e)return el[e]}function ed(){return Object.keys(el)}function em(e){let t=e.endsWith("?"),s=t?e.slice(0,-1):e;return t?`[${s}]`:`<${s}>`}let ef=(e=`agent-device <command> [args] [--json]
|
|
1
|
+
let e,t,s,r,o,n,a;import i from"node:path";import{styleText as l}from"node:util";import{pathToFileURL as c}from"node:url";import u from"node:fs";import p from"node:crypto";import{isEnvTruthy as d,SESSION_SURFACES as m,parseDeviceRotation as f,SETTINGS_USAGE_OVERRIDE as g,parseBatchStepsJson as h,parseWaitArgs as y}from"./3918.js";import{resolveRemoteConfigProfile as w,resolveRemoteConfigPath as b,REMOTE_CONFIG_FIELD_SPECS as v,parseSourceValue as k,buildPrimaryEnvVarName as D}from"./remote-config.js";import{asAppError as I,normalizeError as A,AppError as $}from"./9152.js";import{buildMobileSnapshotPresentation as S,formatSnapshotLine as x,displayNodeLabel as L,readCommandMessage as R,buildSnapshotDisplayLines as N}from"./9076.js";import{createRequestId as C,serializeSessionListEntry as _,serializeSnapshotResult as P,serializeCloseResult as O,readVersion as E,getDiagnosticsMeta as M,emitDiagnostic as F,serializeOpenResult as j,serializeDeployResult as V,resolveDaemonPaths as T,withDiagnosticsScope as B,createAgentDevice as U,flushDiagnosticsToSessionFile as G,serializeEnsureSimulatorResult as q,serializeInstallFromSourceResult as K,serializeDevice as H,localCommandPolicy as J}from"./8564.js";import{stopMetroCompanion as z,ensureMetroCompanion as W}from"./1974.js";import{stopMetroTunnel as Y}from"./metro.js";import{resolveUserPath as X,expandUserHomePath as Z}from"./3267.js";import{createLocalArtifactAdapter as Q}from"./io.js";import{createAgentDeviceClient as ee,CLIENT_COMMANDS as et,sendToDaemon as es}from"./9542.js";import{splitSelectorFromArgs as er}from"./7847.js";import{runCmdStreaming as eo}from"./9818.js";import{maybeRunUpgradeNotifier as en}from"./113.js";function ea(e,t){for(let[s,r]of Object.entries(t))void 0!==r&&(e[s]=r);return e}let ei=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],el=["snapshotDepth","snapshotScope","snapshotRaw"],ec=[{key:"config",names:["--config"],type:"string",usageLabel:"--config <path>",usageDescription:"Load CLI defaults from a specific config file"},{key:"remoteConfig",names:["--remote-config"],type:"string",usageLabel:"--remote-config <path>",usageDescription:"Load remote host + Metro workflow settings from a specific profile file"},{key:"stateDir",names:["--state-dir"],type:"string",usageLabel:"--state-dir <path>",usageDescription:"Daemon state directory (defaults to ~/.agent-device)"},{key:"daemonBaseUrl",names:["--daemon-base-url"],type:"string",usageLabel:"--daemon-base-url <url>",usageDescription:"Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)"},{key:"daemonAuthToken",names:["--daemon-auth-token"],type:"string",usageLabel:"--daemon-auth-token <token>",usageDescription:"Remote HTTP daemon auth token (sent as request token and bearer header)"},{key:"daemonTransport",names:["--daemon-transport"],type:"enum",enumValues:["auto","socket","http"],usageLabel:"--daemon-transport auto|socket|http",usageDescription:"Daemon client transport preference"},{key:"daemonServerMode",names:["--daemon-server-mode"],type:"enum",enumValues:["socket","http","dual"],usageLabel:"--daemon-server-mode socket|http|dual",usageDescription:"Daemon server mode used when spawning daemon"},{key:"tenant",names:["--tenant"],type:"string",usageLabel:"--tenant <id>",usageDescription:"Tenant scope identifier for isolated daemon sessions"},{key:"sessionIsolation",names:["--session-isolation"],type:"enum",enumValues:["none","tenant"],usageLabel:"--session-isolation none|tenant",usageDescription:"Session isolation strategy (tenant prefixes session namespace)"},{key:"runId",names:["--run-id"],type:"string",usageLabel:"--run-id <id>",usageDescription:"Run identifier used for tenant lease admission checks"},{key:"leaseId",names:["--lease-id"],type:"string",usageLabel:"--lease-id <id>",usageDescription:"Lease identifier bound to tenant/run admission scope"},{key:"leaseBackend",names:["--lease-backend"],type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"],usageLabel:"--lease-backend ios-simulator|ios-instance|android-instance",usageDescription:"Lease backend for remote tenant connection admission"},{key:"force",names:["--force"],type:"boolean",usageLabel:"--force",usageDescription:"Force connection state replacement when reconnecting"},{key:"sessionLock",names:["--session-lock"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock reject|strip",usageDescription:"Lock bound-session device routing for this CLI invocation and nested batch steps"},{key:"sessionLocked",names:["--session-locked"],type:"boolean",usageLabel:"--session-locked",usageDescription:"Deprecated alias for --session-lock reject"},{key:"sessionLockConflicts",names:["--session-lock-conflicts"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock-conflicts reject|strip",usageDescription:"Deprecated alias for --session-lock"},{key:"platform",names:["--platform"],type:"enum",enumValues:["ios","macos","android","linux","apple"],usageLabel:"--platform ios|macos|android|linux|apple",usageDescription:"Platform to target (`apple` aliases the Apple automation backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv","desktop"],usageLabel:"--target mobile|tv|desktop",usageDescription:"Device target class to match"},{key:"device",names:["--device"],type:"string",usageLabel:"--device <name>",usageDescription:"Device name to target"},{key:"udid",names:["--udid"],type:"string",usageLabel:"--udid <udid>",usageDescription:"iOS device UDID"},{key:"serial",names:["--serial"],type:"string",usageLabel:"--serial <serial>",usageDescription:"Android device serial"},{key:"surface",names:["--surface"],type:"enum",enumValues:m,usageLabel:"--surface app|frontmost-app|desktop|menubar",usageDescription:"macOS session surface for open (defaults to app)"},{key:"headless",names:["--headless"],type:"boolean",usageLabel:"--headless",usageDescription:"Boot: launch Android emulator without a GUI window"},{key:"runtime",names:["--runtime"],type:"string",usageLabel:"--runtime <id>",usageDescription:"ensure-simulator: CoreSimulator runtime identifier (e.g. com.apple.CoreSimulator.SimRuntime.iOS-18-0)"},{key:"metroHost",names:["--metro-host"],type:"string",usageLabel:"--metro-host <host>",usageDescription:"Session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"Session-scoped Metro/debug port hint"},{key:"metroProjectRoot",names:["--project-root"],type:"string",usageLabel:"--project-root <path>",usageDescription:"metro prepare: React Native project root (default: cwd)"},{key:"metroKind",names:["--kind"],type:"enum",enumValues:["auto","react-native","expo"],usageLabel:"--kind auto|react-native|expo",usageDescription:"metro prepare: detect or force the Metro launcher kind"},{key:"metroPublicBaseUrl",names:["--public-base-url"],type:"string",usageLabel:"--public-base-url <url>",usageDescription:"metro prepare: public base URL used for direct bundle hints"},{key:"metroProxyBaseUrl",names:["--proxy-base-url"],type:"string",usageLabel:"--proxy-base-url <url>",usageDescription:"metro prepare: optional bridge origin for remote Metro access"},{key:"metroBearerToken",names:["--bearer-token"],type:"string",usageLabel:"--bearer-token <token>",usageDescription:"metro prepare: host bridge bearer token (prefer AGENT_DEVICE_PROXY_TOKEN or AGENT_DEVICE_METRO_BEARER_TOKEN)"},{key:"metroPreparePort",names:["--port"],type:"int",min:1,max:65535,usageLabel:"--port <port>",usageDescription:"metro prepare: local Metro port (default: 8081)"},{key:"metroListenHost",names:["--listen-host"],type:"string",usageLabel:"--listen-host <host>",usageDescription:"metro prepare: host Metro listens on (default: 0.0.0.0)"},{key:"metroStatusHost",names:["--status-host"],type:"string",usageLabel:"--status-host <host>",usageDescription:"metro prepare: host used for local /status polling (default: 127.0.0.1)"},{key:"metroStartupTimeoutMs",names:["--startup-timeout-ms"],type:"int",min:1,usageLabel:"--startup-timeout-ms <ms>",usageDescription:"metro prepare: timeout while waiting for Metro to become ready"},{key:"metroProbeTimeoutMs",names:["--probe-timeout-ms"],type:"int",min:1,usageLabel:"--probe-timeout-ms <ms>",usageDescription:"metro prepare: timeout for /status and proxy bridge calls"},{key:"metroRuntimeFile",names:["--runtime-file"],type:"string",usageLabel:"--runtime-file <path>",usageDescription:"metro prepare: optional file path to persist the JSON result"},{key:"metroNoReuseExisting",names:["--no-reuse-existing"],type:"boolean",usageLabel:"--no-reuse-existing",usageDescription:"metro prepare: always start a fresh Metro process"},{key:"metroNoInstallDeps",names:["--no-install-deps"],type:"boolean",usageLabel:"--no-install-deps",usageDescription:"metro prepare: skip package-manager install when node_modules is missing"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"Session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"Session-scoped deep link / launch URL hint"},{key:"boot",names:["--boot"],type:"boolean",usageLabel:"--boot",usageDescription:"ensure-simulator: boot the simulator after ensuring it exists"},{key:"reuseExisting",names:["--reuse-existing"],type:"boolean",usageLabel:"--reuse-existing",usageDescription:"ensure-simulator: reuse an existing simulator (default: true)"},{key:"iosSimulatorDeviceSet",names:["--ios-simulator-device-set"],type:"string",usageLabel:"--ios-simulator-device-set <path>",usageDescription:"Scope iOS simulator discovery/commands to this simulator device set"},{key:"androidDeviceAllowlist",names:["--android-device-allowlist"],type:"string",usageLabel:"--android-device-allowlist <serials>",usageDescription:"Comma/space separated Android serial allowlist for discovery/selection"},{key:"activity",names:["--activity"],type:"string",usageLabel:"--activity <component>",usageDescription:"Android app launch activity (package/Activity); not for URL opens"},{key:"header",names:["--header"],type:"string",multiple:!0,usageLabel:"--header <name:value>",usageDescription:"install-from-source: repeatable HTTP header for URL downloads"},{key:"githubActionsArtifact",names:["--github-actions-artifact"],type:"string",usageLabel:"--github-actions-artifact <owner/repo:artifact>",usageDescription:"install-from-source: GitHub Actions artifact resolved by a remote daemon"},{key:"installSource",names:[],type:"string"},{key:"session",names:["--session"],type:"string",usageLabel:"--session <name>",usageDescription:"Named session"},{key:"count",names:["--count"],type:"int",min:1,max:200,usageLabel:"--count <n>",usageDescription:"Repeat count for press/swipe series"},{key:"fps",names:["--fps"],type:"int",min:1,max:120,usageLabel:"--fps <n>",usageDescription:"Record: target frames per second (iOS physical device runner)"},{key:"quality",names:["--quality"],type:"int",min:5,max:10,usageLabel:"--quality <5-10>",usageDescription:"Record: scale recording resolution from 5 (50%) through 10 (native resolution)"},{key:"hideTouches",names:["--hide-touches"],type:"boolean",usageLabel:"--hide-touches",usageDescription:"Record: disable touch overlays in the final video"},{key:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{key:"delayMs",names:["--delay-ms"],type:"int",min:0,max:1e4,usageLabel:"--delay-ms <ms>",usageDescription:"Delay between typed characters"},{key:"holdMs",names:["--hold-ms"],type:"int",min:0,max:1e4,usageLabel:"--hold-ms <ms>",usageDescription:"Press hold duration for each iteration"},{key:"jitterPx",names:["--jitter-px"],type:"int",min:0,max:100,usageLabel:"--jitter-px <n>",usageDescription:"Deterministic coordinate jitter radius for press"},{key:"pixels",names:["--pixels"],type:"int",min:1,max:1e5,usageLabel:"--pixels <n>",usageDescription:"Scroll: explicit gesture distance in pixels"},{key:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{key:"clickButton",names:["--button"],type:"enum",enumValues:["primary","secondary","middle"],usageLabel:"--button primary|secondary|middle",usageDescription:"Click: choose mouse button (middle reserved for future macOS support)"},{key:"backMode",names:["--in-app"],type:"enum",enumValues:["in-app","system"],setValue:"in-app",usageLabel:"--in-app",usageDescription:"Back: use app-provided back UI when available"},{key:"backMode",names:["--system"],type:"enum",enumValues:["in-app","system"],setValue:"system",usageLabel:"--system",usageDescription:"Back: use system back input or gesture when available"},{key:"pauseMs",names:["--pause-ms"],type:"int",min:0,max:1e4,usageLabel:"--pause-ms <ms>",usageDescription:"Delay between swipe iterations"},{key:"pattern",names:["--pattern"],type:"enum",enumValues:["one-way","ping-pong"],usageLabel:"--pattern one-way|ping-pong",usageDescription:"Swipe repeat pattern"},{key:"verbose",names:["--debug","--verbose","-v"],type:"boolean",usageLabel:"--debug, --verbose, -v",usageDescription:"Enable debug diagnostics and stream daemon/runner logs"},{key:"json",names:["--json"],type:"boolean",usageLabel:"--json",usageDescription:"JSON output"},{key:"help",names:["--help","-h"],type:"boolean",usageLabel:"--help, -h",usageDescription:"Print help and exit"},{key:"version",names:["--version","-V"],type:"boolean",usageLabel:"--version, -V",usageDescription:"Print version and exit"},{key:"snapshotDiff",names:["--diff"],type:"boolean",usageLabel:"--diff",usageDescription:"Snapshot: show structural diff against the previous session baseline"},{key:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{key:"networkInclude",names:["--include"],type:"enum",enumValues:["summary","headers","body","all"],usageLabel:"--include summary|headers|body|all",usageDescription:"Network: include headers, bodies, or both in output"},{key:"shutdown",names:["--shutdown"],type:"boolean",usageLabel:"--shutdown",usageDescription:"close: shutdown associated iOS simulator after ending session"},{key:"relaunch",names:["--relaunch"],type:"boolean",usageLabel:"--relaunch",usageDescription:"open: terminate app process before launching it"},{key:"restart",names:["--restart"],type:"boolean",usageLabel:"--restart",usageDescription:"logs clear: stop active stream, clear logs, then start streaming again"},{key:"retainPaths",names:["--retain-paths"],type:"boolean",usageLabel:"--retain-paths",usageDescription:"install-from-source: keep materialized artifact paths after install"},{key:"retentionMs",names:["--retention-ms"],type:"int",min:1,usageLabel:"--retention-ms <ms>",usageDescription:"install-from-source: retention TTL for materialized artifact paths"},{key:"noRecord",names:["--no-record"],type:"boolean",usageLabel:"--no-record",usageDescription:"Do not record this action"},{key:"replayUpdate",names:["--update","-u"],type:"boolean",usageLabel:"--update, -u",usageDescription:"Replay: update selectors and rewrite replay file in place"},{key:"replayEnv",names:["-e","--env"],type:"string",multiple:!0,usageLabel:"-e KEY=VALUE, --env KEY=VALUE",usageDescription:"Replay/Test: inject or override a ${KEY} variable for the script (repeatable)"},{key:"failFast",names:["--fail-fast"],type:"boolean",usageLabel:"--fail-fast",usageDescription:"Test: stop the suite after the first failing script"},{key:"timeoutMs",names:["--timeout"],type:"int",min:1,usageLabel:"--timeout <ms>",usageDescription:"Test: maximum wall-clock time per script attempt"},{key:"retries",names:["--retries"],type:"int",min:0,max:3,usageLabel:"--retries <n>",usageDescription:"Test: retry each failed script up to n additional times"},{key:"artifactsDir",names:["--artifacts-dir"],type:"string",usageLabel:"--artifacts-dir <path>",usageDescription:"Test: root directory for suite artifacts"},{key:"reportJunit",names:["--report-junit"],type:"string",usageLabel:"--report-junit <path>",usageDescription:"Test: write a JUnit XML report for the replay suite"},{key:"steps",names:["--steps"],type:"string",usageLabel:"--steps <json>",usageDescription:"Batch: JSON array of steps"},{key:"stepsFile",names:["--steps-file"],type:"string",usageLabel:"--steps-file <path>",usageDescription:"Batch: read steps JSON from file"},{key:"batchOnError",names:["--on-error"],type:"enum",enumValues:["stop"],usageLabel:"--on-error stop",usageDescription:"Batch: stop when a step fails"},{key:"batchMaxSteps",names:["--max-steps"],type:"int",min:1,max:1e3,usageLabel:"--max-steps <n>",usageDescription:"Batch: maximum number of allowed steps"},{key:"appsFilter",names:["--user-installed"],type:"enum",setValue:"user-installed",usageLabel:"--user-installed",usageDescription:"Apps: list user-installed apps"},{key:"appsFilter",names:["--all"],type:"enum",setValue:"all",usageLabel:"--all",usageDescription:"Apps: list all apps (include system/default apps)"},{key:"snapshotInteractiveOnly",names:["-i"],type:"boolean",usageLabel:"-i",usageDescription:"Snapshot: interactive elements only"},{key:"snapshotCompact",names:["-c"],type:"boolean",usageLabel:"-c",usageDescription:"Snapshot: compact output (drop empty structure)"},{key:"snapshotDepth",names:["--depth","-d"],type:"int",min:0,usageLabel:"--depth, -d <depth>",usageDescription:"Snapshot: limit snapshot depth"},{key:"snapshotScope",names:["--scope","-s"],type:"string",usageLabel:"--scope, -s <scope>",usageDescription:"Snapshot: scope snapshot to label/identifier"},{key:"snapshotRaw",names:["--raw"],type:"boolean",usageLabel:"--raw",usageDescription:"Snapshot: raw node output"},{key:"findFirst",names:["--first"],type:"boolean",usageLabel:"--first",usageDescription:"Find: pick the first match when ambiguous"},{key:"findLast",names:["--last"],type:"boolean",usageLabel:"--last",usageDescription:"Find: pick the last match when ambiguous"},{key:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"},{key:"overlayRefs",names:["--overlay-refs"],type:"boolean",usageLabel:"--overlay-refs",usageDescription:"Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide"},{key:"screenshotFullscreen",names:["--fullscreen"],type:"boolean",usageLabel:"--fullscreen",usageDescription:"Screenshot: capture the full screen instead of the app window"},{key:"screenshotMaxSize",names:["--max-size"],type:"int",min:1,usageLabel:"--max-size <px>",usageDescription:"Screenshot: downscale so the longest edge is at most <px>"},{key:"baseline",names:["--baseline","-b"],type:"string",usageLabel:"--baseline, -b <path>",usageDescription:"Diff screenshot: path to baseline image file"},{key:"threshold",names:["--threshold"],type:"string",usageLabel:"--threshold <0-1>",usageDescription:"Diff screenshot: color distance threshold (default 0.1)"}],eu=new Set(["json","config","remoteConfig","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","leaseBackend","sessionLock","sessionLocked","sessionLockConflicts","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),ep={boot:{helpDescription:"Ensure target device/simulator is booted and ready",summary:"Boot target device/simulator",positionalArgs:[],allowedFlags:["headless"]},open:{helpDescription:"Boot device/simulator; optionally launch app or deep link URL (macOS also supports --surface app|frontmost-app|desktop|menubar)",summary:"Open an app, deep link or URL, save replays",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","saveScript","relaunch","surface"]},connect:{usageOverride:"connect --remote-config <path> [--tenant <id>] [--run-id <id>] [--lease-backend <backend>] [--force]",helpDescription:"Connect to a remote daemon and save remote session state",summary:"Connect to remote daemon",positionalArgs:[],allowedFlags:["force","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","launchUrl"],skipCapabilityCheck:!0},disconnect:{helpDescription:"Disconnect remote daemon state, stop owned Metro companion, and release lease",summary:"Disconnect remote daemon",positionalArgs:[],allowedFlags:["shutdown"],skipCapabilityCheck:!0},connection:{usageOverride:"connection status",listUsageOverride:"connection status",helpDescription:"Inspect active remote connection state",summary:"Inspect remote connection",positionalArgs:["status"],allowedFlags:[],skipCapabilityCheck:!0},close:{helpDescription:"Close app or just end session",summary:"Close app or end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},reinstall:{helpDescription:"Uninstall + install app from binary path",summary:"Reinstall app from binary path",positionalArgs:["app","path"],allowedFlags:[]},install:{helpDescription:"Install app from binary path without uninstalling first",summary:"Install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},"install-from-source":{usageOverride:"install-from-source <url> | install-from-source --github-actions-artifact <owner/repo:artifact>",listUsageOverride:"install-from-source <url> | install-from-source --github-actions-artifact",helpDescription:"Install app from a URL or remote-resolved source",summary:"Install app from a source",positionalArgs:["url?"],allowedFlags:["header","githubActionsArtifact","installSource","retainPaths","retentionMs"]},push:{helpDescription:"Simulate push notification payload delivery",summary:"Deliver push payload",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},snapshot:{usageOverride:"snapshot [--diff] [-i] [-c] [-d <depth>] [-s <scope>] [--raw]",helpDescription:"Capture accessibility tree or diff against the previous session baseline",positionalArgs:[],allowedFlags:["snapshotDiff",...ei]},diff:{usageOverride:"diff snapshot | diff screenshot --baseline <path> [current.png] [--out <diff.png>] [--threshold <0-1>] [--overlay-refs]",helpDescription:"Diff accessibility snapshot or compare screenshots pixel-by-pixel",summary:"Diff snapshot or screenshot",positionalArgs:["kind","current?"],allowedFlags:[...ei,"baseline","threshold","out","overlayRefs"]},"ensure-simulator":{helpDescription:"Ensure an iOS simulator exists in a device set (create if missing)",summary:"Ensure iOS simulator exists",positionalArgs:[],allowedFlags:["runtime","boot","reuseExisting"],skipCapabilityCheck:!0},devices:{helpDescription:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},apps:{helpDescription:"List installed apps (includes default/system apps by default)",summary:"List installed apps",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:"all"}},appstate:{helpDescription:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},metro:{usageOverride:"metro prepare (--public-base-url <url> | --proxy-base-url <url>) [--project-root <path>] [--port <port>] [--kind auto|react-native|expo]\n agent-device metro reload [--metro-host <host>] [--metro-port <port>] [--bundle-url <url>]",listUsageOverride:"metro prepare --public-base-url <url> | --proxy-base-url <url>; metro reload",helpDescription:"Prepare a local Metro runtime or ask Metro to reload connected React Native apps",summary:"Prepare Metro or reload apps",positionalArgs:["prepare|reload"],allowedFlags:["metroHost","metroPort","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","bundleUrl"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",listUsageOverride:"clipboard read | clipboard write <text>",helpDescription:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",helpDescription:"Inspect Android keyboard visibility/type or dismiss the device keyboard",summary:"Inspect or dismiss the device keyboard",positionalArgs:["action?"],allowedFlags:[]},perf:{helpDescription:"Show session performance metrics",summary:"Show performance metrics",positionalArgs:[],allowedFlags:[]},"react-devtools":{usageOverride:"react-devtools [...args]",listUsageOverride:"react-devtools [...args]",helpDescription:"Run pinned agent-react-devtools commands for React Native component trees, props/state/hooks, and render profiling",summary:"Inspect and profile React Native component trees",positionalArgs:["args?"],allowsExtraPositionals:!0,allowedFlags:[],skipCapabilityCheck:!0},back:{usageOverride:"back [--in-app|--system]",helpDescription:"Navigate back with explicit app or system semantics",summary:"Go back",positionalArgs:[],allowedFlags:["backMode"]},home:{helpDescription:"Go to home screen (where supported)",summary:"Go home",positionalArgs:[],allowedFlags:[]},rotate:{usageOverride:"rotate <portrait|portrait-upside-down|landscape-left|landscape-right>",helpDescription:"Rotate device orientation on iOS and Android",summary:"Rotate device orientation",positionalArgs:["orientation"],allowedFlags:[]},"app-switcher":{helpDescription:"Open app switcher (where supported)",summary:"Open app switcher",positionalArgs:[],allowedFlags:[]},wait:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",helpDescription:"Wait for duration, text, ref, or selector to appear",summary:"Wait for time, text, ref, or selector",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...el]},alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",helpDescription:"Inspect or handle alert (iOS simulator and macOS desktop)",summary:"Inspect or handle iOS/macOS alerts",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",helpDescription:"Tap/click by coordinates, snapshot ref, or selector",summary:"Tap by coordinates, ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap","clickButton",...el]},get:{usageOverride:"get text|attrs <@ref|selector>",helpDescription:"Return element text/attributes by ref or selector",summary:"Get text or attrs by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...el]},replay:{helpDescription:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate","replayEnv"],skipCapabilityCheck:!0},test:{usageOverride:"test <path-or-glob>...",listUsageOverride:"test <path-or-glob>...",helpDescription:"Run one or more .ad scripts as a serial test suite",summary:"Run .ad test suites",positionalArgs:["pathOrGlob"],allowsExtraPositionals:!0,allowedFlags:["replayUpdate","replayEnv","failFast","timeoutMs","retries","artifactsDir","reportJunit"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",listUsageOverride:"batch --steps <json> | --steps-file <path>",helpDescription:"Execute multiple commands in one daemon request",summary:"Run multiple commands",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",helpDescription:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",summary:"Press by coordinates, ref, or selector",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...el]},longpress:{helpDescription:"Long press by coordinates (iOS and Android)",summary:"Long press by coordinates",positionalArgs:["x","y","durationMs?"],allowedFlags:[]},swipe:{helpDescription:"Swipe coordinates with optional repeat pattern",summary:"Swipe coordinates",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{helpDescription:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},type:{helpDescription:"Type text in focused field",positionalArgs:["text"],allowsExtraPositionals:!0,allowedFlags:["delayMs"]},fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",helpDescription:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...el,"delayMs"]},scroll:{usageOverride:"scroll <direction> [amount] [--pixels <n>]",helpDescription:"Scroll in direction (relative amount or explicit pixels)",summary:"Scroll in a direction",positionalArgs:["direction","amount?"],allowedFlags:["pixels"]},pinch:{helpDescription:"Pinch/zoom gesture (Apple simulator or macOS app session)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},screenshot:{helpDescription:"Capture screenshot (macOS app sessions default to the app window; use --fullscreen for full desktop, --max-size to downscale, or --overlay-refs to annotate the image with current refs)",positionalArgs:["path?"],allowedFlags:["out","overlayRefs","screenshotFullscreen","screenshotMaxSize"]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",helpDescription:"Trigger app-defined event hook via deep link template",summary:"Trigger app event hook",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] [--quality <5-10>] [--hide-touches] | record stop",listUsageOverride:"record start [path] | record stop",helpDescription:"Start/stop screen recording",summary:"Start or stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps","quality","hideTouches"]},trace:{usageOverride:"trace start [path] | trace stop [path]",listUsageOverride:"trace start [path] | trace stop",helpDescription:"Start/stop trace log capture",summary:"Start or stop trace capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",helpDescription:"Session app log info, start/stop streaming, diagnostics, and markers",summary:"Manage session app logs",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] [--include summary|headers|body|all] | network log [limit] [summary|headers|body|all] [--include summary|headers|body|all]",helpDescription:"Dump recent HTTP(s) traffic parsed from the session app log",summary:"Show recent HTTP traffic",positionalArgs:["dump|log","limit?","include?"],allowedFlags:["networkInclude"]},find:{usageOverride:"find <locator|text> <action> [value] [--first|--last]",helpDescription:"Find by text/label/value/role/id and run action",summary:"Find an element and act",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw","findFirst","findLast"]},is:{helpDescription:"Assert UI state (visible|hidden|exists|editable|selected|text)",summary:"Assert UI state",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...el]},settings:{usageOverride:g,listUsageOverride:"settings [area] [options]",helpDescription:"Toggle OS settings, animation scales, appearance, and app permissions (macOS supports only settings appearance <light|dark|toggle> and settings permission <grant|reset> <accessibility|screen-recording|input-monitoring>; wifi|airplane|location|animations remain unsupported on macOS; mobile permission actions use the active session app)",summary:"Change OS settings and app permissions",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",helpDescription:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},ed=new Map,em=new Map;for(let e of ec){for(let t of e.names)ed.set(t,e);let t=em.get(e.key);t?t.push(e):em.set(e.key,[e])}function ef(e){if(e)return ep[e]}function eg(){return Object.keys(ep)}function eh(e){let t=e.endsWith("?"),s=t?e.slice(0,-1):e;return t?`[${s}]`:`<${s}>`}let ey=(e=`agent-device <command> [args] [--json]
|
|
2
2
|
|
|
3
3
|
CLI to control iOS and Android devices for AI agents.
|
|
4
|
-
`,t=
|
|
4
|
+
`,t=ev("Commands:",eg().map(e=>{let t=ep[e];if(!t)throw Error(`Missing command schema for ${e}`);return{name:e,schema:t,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let s=t.positionalArgs.map(s=>{var r,o,n;let a,i,l,c;return r=e,o=t,i=(a=(n=s).endsWith("?"))?n.slice(0,-1):n,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==o.usageOverride&&o.usageOverride.startsWith(`${r} ${i}`),a?l?`[${i}]`:c?i:`[${i}]`:c?i:`<${i}>`});return[e,...s].join(" ")}(e,t)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),s=eb("Flags:",ew(eu)),r=[ev("Agent Skills:",[{label:"agent-device",description:"Canonical mobile automation flows"},{label:"react-devtools",description:"React Native component tree and render profiling"},{label:"dogfood",description:"Exploratory QA and bug hunts"}]),"See `skills/<name>/SKILL.md` in the installed package."].join("\n\n"),o=ek("Configuration:",["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."]),n=ev("Environment:",[{label:"AGENT_DEVICE_SESSION",description:"Default session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"}]),a=ek("Examples:",["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"]),`${e}
|
|
5
5
|
${t}
|
|
6
6
|
|
|
7
7
|
${s}
|
|
@@ -13,75 +13,75 @@ ${o}
|
|
|
13
13
|
${n}
|
|
14
14
|
|
|
15
15
|
${a}
|
|
16
|
-
`);function
|
|
17
|
-
(none)`;let s=Math.max(...t.map(e=>e.label.length))+2,r=[e];for(let e of t)r.push(` ${e.label.padEnd(s)}${e.description}`);return r.join("\n")}function
|
|
18
|
-
(none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let
|
|
19
|
-
`)}function
|
|
16
|
+
`);function ew(e){return ec.filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function eb(e,t){return ev(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function ev(e,t){if(0===t.length)return`${e}
|
|
17
|
+
(none)`;let s=Math.max(...t.map(e=>e.label.length))+2,r=[e];for(let e of t)r.push(` ${e.label.padEnd(s)}${e.description}`);return r.join("\n")}function ek(e,t){return 0===t.length?`${e}
|
|
18
|
+
(none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let eD=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),eI={iosSimulatorDeviceSet:["IOS_SIMULATOR_DEVICE_SET"],androidDeviceAllowlist:["ANDROID_DEVICE_ALLOWLIST"],metroBearerToken:["AGENT_DEVICE_PROXY_TOKEN"]},eA=function(){let e=new Map;for(let t of ec){let s=e.get(t.key);s?s.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 eg()){let s=ef(e);if(s)for(let r of s.allowedFlags){let s=t.get(r);s&&s.has("*")||(s?s.add(e):t.set(r,new Set([e])))}}return[...e.entries()].map(([e,s])=>({key:e,flagDefinitions:s,config:{enabled:!eD.has(e),key:e},env:{names:[D(e),...eI[e]??[]]},supportsCommand(s){let r=t.get(e);return!!r&&(!!r.has("*")||!!s&&r.has(s))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),e$=new Map(eA.map(e=>[e.key,e]));function eS(e,t){return e$.get(e)?.supportsCommand(t)??!1}function ex(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let s=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===s.type){let t=e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...s,setValue:void 0,enumValues:t}}return s}function eL(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function eR(e){return e.replace(/^-+/,"")}function eN(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?eL(e):[e,void 0];return void 0!==ed.get(t)}function eC(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}function e_(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
19
|
+
`)}function eP(e,t={}){let s=e instanceof $?A(e):e;process.stderr.write(`Error (${s.code}): ${s.message}
|
|
20
20
|
`),s.hint&&process.stderr.write(`Hint: ${s.hint}
|
|
21
21
|
`),s.diagnosticId&&process.stderr.write(`Diagnostic ID: ${s.diagnosticId}
|
|
22
22
|
`),s.logPath&&process.stderr.write(`Diagnostics Log: ${s.logPath}
|
|
23
23
|
`),t.showDetails&&s.details&&process.stderr.write(`${JSON.stringify(s.details,null,2)}
|
|
24
|
-
`)}function
|
|
25
|
-
`,{encoding:"utf8",mode:384}),u.chmodSync(e,384)}function
|
|
26
|
-
`))}function
|
|
27
|
-
Runtime: ${s.runtime}`:`${e}: ${s.device} ${s.udid}${t}`}),!0},ta=async({positionals:e,flags:t,client:s})=>{if("prepare"!==(e[0]??"").toLowerCase())throw new I("INVALID_ARGS","metro only supports prepare");if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new I("INVALID_ARGS","metro prepare requires --public-base-url <url> or --proxy-base-url <url>.");let r=await s.metro.prepare({projectRoot:t.metroProjectRoot,kind:t.metroKind,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:t.tenant&&t.runId&&t.leaseId?{tenantId:t.tenant,runId:t.runId,leaseId:t.leaseId}:void 0,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:!t.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!t.metroNoInstallDeps&&void 0,runtimeFilePath:t.metroRuntimeFile});return te(t,r,()=>JSON.stringify(r,null,2)),!0},ti=async({flags:e,client:t})=>{let s=await t.apps.list({...e7(e),appsFilter:e.appsFilter});return te(e,{apps:s},()=>s.join("\n")),!0},tl=async({positionals:e,flags:t,client:s})=>{let r=T(await tp("install",e,t,s));return tt(t,r),!0},tc=async({positionals:e,flags:t,client:s})=>{let r=T(await tp("reinstall",e,t,s));return tt(t,r),!0},tu=async({positionals:e,flags:t,client:s})=>{let r=H(await td(e,t,s));return tt(t,r),!0};async function tp(e,t,s,r){let o=t[0],n=t[1];if(!o||!n)throw new I("INVALID_ARGS",`${e} requires: ${e} <app> <path-to-app-binary>`);let a={app:o,appPath:n,...e7(s)};return"install"===e?await r.apps.install(a):await r.apps.reinstall(a)}async function td(e,t,s){let r=e[0]?.trim();if(!r)throw new I("INVALID_ARGS","install-from-source requires: install-from-source <url>");if(e.length>1)throw new I("INVALID_ARGS","install-from-source accepts exactly one positional argument: <url>");return await s.apps.installFromSource({...e7(t),retainPaths:t.retainPaths,retentionMs:t.retentionMs,source:{kind:"url",url:r,headers:function(e){if(!e||0===e.length)return;let t={};for(let s of e){let e=s.indexOf(":");if(e<=0)throw new I("INVALID_ARGS",`Invalid --header value "${s}". Expected "name:value".`);let r=s.slice(0,e).trim(),o=s.slice(e+1).trim();if(!r)throw new I("INVALID_ARGS",`Invalid --header value "${s}". Header name cannot be empty.`);t[r]=o}return t}(t.header)}})}let tm=async({positionals:e,flags:t,client:s})=>{let r=j(await s.apps.open({app:e[0],url:e[1],surface:t.surface,activity:t.activity,relaunch:t.relaunch,saveScript:t.saveScript,noRecord:t.noRecord,...e7(t)}));return tt(t,r),!0},tf=async({positionals:e,flags:t,client:s})=>{let r=O(e[0]?await s.apps.close({app:e[0],shutdown:t.shutdown}):await s.sessions.close({shutdown:t.shutdown}));return tt(t,r),!0},tg=async({flags:e,client:t})=>{var s,r,o,n;if(!e.remoteConfig)throw new I("INVALID_ARGS","connect requires --remote-config <path>.");let a=e.tenant,i=e.runId;if(!a)throw new I("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!i)throw new I("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new I("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let l=V(e.stateDir).baseDir,c=e.session?null:ez({stateDir:l}),u=e.session??c?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${p.randomBytes(3).toString("hex")}`;if(!eB({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${p.randomBytes(2).toString("hex")}`}(l),d=w({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env}),m=eH(d.resolvedPath),f=eG(e),g=c?.session===u?c:eB({stateDir:l,session:u});if(g&&(s=g,r={flags:e,session:u,remoteConfigPath:d.resolvedPath,remoteConfigHash:m,desiredLeaseBackend:e3(e),daemon:f},s.remoteConfigPath!==r.remoteConfigPath||s.remoteConfigHash!==r.remoteConfigHash||s.session!==r.session||s.tenant!==r.flags.tenant||s.runId!==r.flags.runId||void 0!==r.desiredLeaseBackend&&s.leaseBackend!==r.desiredLeaseBackend||void 0!==r.flags.platform&&s.platform!==r.flags.platform||void 0!==r.flags.target&&s.target!==r.flags.target||(o=s.daemon,n=r.daemon,(o?.baseUrl??void 0)!==(n?.baseUrl??void 0)||(o?.transport??void 0)!==(n?.transport??void 0)||(o?.serverMode??void 0)!==(n?.serverMode??void 0)))&&!e.force)throw new I("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:u,remoteConfig:g.remoteConfigPath});let h=new Date().toISOString(),y={version:1,session:u,remoteConfigPath:d.resolvedPath,remoteConfigHash:m,daemon:f,tenant:a,runId:i,leaseId:g&&!e.force?g.leaseId:void 0,leaseBackend:g&&!e.force?g.leaseBackend:e3(e),platform:e.platform??(g&&!e.force?g.platform:void 0),target:e.target??(g&&!e.force?g.target:void 0),runtime:g&&!e.force?g.runtime:void 0,metro:g&&!e.force?g.metro:void 0,connectedAt:g&&!e.force?g.connectedAt:h,updatedAt:h};eU({stateDir:l,state:y}),g&&e.force&&(await e2(g.metro),await e8(t,g));let b=function(e,t){if(!t.runtime&&(e5(e)||tb(t.remoteConfigPath)))return tw(t.remoteConfigPath)}(e,y);return te(e,tv(y,b),()=>[`Connected remote session "${u}" tenant "${a}" run "${i}" ${y.leaseId?`lease ${y.leaseId}`:"lease pending"}`,b?.message].filter(e=>!!e).join("\n")),!0},th=async({flags:e,client:t})=>{let s=e.session??"default",r=V(e.stateDir).baseDir,o=eB({stateDir:r,session:s})??(e.session?null:ez({stateDir:r}));if(!o)return te(e,{connected:!1,session:s},()=>`No remote connection for "${s}".`),!0;let n=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await e2(o.metro);let a=!1;if(o.leaseId)try{a=(await t.leases.release({tenant:o.tenant,runId:o.runId,leaseId:o.leaseId})).released}catch{}return eq({stateDir:r,session:n}),te(e,{connected:!1,session:n,released:a},()=>`Disconnected remote session "${n}".`),!0},ty=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new I("INVALID_ARGS","connection accepts only: status");let s=t.session??"default",r=V(t.stateDir).baseDir,o=eB({stateDir:r,session:s})??(t.session?null:ez({stateDir:r}));if(!o)return te(t,{connected:!1,session:s},()=>`No remote connection for "${s}".`),!0;let n=function(e){if(!e.runtime&&tb(e.remoteConfigPath))return tw(e.remoteConfigPath)}(o);return te(t,tv(o,n),()=>[`Connected remote session "${o.session}".`,`tenant=${o.tenant} runId=${o.runId} leaseId=${o.leaseId??"pending"} backend=${o.leaseBackend??"pending"}`,`remoteConfig=${o.remoteConfigPath}`,o.runtime?"metro=prepared":"metro=not-prepared",n?.message].filter(e=>!!e).join("\n")),!0};function tw(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 tb(e){try{let t=w({configPath:e,cwd:process.cwd(),env:process.env}).profile;return!!(t.metroPublicBaseUrl||t.metroProxyBaseUrl||t.metroProjectRoot||t.metroKind)}catch{return!1}}function tv(e,t){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 p.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let tk=async({flags:e,client:t})=>{let s=P(await t.capture.snapshot({...e7(e),interactiveOnly:e.snapshotInteractiveOnly,compact:e.snapshotCompact,depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw}));return te(e,s,()=>(function(e,t={}){var s,r,o;let n,a=e.nodes,i=Array.isArray(a)?a:[],l="string"==typeof e.backend?e.backend:void 0,c=t.raw||"macos-helper"===l?null:A(i),u=!!e.truncated,p="string"==typeof e.appName?e.appName:void 0,d="string"==typeof e.appBundleId?e.appBundleId:void 0,m=[];p&&m.push(`Page: ${p}`),d&&m.push(`App: ${d}`);let f=c?.nodes??i,g=t.raw||"macos-helper"===l?null:function(e,t,s,r){let o=e.visibility;if(o&&"object"==typeof o&&"boolean"==typeof o.partial&&"number"==typeof o.visibleNodeCount&&"number"==typeof o.totalNodeCount&&Array.isArray(o.reasons))return{partial:o.partial,visibleNodeCount:o.visibleNodeCount,totalNodeCount:o.totalNodeCount,reasons:o.reasons.filter(e=>"string"==typeof e)};let n=t?.hiddenCount??0,a=!!t&&t.nodes.some(e=>e.hiddenContentAbove||e.hiddenContentBelow);return n>0?{partial:!0,visibleNodeCount:s,totalNodeCount:r,reasons:["offscreen-nodes"]}:a?{partial:!0,visibleNodeCount:s,totalNodeCount:s,reasons:[]}:null}(e,c,f.length,i.length),h=g?.partial?g.totalNodeCount>g.visibleNodeCount?`Snapshot: ${g.visibleNodeCount} visible nodes (${g.totalNodeCount} total)${u?" (truncated)":""}`:`Snapshot: ${g.visibleNodeCount} visible nodes${u?" (truncated)":""}`:`Snapshot: ${i.length} nodes${u?" (truncated)":""}`,y=m.length>0?`${m.join("\n")}
|
|
28
|
-
`:"",w=(s=e,r=i,o=t,n=
|
|
24
|
+
`)}function eO(e){return`x=${e.x},y=${e.y},w=${e.width},h=${e.height}`}function eE(e){return e>0?`+${e}`:String(e)}function eM(e){let t=e.nearestText?` near ${JSON.stringify(e.nearestText)}`:"",s=e.regionIndex?` r${e.regionIndex}`:"";return`${e.likelyKind}${t}${s}`}function eF(e){return e.min===e.max?eE(e.min):`${eE(e.min)}..${eE(e.max)}`}function ej(e){let t=process.cwd(),s=i.relative(t,e);return""!==s&&(s.startsWith("..")||i.isAbsolute(s))?e:""===s?".":`.${i.sep}${s}`}function eV(e){return"number"==typeof e&&Number.isFinite(e)?e:0}function eT(){let e=process.env.FORCE_COLOR;return"string"==typeof e?"0"!==e:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY}function eB(e,t){return t?l("dim",e):e}function eU(e){let t=e.warnings;return Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.length>0):[]}function eG(e){var t;let s="scroll-area"===(t=e.type)||"list"===t||"collection"===t||"table"===t?t:null;if(!s)return[];let r=[];if(e.node.hiddenContentAbove&&r.push(`[content above ${s} hidden]`),e.node.hiddenContentBelow&&r.push(`[content below ${s} hidden]`),0===r.length)return[];let o=" ".repeat(e.depth+1);return r.map(e=>`${o}${e}`)}function eq(e){var t;let s,r=eW(e);if(!u.existsSync(r))return null;try{s=JSON.parse(u.readFileSync(r,"utf8"))}catch(t){return e0(e,t),null}return!(!(t=s)||"object"!=typeof t||Array.isArray(t))&&1===t.version&&"string"==typeof t.session&&"string"==typeof t.remoteConfigPath&&"string"==typeof t.remoteConfigHash&&(void 0===t.daemon||"object"==typeof t.daemon&&null!==t.daemon&&!Array.isArray(t.daemon))&&"string"==typeof t.tenant&&"string"==typeof t.runId&&(void 0===t.leaseId||"string"==typeof t.leaseId)&&(void 0===t.leaseBackend||"string"==typeof t.leaseBackend)&&"string"==typeof t.connectedAt&&"string"==typeof t.updatedAt?s:(e0(e),null)}function eK(e){let t=eW({stateDir:e.stateDir,session:e.state.session});u.mkdirSync(i.dirname(t),{recursive:!0}),eQ(t,e.state),eQ(eY(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 eJ(e){u.rmSync(eW(e),{force:!0});let t=eY(e.stateDir);eZ(e.stateDir)===e.session&&u.rmSync(t,{force:!0})}function ez(e){try{return p.createHash("sha256").update(u.readFileSync(e)).digest("hex")}catch(t){throw new $("INVALID_ARGS",`Remote config file not found: ${e}`,{cause:t instanceof Error?t.message:String(t)})}}function eW(e){return i.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 s=p.createHash("sha256").update(e).digest("hex").slice(0,8);return`${t}-${s}`}(e.session)}.json`)}function eY(e){return i.join(e,"remote-connections",".active-session.json")}function eX(e){let t=eZ(e.stateDir);return t?eq({stateDir:e.stateDir,session:t}):null}function eZ(e){let t=eY(e);if(u.existsSync(t))try{let e=JSON.parse(u.readFileSync(t,"utf8"));return"string"==typeof e.session?e.session:void 0}catch{return}}function eQ(e,t){u.writeFileSync(e,`${JSON.stringify(t,null,2)}
|
|
25
|
+
`,{encoding:"utf8",mode:384}),u.chmodSync(e,384)}function e0(e,t){F({level:"warn",phase:"remote_connection_state_invalid",data:{session:e.session,cause:t instanceof Error?t.message:t?String(t):void 0}}),eJ(e)}let e1=new Set(["connect","connection","close","devices","disconnect","ensure-simulator","metro","session"]),e2=new Set(["open"]);async function e8(e){let t,s,{command:r,flags:o,client:n}=e;if(!o.remoteConfig)return{flags:o,runtime:e.runtime};let a=T(o.stateDir).baseDir,i=w({configPath:o.remoteConfig,cwd:process.cwd(),env:process.env}),l={...function(e){let t={};for(let s of v){let r=e[s.key];void 0!==r&&(t[s.key]=r)}return t}(i.profile),...o,remoteConfig:i.resolvedPath},c=eq({stateDir:a,session:l.session??"default"});if(c&&c.remoteConfigPath!==i.resolvedPath)throw new $("INVALID_ARGS","A different remote connection is already active for this session. Run connect --force or disconnect before using a different --remote-config.",{session:c.session,activeRemoteConfig:c.remoteConfigPath,requestedRemoteConfig:i.resolvedPath});let u=c??function(e,t){if(!e.tenant)throw new $("INVALID_ARGS","remote command requires tenant in remote config or via --tenant <id>.");if(!e.runId)throw new $("INVALID_ARGS","remote command requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new $("INVALID_ARGS","remote command requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let s=new Date().toISOString();return{version:1,session:e.session??"default",remoteConfigPath:t,remoteConfigHash:ez(t),daemon:eH(e),tenant:e.tenant,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend??e9(e),platform:e.platform,target:e.target,connectedAt:s,updatedAt:s}}(l,i.resolvedPath),p={...l,session:u.session},d=function(e,t){if(e)return te(e,t)?e:void 0}(u.runtime,p.platform)??e.runtime,m=u,f=!c;if(g=r,!e1.has(g)){let e=u.leaseBackend??function(e,t){let s=e9(e);if(s)return s;throw new $("INVALID_ARGS",`${t} requires --platform ios|android or --lease-backend when the remote connection has not resolved a lease yet.`)}(o,r);var g,h,y,b,k,D=u,I=o,A=e;if(D.leaseBackend&&D.leaseBackend!==A)throw new $("INVALID_ARGS","Active remote connection is already bound to a different lease backend. Re-run connect --force to replace it.",{session:D.session,leaseBackend:D.leaseBackend});if(D.platform&&I.platform&&D.platform!==I.platform)throw new $("INVALID_ARGS","Active remote connection is already bound to a different platform. Re-run connect --force to replace it.",{session:D.session,platform:D.platform});if(D.target&&I.target&&D.target!==I.target)throw new $("INVALID_ARGS","Active remote connection is already bound to a different target. Re-run connect --force to replace it.",{session:D.session,target:D.target});let t=await tt(n,m,e);p.leaseId=t.leaseId,p.leaseBackend=e,p.platform=m.platform??p.platform,p.target=m.target??p.target,(m.leaseId!==t.leaseId||m.leaseBackend!==e)&&(m={...m,leaseId:t.leaseId,leaseBackend:e,platform:m.platform??o.platform,target:m.target??o.target,updatedAt:new Date().toISOString()},f=!0)}if(h=r,y=e.batchSteps,(e2.has(h)||"batch"===h&&y&&y.some(e=>{let t=e.command.trim().toLowerCase();return e2.has(t)&&void 0===e.runtime}))&&e7(p)&&(!m.leaseId&&p.leaseId&&(m={...m,leaseId:p.leaseId,leaseBackend:p.leaseBackend}),e.forceRuntimePrepare||!d||!te(d,p.platform))){if(!m.leaseId)throw new $("INVALID_ARGS",`${r} requires a resolved remote lease before Metro runtime can be prepared.`);let e=await e3(p,n,u.remoteConfigPath,u.session,{tenantId:u.tenant,runId:u.runId,leaseId:m.leaseId});d=e.runtime;let o=(b=m.metro,k=e.cleanup,b?.projectRoot!==k?.projectRoot||b?.profileKey!==k?.profileKey||b?.consumerKey!==k?.consumerKey);t=o?m.metro:void 0,s=o?e.cleanup:void 0,m={...m,runtime:e.runtime,metro:e.cleanup,updatedAt:new Date().toISOString()},f=!0}if(f)try{eK({stateDir:a,state:m})}catch(e){throw await e5(s),e}return await e5(t),{flags:{...p,session:m.session,leaseId:m.leaseId,leaseBackend:m.leaseBackend,platform:m.platform??p.platform,target:m.target??p.target},runtime:d}}async function e3(e,t,s,r,o){if(!e.metroProjectRoot&&!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)return{};if("ios"!==e.platform&&"android"!==e.platform)throw new $("INVALID_ARGS",'Deferred Metro preparation requires platform "ios" or "android".');if(!e.metroPublicBaseUrl&&!e.metroProxyBaseUrl)throw new $("INVALID_ARGS","Deferred Metro preparation requires metroPublicBaseUrl or metroProxyBaseUrl when Metro settings are provided.");let n=await t.metro.prepare({projectRoot:e.metroProjectRoot,kind:e.metroKind,publicBaseUrl:e.metroPublicBaseUrl,proxyBaseUrl:e.metroProxyBaseUrl,bearerToken:e.metroBearerToken,bridgeScope:o,launchUrl:e.launchUrl,companionProfileKey:s,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?n.iosRuntime:n.androidRuntime,cleanup:e.metroProxyBaseUrl?{projectRoot:n.projectRoot,profileKey:s,consumerKey:r}:void 0}}async function e5(e){if(e)try{await Y(e)}catch{}}async function e4(e){try{await z({projectRoot:process.cwd(),stateDir:e.stateDir,kind:"react-devtools",profileKey:e.state.remoteConfigPath,consumerKey:e.state.session})}catch{}}async function e6(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 e9(e){return e.leaseBackend?e.leaseBackend:"android"===e.platform?"android-instance":"ios"===e.platform?"ios-instance":void 0}function e7(e){return!!(e.metroPublicBaseUrl||e.metroProxyBaseUrl||e.metroProjectRoot||e.metroKind)}function te(e,t){return!e.platform||!t||"ios"!==t&&"android"!==t||e.platform===t}async function tt(e,t,s){if(t.leaseId&&t.leaseBackend===s){let r=await ts(e,t.leaseId,{tenant:t.tenant,runId:t.runId,leaseBackend:s});if(r)return r}return await e.leases.allocate({tenant:t.tenant,runId:t.runId,leaseBackend:s})}async function ts(e,t,s){try{return await e.leases.heartbeat({tenant:s.tenant,runId:s.runId,leaseId:t,leaseBackend:s.leaseBackend})}catch(e){var r;if((r=e)instanceof $&&"UNAUTHORIZED"===r.code&&(r.details?.reason==="LEASE_NOT_FOUND"||r.details?.reason==="LEASE_EXPIRED"||r.details?.reason==="LEASE_REVOKED"))return;throw e}}function tr(e){return{platform:e.platform,target:e.target,device:e.device,udid:e.udid,serial:e.serial,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet,androidDeviceAllowlist:e.androidDeviceAllowlist}}function to(e,t,s){var r;if(e.json)return void e_({success:!0,data:t});let o=s?.();o&&(r=o,process.stdout.write(r.endsWith("\n")?r:`${r}
|
|
26
|
+
`))}function tn(e,t){to(e,t,()=>R(t))}let ta=async({positionals:e,flags:t,client:s})=>{if("list"!==(e[0]??"list"))throw new $("INVALID_ARGS","session only supports list");let r={sessions:(await s.sessions.list()).map(_)};return to(t,r,()=>JSON.stringify(r,null,2)),!0},ti=async({flags:e,client:t})=>{let s=await t.devices.list(tr(e));return to(e,{devices:s.map(H)},()=>s.map(tl).join("\n")),!0};function tl(e){let t=e.kind?` ${e.kind}`:"",s=e.target?` target=${e.target}`:"",r="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${s})${r}`}let tc=async({flags:e,client:t})=>{if(!e.device)throw new $("INVALID_ARGS","ensure-simulator requires --device <name>");let s=await t.simulators.ensure({device:e.device,runtime:e.runtime,boot:e.boot,reuseExisting:e.reuseExisting,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet});return to(e,q(s),()=>{let e=s.created?"Created":"Reused",t=s.booted?" (booted)":"";return s.runtime?`${e}: ${s.device} ${s.udid}${t}
|
|
27
|
+
Runtime: ${s.runtime}`:`${e}: ${s.device} ${s.udid}${t}`}),!0},tu=async({positionals:e,flags:t,client:s})=>{let r=(e[0]??"").toLowerCase();if("reload"===r){let e=await s.metro.reload({metroHost:t.metroHost,metroPort:t.metroPort,bundleUrl:t.bundleUrl,timeoutMs:t.metroProbeTimeoutMs});return to(t,e,()=>`Reloaded React Native apps via ${e.reloadUrl}`),!0}if("prepare"!==r)throw new $("INVALID_ARGS","metro requires a subcommand: prepare or reload");if(!t.metroPublicBaseUrl&&!t.metroProxyBaseUrl)throw new $("INVALID_ARGS","metro prepare requires --public-base-url <url> or --proxy-base-url <url>.");let o=await s.metro.prepare({projectRoot:t.metroProjectRoot,kind:t.metroKind,port:t.metroPreparePort,listenHost:t.metroListenHost,statusHost:t.metroStatusHost,publicBaseUrl:t.metroPublicBaseUrl,proxyBaseUrl:t.metroProxyBaseUrl,bearerToken:t.metroBearerToken,bridgeScope:t.tenant&&t.runId&&t.leaseId?{tenantId:t.tenant,runId:t.runId,leaseId:t.leaseId}:void 0,startupTimeoutMs:t.metroStartupTimeoutMs,probeTimeoutMs:t.metroProbeTimeoutMs,reuseExisting:!t.metroNoReuseExisting&&void 0,installDependenciesIfNeeded:!t.metroNoInstallDeps&&void 0,runtimeFilePath:t.metroRuntimeFile});return to(t,o,()=>JSON.stringify(o,null,2)),!0},tp=async({flags:e,client:t})=>{let s=await t.apps.list({...tr(e),appsFilter:e.appsFilter});return to(e,{apps:s},()=>s.join("\n")),!0};function td(e,t,s,r){var o;return"number"==typeof s||"string"==typeof(o=s)&&/^\d+$/.test(o.trim())?{kind:"github-actions-artifact",owner:e,repo:t,artifactId:function(e,t){let s="number"==typeof e?e:"string"==typeof e?Number(e):NaN;if(!Number.isInteger(s))throw new $("INVALID_ARGS",`${t} must be an integer.`);return s}(s,r)}:{kind:"github-actions-artifact",owner:e,repo:t,artifactName:tf(s,r)}}function tm(e,t){let s=e.indexOf("/");if(s<=0||s===e.length-1||-1!==e.indexOf("/",s+1))throw new $("INVALID_ARGS",`${t} must use owner/repo.`);let r={owner:e.slice(0,s).trim(),repo:e.slice(s+1).trim()};if(!r.owner||!r.repo)throw new $("INVALID_ARGS",`${t} must use owner/repo.`);return r}function tf(e,t){let s="string"==typeof e&&e.trim().length>0?e.trim():void 0;if(!s)throw new $("INVALID_ARGS",`${t} must be a non-empty string.`);return s}let tg=async({positionals:e,flags:t,client:s})=>{let r=V(await tw("install",e,t,s));return tn(t,r),!0},th=async({positionals:e,flags:t,client:s})=>{let r=V(await tw("reinstall",e,t,s));return tn(t,r),!0},ty=async({positionals:e,flags:t,client:s})=>{let r=K(await tb(e,t,s));return tn(t,r),!0};async function tw(e,t,s,r){let o=t[0],n=t[1];if(!o||!n)throw new $("INVALID_ARGS",`${e} requires: ${e} <app> <path-to-app-binary>`);let a={app:o,appPath:n,...tr(s)};return"install"===e?await r.apps.install(a):await r.apps.reinstall(a)}async function tb(e,t,s){let r=function(e,t){let s=e[0]?.trim();if(e.length>1)throw new $("INVALID_ARGS","install-from-source accepts either one <url> positional or --github-actions-artifact");let r=t.githubActionsArtifact?function(e,t="--github-actions-artifact"){let s=e.indexOf(":");if(s<=0||s===e.length-1)throw new $("INVALID_ARGS",`${t} must use owner/repo:artifact, for example thymikee/RNCLI83:6635342232`);let{owner:r,repo:o}=tm(e.slice(0,s),t);return td(r,o,e.slice(s+1),`${t} artifact`)}(t.githubActionsArtifact):void 0,o=t.installSource;if(1!=+!!s+ +!!r+ +!!o)throw new $("INVALID_ARGS","install-from-source requires exactly one source: <url>, --github-actions-artifact, or config installSource");return r||o||{kind:"url",url:s,headers:function(e){if(!e||0===e.length)return;let t={};for(let s of e){let e=s.indexOf(":");if(e<=0)throw new $("INVALID_ARGS",`Invalid --header value "${s}". Expected "name:value".`);let r=s.slice(0,e).trim(),o=s.slice(e+1).trim();if(!r)throw new $("INVALID_ARGS",`Invalid --header value "${s}". Header name cannot be empty.`);t[r]=o}return t}(t.header)}}(e,t);if("url"!==r.kind&&t.header&&t.header.length>0)throw new $("INVALID_ARGS","install-from-source --header is only supported for URL sources");return await s.apps.installFromSource({...tr(t),retainPaths:t.retainPaths,retentionMs:t.retentionMs,source:r})}let tv=async({positionals:e,flags:t,client:s})=>{let r=j(await s.apps.open({app:e[0],url:e[1],surface:t.surface,activity:t.activity,relaunch:t.relaunch,saveScript:t.saveScript,noRecord:t.noRecord,...tr(t)}));return tn(t,r),!0},tk=async({positionals:e,flags:t,client:s})=>{let r=O(e[0]?await s.apps.close({app:e[0],shutdown:t.shutdown}):await s.sessions.close({shutdown:t.shutdown}));return tn(t,r),!0},tD=async({flags:e,client:t})=>{var s,r,o,n;if(!e.remoteConfig)throw new $("INVALID_ARGS","connect requires --remote-config <path>.");let a=e.tenant,i=e.runId;if(!a)throw new $("INVALID_ARGS","connect requires tenant in remote config or via --tenant <id>.");if(!i)throw new $("INVALID_ARGS","connect requires runId in remote config or via --run-id <id>.");if(!e.daemonBaseUrl)throw new $("INVALID_ARGS","connect requires daemonBaseUrl in remote config, config, env, or --daemon-base-url.");let l=T(e.stateDir).baseDir,c=e.session?null:eX({stateDir:l}),u=e.session??c?.session??function(e){for(let t=0;t<8;t+=1){let t=`adc-${p.randomBytes(3).toString("hex")}`;if(!eq({stateDir:e,session:t}))return t}return`adc-${Date.now().toString(36)}-${p.randomBytes(2).toString("hex")}`}(l),d=w({configPath:e.remoteConfig,cwd:process.cwd(),env:process.env}),m=ez(d.resolvedPath),f=eH(e),g=c?.session===u?c:eq({stateDir:l,session:u});if(g&&(s=g,r={flags:e,session:u,remoteConfigPath:d.resolvedPath,remoteConfigHash:m,desiredLeaseBackend:e9(e),daemon:f},s.remoteConfigPath!==r.remoteConfigPath||s.remoteConfigHash!==r.remoteConfigHash||s.session!==r.session||s.tenant!==r.flags.tenant||s.runId!==r.flags.runId||void 0!==r.desiredLeaseBackend&&s.leaseBackend!==r.desiredLeaseBackend||void 0!==r.flags.platform&&s.platform!==r.flags.platform||void 0!==r.flags.target&&s.target!==r.flags.target||(o=s.daemon,n=r.daemon,(o?.baseUrl??void 0)!==(n?.baseUrl??void 0)||(o?.transport??void 0)!==(n?.transport??void 0)||(o?.serverMode??void 0)!==(n?.serverMode??void 0)))&&!e.force)throw new $("INVALID_ARGS","A different remote connection is already active for this session. Re-run connect with --force to replace it.",{session:u,remoteConfig:g.remoteConfigPath});let h=new Date().toISOString(),y={version:1,session:u,remoteConfigPath:d.resolvedPath,remoteConfigHash:m,daemon:f,tenant:a,runId:i,leaseId:g&&!e.force?g.leaseId:void 0,leaseBackend:g&&!e.force?g.leaseBackend:e9(e),platform:e.platform??(g&&!e.force?g.platform:void 0),target:e.target??(g&&!e.force?g.target:void 0),runtime:g&&!e.force?g.runtime:void 0,metro:g&&!e.force?g.metro:void 0,connectedAt:g&&!e.force?g.connectedAt:h,updatedAt:h};eK({stateDir:l,state:y}),g&&e.force&&(await e5(g.metro),await e4({stateDir:l,state:g}),await e6(t,g));let b=function(e,t){if(!t.runtime&&(e7(e)||tS(t.remoteConfigPath)))return t$(t.remoteConfigPath)}(e,y);return to(e,tx(y,b),()=>[`Connected remote session "${u}" tenant "${a}" run "${i}" ${y.leaseId?`lease ${y.leaseId}`:"lease pending"}`,b?.message].filter(e=>!!e).join("\n")),!0},tI=async({flags:e,client:t})=>{let s=e.session??"default",r=T(e.stateDir).baseDir,o=eq({stateDir:r,session:s})??(e.session?null:eX({stateDir:r}));if(!o)return to(e,{connected:!1,session:s},()=>`No remote connection for "${s}".`),!0;let n=o.session;try{await t.sessions.close({shutdown:e.shutdown})}catch{}await e5(o.metro),await e4({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 eJ({stateDir:r,session:n}),to(e,{connected:!1,session:n,released:a},()=>`Disconnected remote session "${n}".`),!0},tA=async({positionals:e,flags:t})=>{if("status"!==e[0])throw new $("INVALID_ARGS","connection accepts only: status");let s=t.session??"default",r=T(t.stateDir).baseDir,o=eq({stateDir:r,session:s})??(t.session?null:eX({stateDir:r}));if(!o)return to(t,{connected:!1,session:s},()=>`No remote connection for "${s}".`),!0;let n=function(e){if(!e.runtime&&tS(e.remoteConfigPath))return t$(e.remoteConfigPath)}(o);return to(t,tx(o,n),()=>[`Connected remote session "${o.session}".`,`tenant=${o.tenant} runId=${o.runId} leaseId=${o.leaseId??"pending"} backend=${o.leaseBackend??"pending"}`,`remoteConfig=${o.remoteConfigPath}`,o.runtime?"metro=prepared":"metro=not-prepared",n?.message].filter(e=>!!e).join("\n")),!0};function t$(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=w({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){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 p.createHash("sha256").update(e).digest("hex").slice(0,12)}(e.daemon?.baseUrl),metro:e.metro?{prepared:!0,projectRoot:e.metro.projectRoot}:{prepared:!1},...t?{runtimePreparation:t}:{},connectedAt:e.connectedAt,updatedAt:e.updatedAt}}let tL=async({flags:e,client:t})=>{let s=P(await t.capture.snapshot({...tr(e),interactiveOnly:e.snapshotInteractiveOnly,compact:e.snapshotCompact,depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw}));return to(e,s,()=>(function(e,t={}){var s,r,o;let n,a=e.nodes,i=Array.isArray(a)?a:[],l="string"==typeof e.backend?e.backend:void 0,c=t.raw||"macos-helper"===l?null:S(i),u=!!e.truncated,p="string"==typeof e.appName?e.appName:void 0,d="string"==typeof e.appBundleId?e.appBundleId:void 0,m=[];p&&m.push(`Page: ${p}`),d&&m.push(`App: ${d}`);let f=c?.nodes??i,g=t.raw||"macos-helper"===l?null:function(e,t,s,r){let o=e.visibility;if(o&&"object"==typeof o&&"boolean"==typeof o.partial&&"number"==typeof o.visibleNodeCount&&"number"==typeof o.totalNodeCount&&Array.isArray(o.reasons))return{partial:o.partial,visibleNodeCount:o.visibleNodeCount,totalNodeCount:o.totalNodeCount,reasons:o.reasons.filter(e=>"string"==typeof e)};let n=t?.hiddenCount??0,a=!!t&&t.nodes.some(e=>e.hiddenContentAbove||e.hiddenContentBelow);return n>0?{partial:!0,visibleNodeCount:s,totalNodeCount:r,reasons:["offscreen-nodes"]}:a?{partial:!0,visibleNodeCount:s,totalNodeCount:s,reasons:[]}:null}(e,c,f.length,i.length),h=g?.partial?g.totalNodeCount>g.visibleNodeCount?`Snapshot: ${g.visibleNodeCount} visible nodes (${g.totalNodeCount} total)${u?" (truncated)":""}`:`Snapshot: ${g.visibleNodeCount} visible nodes${u?" (truncated)":""}`:`Snapshot: ${i.length} nodes${u?" (truncated)":""}`,y=m.length>0?`${m.join("\n")}
|
|
28
|
+
`:"",w=(s=e,r=i,o=t,n=eU(s),!o.raw&&function(e){if(e.length<20)return!1;let t=new Map;for(let s of e){let e=(s.type??"").toLowerCase(),r=L(s).trim().toLowerCase();if(!r)continue;let o=`${e}|${r}`;t.set(o,(t.get(o)??0)+1)}let s=0;for(let e of t.values())e>1&&(s+=e);return s>=8}(r)&&n.push("Warning: possible repeated nav subtree detected."),n),b=w.length>0?`${w.join("\n")}
|
|
29
29
|
`:"";if(0===i.length)return`${y}${h}
|
|
30
30
|
${b}`;if(t.raw){let e=i.map(e=>JSON.stringify(e));return`${y}${h}
|
|
31
31
|
${b}${e.join("\n")}
|
|
32
|
-
`}if(t.flatten){let e=N(f,{summarizeTextSurfaces:!0}).flatMap(e=>[x(e.node,0,!1,e.type,{summarizeTextSurfaces:!0}),...
|
|
32
|
+
`}if(t.flatten){let e=N(f,{summarizeTextSurfaces:!0}).flatMap(e=>[x(e.node,0,!1,e.type,{summarizeTextSurfaces:!0}),...eG({...e,depth:0})]),t=c&&c.summaryLines.length>0?`
|
|
33
33
|
${c.summaryLines.join("\n")}`:"";return`${y}${h}
|
|
34
34
|
${b}${e.join("\n")}${t}
|
|
35
|
-
`}let v=N(f,{summarizeTextSurfaces:!0}).flatMap(e=>[e.text,...
|
|
35
|
+
`}let v=N(f,{summarizeTextSurfaces:!0}).flatMap(e=>[e.text,...eG(e)]),k=c&&c.summaryLines.length>0?`
|
|
36
36
|
${c.summaryLines.join("\n")}`:"";return`${y}${h}
|
|
37
37
|
${b}${v.join("\n")}${k}
|
|
38
|
-
`})(s,{raw:e.snapshotRaw,flatten:e.snapshotInteractiveOnly})),!0},
|
|
38
|
+
`})(s,{raw:e.snapshotRaw,flatten:e.snapshotInteractiveOnly})),!0},tR=async({positionals:e,flags:t,client:s})=>{let r=await s.capture.screenshot({path:e[0]??t.out,overlayRefs:t.overlayRefs,maxSize:t.screenshotMaxSize,...void 0!==t.screenshotFullscreen?{fullscreen:t.screenshotFullscreen}:{}});return to(t,{path:r.path,...r.overlayRefs?{overlayRefs:r.overlayRefs}:{}},()=>r.overlayRefs?`Annotated ${r.overlayRefs.length} refs onto ${r.path}`:r.path),!0},tN=async({positionals:e,flags:t,client:s})=>{var r;if("snapshot"===e[0]){let e=await s.capture.diff({...tr(t),kind:"snapshot",out:t.out,interactiveOnly:t.snapshotInteractiveOnly,compact:t.snapshotCompact,depth:t.snapshotDepth,scope:t.snapshotScope,raw:t.snapshotRaw});return to(t,e,()=>(function(e){var t;let s=!0===e.baselineInitialized,r=e.summary??{},o=eV(r.additions),n=eV(r.removals),a=eV(r.unchanged),i=eT(),c=eU(e),u=c.length>0?`${c.join("\n")}
|
|
39
39
|
`:"";if(s)return`${u}Baseline initialized (${a} lines).
|
|
40
40
|
`;let p=(function(e){if(0===e.length)return e;let t=e.map((e,t)=>({index:t,kind:e.kind})).filter(e=>"added"===e.kind||"removed"===e.kind).map(e=>e.index);if(0===t.length)return e;let s=Array(e.length).fill(!1);for(let r of t){let t=Math.max(0,r-1),o=Math.min(e.length-1,r+1);for(let e=t;e<=o;e+=1)s[e]=!0}return e.filter((e,t)=>s[t])})(Array.isArray(e.lines)?e.lines:[]).map(e=>{let t="string"==typeof e.text?e.text:"";if("added"===e.kind){let e=t.startsWith(" ")?`+${t}`:`+ ${t}`;return i?l("green",e):e}if("removed"===e.kind){let e=t.startsWith(" ")?`-${t}`:`- ${t}`;return i?l("red",e):e}return i?l("dim",t):t}),d=p.length>0?`${p.join("\n")}
|
|
41
41
|
`:"";if(!i)return`${u}${d}${o} additions, ${n} removals, ${a} unchanged
|
|
42
42
|
`;let m=`${(t=String(o),l("green",t))} additions, ${l("red",String(n))} removals, ${l("dim",String(a))} unchanged`;return`${u}${d}${m}
|
|
43
|
-
`})(e)),!0}if("screenshot"!==e[0])return!1;let o=t.baseline;if(!o||"string"!=typeof o)throw new
|
|
44
|
-
`})(u)),!0},
|
|
45
|
-
`):
|
|
46
|
-
`}(t),"utf8")}catch(s){let t=s instanceof Error?s.message:String(s);throw new
|
|
43
|
+
`})(e)),!0}if("screenshot"!==e[0])return!1;let o=t.baseline;if(!o||"string"!=typeof o)throw new $("INVALID_ARGS","diff screenshot requires --baseline <path>");let n=X(o),a="string"==typeof t.out?X(t.out):void 0,i=e[1];if(e.length>2)throw new $("INVALID_ARGS","diff screenshot accepts at most one current screenshot path");let c=U({backend:(r=s,{platform:function(e){switch(e.platform){case"android":case"linux":case"macos":return e.platform;default:return"ios"}}(t),captureScreenshot:async(e,t,s)=>{let o=await r.capture.screenshot({path:t,session:e.session,overlayRefs:s?.overlayRefs,fullscreen:s?.fullscreen,surface:s?.surface});return{path:o.path,...o.overlayRefs?{overlayRefs:o.overlayRefs}:{}}}}),artifacts:Q(),sessions:{get:e=>({name:e}),set:()=>{}},policy:J()}),u=await c.capture.diffScreenshot({session:t.session,baseline:{kind:"path",path:n},current:i?{kind:"path",path:X(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 to(t,u,()=>(function(e){let t=eT(),s=!0===e.match,r=eV(e.differentPixels),o=eV(e.totalPixels),n=eV(e.mismatchPercentage),a=e.diffPath,i=e.dimensionMismatch,c=[];if(s){let e=t?l("green","✓"):"✓";c.push(`${e} Screenshots match.`)}else if(i){let e=t?l("red","✗"):"✗",s=i.expected,r=i.actual;c.push(`${e} Screenshots have different dimensions: expected ${s?.width}x${s?.height}, got ${r?.width}x${r?.height}`)}else{let e=t?l("red","✗"):"✗",s=0===n&&r>0?"<0.01":String(n),o=`${s}% pixels differ`;c.push(`${e} ${t?l("red",o):o}`)}if(a&&!s){let e=ej(a),s=t?l("dim","Diff image:"):"Diff image:",r=t?l("green",e):e;c.push(` ${s} ${r}`)}if(e.currentOverlayPath&&!s){let s=ej(e.currentOverlayPath),r=t?l("dim","Current overlay:"):"Current overlay:",o=t?l("green",s):s,n=eV(e.currentOverlayRefCount),a=n>0?` (${n} refs)`:"";c.push(` ${r} ${o}${a}`)}if(!s&&!i){let e=t?l("red",String(r)):String(r);c.push(` ${e} different / ${o} total pixels`)}let u=s||i?[]:function(e){let t=[];for(let s of(e.ocr?.movementClusters??[]).slice(0,2))t.push(`text movement cluster: ${function(e){let t=e.slice(0,4).map(e=>JSON.stringify(e)),s=e.length>t.length?` +${e.length-t.length} more`:"";return`${t.join(", ")}${s}`}(s.texts)} dx=${eF(s.xRange)}px dy=${eF(s.yRange)}px`);let s=(e.nonTextDeltas??[]).filter(e=>["icon","toggle","chevron"].includes(e.likelyKind)).slice(0,3);s.length>0&&t.push(`non-text controls: ${s.map(eM).join("; ")}`);let r=(e.nonTextDeltas??[]).filter(e=>"separator"===e.likelyKind).slice(0,2);return r.length>0&&t.push(`non-text boundaries: ${r.map(eM).join("; ")}`),t.slice(0,6)}(e);if(u.length>0)for(let e of(c.push(` ${eB("Hints:",t)}`),u))c.push(` - ${e}`);let p=Array.isArray(e.regions)?e.regions:[];if(!s&&!i&&p.length>0)for(let e of(c.push(` ${eB("Changed regions:",t)}`),p.slice(0,5))){let t=0===e.shareOfDiffPercentage&&e.differentPixels>0?"<0.01":String(e.shareOfDiffPercentage),s=e.rect;c.push(` ${e.index}. ${e.location} x=${s.x} y=${s.y} ${s.width}x${s.height}, ${t}% of diff, change=${e.dominantChange}`);let r=function(e){let t=[e.size?`size=${e.size}`:null,e.shape?`shape=${e.shape}`:null,"number"==typeof e.densityPercentage?`density=${e.densityPercentage}%`:null,e.averageBaselineColorHex&&e.averageCurrentColorHex?`avgColor=${e.averageBaselineColorHex}->${e.averageCurrentColorHex}`:null,"number"==typeof e.baselineLuminance&&"number"==typeof e.currentLuminance?`luminance=${e.baselineLuminance}->${e.currentLuminance}`:null].filter(e=>null!==e);return t.length>0?t.join(" "):null}(e);r&&c.push(` ${r}`);let o=e.currentOverlayMatches?.[0];if(o){let e=o.label?` "${o.label}"`:"";c.push(` overlaps @${o.ref}${e}, ${o.regionCoveragePercentage}% of region`)}}let d=e.ocr?.matches??[];if(!s&&!i&&d.length>0){let s=d.slice(0,8);for(let[r,o]of(c.push(` ${eB(`OCR text deltas (${e.ocr?.provider}; baselineBlocks=${e.ocr?.baselineBlocks} currentBlocks=${e.ocr?.currentBlocks}; showing ${s.length}/${d.length}; px):`,t)}`),c.push(` ${eB("item | text | movePx | sizeDeltaPx | bboxBaseline | bboxCurrent | confidence | issueHint",t)}`),s.entries())){let e=o.delta;c.push(` ${r+1} | ${JSON.stringify(o.text)} | ${eE(e.x)},${eE(e.y)} | ${eE(e.width)},${eE(e.height)} | ${eO(o.baselineRect)} | ${eO(o.currentRect)} | ${o.confidence} | ${o.possibleTextMetricMismatch?"ocr-bbox-size-change":"-"}`)}}let m=e.nonTextDeltas??[];if(!s&&!i&&m.length>0){let e=m.slice(0,8);for(let s of(c.push(` ${eB(`Non-text visual deltas (showing ${e.length}/${m.length}; px):`,t)}`),c.push(` ${eB("item | region | slot | kind | bboxCurrent | nearestText",t)}`),e))c.push(` ${s.index} | ${s.regionIndex?`r${s.regionIndex}`:"-"} | ${s.slot} | ${s.likelyKind} | ${eO(s.rect)} | ${s.nearestText?JSON.stringify(s.nearestText):"-"}`)}return`${c.join("\n")}
|
|
44
|
+
`})(u)),!0},tC={[et.wait]:async({positionals:e,flags:t,client:s})=>(tn(t,await s.command.wait(function(e,t){let s=y(e);if(!s)throw new $("INVALID_ARGS","wait requires <ms>, text <text>, @ref, or <selector> [timeoutMs].");let r={...tr(t),depth:t.snapshotDepth,scope:t.snapshotScope,raw:t.snapshotRaw};if("sleep"===s.kind)return{...r,durationMs:s.durationMs};if("text"===s.kind){if(!s.text)throw new $("INVALID_ARGS","wait requires text.");return{...r,text:s.text,...t_(s.timeoutMs)}}return"ref"===s.kind?{...r,ref:s.rawRef,...t_(s.timeoutMs)}:{...r,selector:s.selectorExpression,...t_(s.timeoutMs)}}(e,t))),!0),[et.alert]:async({positionals:e,flags:t,client:s})=>(tn(t,await s.command.alert(function(e,t){if(e.length>2)throw new $("INVALID_ARGS","alert accepts at most action and timeout arguments.");let s=function(e){let t=e?.toLowerCase();if(void 0===t||"get"===t||"accept"===t||"dismiss"===t||"wait"===t)return t;throw new $("INVALID_ARGS","alert action must be get, accept, dismiss, or wait.")}(e[0]),r=function(e,t){if(void 0===e)return;let s=Number(e);if(Number.isFinite(s))return s;throw new $("INVALID_ARGS",`${t} must be a finite number.`)}(e[1],"alert timeout");return{...tr(t),...s?{action:s}:{},...void 0!==r?{timeoutMs:r}:{}}}(e,t))),!0),[et.appState]:async({flags:e,client:t})=>{let s=await t.command.appState(tr(e));return to(e,s,()=>(function(e){if("ios"===e.platform){let t=[`Foreground app: ${e.appName??e.appBundleId??"unknown"}`];return e.appBundleId&&t.push(`Bundle: ${e.appBundleId}`),e.source&&t.push(`Source: ${e.source}`),t.join("\n")}if("android"===e.platform){let t=[`Foreground app: ${e.package??"unknown"}`];return e.activity&&t.push(`Activity: ${e.activity}`),t.join("\n")}return null})(s)),!0},[et.back]:async({flags:e,client:t})=>(tn(e,await t.command.back({...tr(e),mode:e.backMode})),!0),[et.home]:async({flags:e,client:t})=>(tn(e,await t.command.home(tr(e))),!0),[et.rotate]:async({positionals:e,flags:t,client:s})=>(tn(t,await s.command.rotate(function(e,t){if(e.length>1)throw new $("INVALID_ARGS","rotate accepts exactly one orientation argument.");return{...tr(t),orientation:f(e[0])}}(e,t))),!0),[et.appSwitcher]:async({flags:e,client:t})=>(tn(e,await t.command.appSwitcher(tr(e))),!0),[et.keyboard]:async({positionals:e,flags:t,client:s})=>(tn(t,await s.command.keyboard(function(e,t){if(e.length>1)throw new $("INVALID_ARGS","keyboard accepts at most one action argument.");let s=function(e){let t=e?.toLowerCase();if("get"===t)return"status";if(void 0===t||"status"===t||"dismiss"===t)return t;throw new $("INVALID_ARGS","keyboard action must be status, get, or dismiss.")}(e[0]);return{...tr(t),...s?{action:s}:{}}}(e,t))),!0),[et.clipboard]:async({positionals:e,flags:t,client:s})=>{var r,o;return r=t,o=await s.command.clipboard(function(e,t){let s=e[0]?.toLowerCase();if("read"!==s&&"write"!==s)throw new $("INVALID_ARGS","clipboard requires a subcommand: read or write.");let r=tr(t);if("read"===s){if(1!==e.length)throw new $("INVALID_ARGS","clipboard read does not accept additional arguments.");return{...r,action:s}}if(e.length<2)throw new $("INVALID_ARGS","clipboard write requires text.");return{...r,action:s,text:e.slice(1).join(" ")}}(e,t)),r.json?to(r,o):"read"===o.action?process.stdout.write(`${o.text}
|
|
45
|
+
`):tn(r,o),!0}};function t_(e){return null===e?{}:{timeoutMs:e}}function tP(e){let{suite:t,json:s,verbose:r,reportJunit:o}=e;return(o&&function(e,t){let s=i.dirname(e);try{u.mkdirSync(s,{recursive:!0}),u.writeFileSync(e,function(e){let t=['<?xml version="1.0" encoding="UTF-8"?>',"<testsuites>",` <testsuite name="agent-device replay suite" tests="${e.total}" failures="${e.failed}" skipped="${e.skipped}" time="${tM(e.durationMs)}">`];for(let s of e.tests)t.push(...function(e){let t=tF(i.basename(e.file)),s=tF("."===i.dirname(e.file)?e.file:i.dirname(e.file)),r=tF(e.file),o=tM(e.durationMs),n=[` <testcase classname="${s}" name="${t}" file="${r}" time="${o}">`];"failed"===e.status?n.push(` <failure message="${tF(e.error.message)}">${tF(function(e){let t=[e.error.message];e.error.hint&&t.push(`hint: ${e.error.hint}`),e.error.diagnosticId&&t.push(`diagnosticId: ${e.error.diagnosticId}`),e.error.logPath&&t.push(`logPath: ${e.error.logPath}`),e.artifactsDir&&t.push(`artifactsDir: ${e.artifactsDir}`);let s=e.error.details?JSON.stringify(e.error.details,null,2):void 0;return s&&t.push(`details: ${s}`),t.join("\n")}(e))}</failure>`):"skipped"===e.status&&n.push(` <skipped message="${tF(e.message)}" />`);let a=function(e){let t=[`status: ${e.status}`,`durationMs: ${e.durationMs}`];return"attempts"in e&&t.push(`attempts: ${e.attempts}`),"session"in e&&t.push(`session: ${e.session}`),"replayed"in e&&t.push(`replayed: ${e.replayed}`),"healed"in e&&t.push(`healed: ${e.healed}`),"artifactsDir"in e&&e.artifactsDir&&t.push(`artifactsDir: ${e.artifactsDir}`),"passed"===e.status&&e.attempts>1&&t.push("flaky: true"),t.join("\n")}(e);return a&&n.push(` <system-out>${tF(a)}</system-out>`),n.push(" </testcase>"),n}(s));return t.push(" </testsuite>"),t.push("</testsuites>"),`${t.join("\n")}
|
|
46
|
+
`}(t),"utf8")}catch(s){let t=s instanceof Error?s.message:String(s);throw new $("COMMAND_FAILED",`Failed to write JUnit report to ${e}: ${t}`)}}(o,t),s)?(e_({success:!0,data:t}),function(e){return+(e.failed>0)}(t)):function(e,t={}){let s=e.tests.filter(tE);if(t.verbose)for(let t of e.tests)!function(e){if("failed"===e.status)return tO(e);let t="passed"===e.status?tE(e)?"FLAKY":"PASS":"skipped"===e.status?"SKIP":"INFO",s="attempts"in e&&e.attempts>1?` after ${e.attempts} attempts`:"",r=e.durationMs>0?` (${e.durationMs}ms)`:"";process.stdout.write(`${t} ${e.file}${s}${r}
|
|
47
47
|
`),"skipped"===e.status&&process.stdout.write(` ${e.message??"skipped"}
|
|
48
|
-
`)}(t);else{for(let t of e.failures)
|
|
48
|
+
`)}(t);else{for(let t of e.failures)tO(t);for(let e of s)!function(e){let t=e.durationMs>0?` (${e.durationMs}ms)`:"";process.stdout.write(`FLAKY ${e.file} after ${e.attempts} attempts${t}
|
|
49
49
|
`)}(e)}let r="number"==typeof e.durationMs?e.durationMs:void 0,o=s.length>0?`, ${s.length} flaky`:"";return process.stdout.write(`Test summary: ${e.passed} passed, ${e.failed} failed${o}${void 0!==r?` in ${r}ms`:""}
|
|
50
|
-
`),function(e){return+(e.failed>0)}(e)}(t,{verbose:r})}function
|
|
50
|
+
`),function(e){return+(e.failed>0)}(e)}(t,{verbose:r})}function tO(e){let t=e.attempts>1?` after ${e.attempts} attempts`:"",s=e.durationMs>0?` (${e.durationMs}ms)`:"";process.stdout.write(`FAIL ${e.file}${t}${s}
|
|
51
51
|
`),process.stdout.write(` ${e.error?.message??"Unknown test failure"}
|
|
52
52
|
`),e.error?.hint&&process.stdout.write(` hint: ${e.error.hint}
|
|
53
53
|
`),e.artifactsDir&&process.stdout.write(` artifacts: ${e.artifactsDir}
|
|
54
54
|
`),e.error?.logPath&&process.stdout.write(` log: ${e.error.logPath}
|
|
55
55
|
`),e.error?.diagnosticId&&process.stdout.write(` diagnostic: ${e.error.diagnosticId}
|
|
56
|
-
`)}function
|
|
56
|
+
`)}function tE(e){return"passed"===e.status&&e.attempts>1}function tM(e){return(Math.max(0,e)/1e3).toFixed(3)}function tF(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}let tj={[et.boot]:tV(et.boot,({client:e,flags:t})=>e.devices.boot({...tr(t),headless:t.headless})),[et.push]:tV(et.push,({client:e,positionals:t,flags:s})=>e.apps.push({...tr(s),app:tG(t[0],"push requires bundleOrPackage"),payload:tG(t[1],"push requires payloadOrJson")})),[et.perf]:tV(et.perf,({client:e,flags:t})=>e.observability.perf(tr(t))),[et.click]:tV(et.click,({client:e,positionals:t,flags:s})=>e.interactions.click({...tB(t),...tT(s),...tr(s),count:s.count,intervalMs:s.intervalMs,holdMs:s.holdMs,jitterPx:s.jitterPx,doubleTap:s.doubleTap,button:s.clickButton})),[et.get]:tV(et.get,({client:e,positionals:t,flags:s})=>e.interactions.get({...function(e){if(e[0]?.startsWith("@"))return{ref:e[0],label:e.slice(1).join(" ")||void 0};let t=e.join(" ").trim();if(!t)throw new $("INVALID_ARGS","get requires @ref or selector expression");return{selector:t}}(t.slice(1)),...tT(s),...tr(s),format:function(e){if("text"===e||"attrs"===e)return e;throw new $("INVALID_ARGS","get only supports text or attrs")}(t[0])})),[et.replay]:tV(et.replay,({client:e,positionals:t,flags:s})=>e.replay.run({...tr(s),path:tG(t[0],"replay requires path"),update:s.replayUpdate,env:s.replayEnv})),[et.test]:tV(et.test,({client:e,positionals:t,flags:s})=>(({json:s.json}).json||process.stderr.write("Running replay suite...\n"),e.replay.test({...tr(s),paths:t,update:s.replayUpdate,env:s.replayEnv,failFast:s.failFast,timeoutMs:s.timeoutMs,retries:s.retries,artifactsDir:s.artifactsDir,reportJunit:s.reportJunit}))),[et.batch]:tV(et.batch,({client:e,flags:t})=>e.batch.run({...tr(t),steps:t.batchSteps??[],onError:t.batchOnError,maxSteps:t.batchMaxSteps,out:t.out})),[et.press]:tV(et.press,({client:e,positionals:t,flags:s})=>e.interactions.press({...tB(t),...tT(s),...tr(s),count:s.count,intervalMs:s.intervalMs,holdMs:s.holdMs,jitterPx:s.jitterPx,doubleTap:s.doubleTap})),[et.longPress]:tV(et.longPress,({client:e,positionals:t,flags:s})=>e.interactions.longPress({...tr(s),x:Number(t[0]),y:Number(t[1]),durationMs:tq(t[2])})),[et.swipe]:tV(et.swipe,({client:e,positionals:t,flags:s})=>e.interactions.swipe({...tr(s),from:{x:Number(t[0]),y:Number(t[1])},to:{x:Number(t[2]),y:Number(t[3])},durationMs:tq(t[4]),count:s.count,pauseMs:s.pauseMs,pattern:s.pattern})),[et.focus]:tV(et.focus,({client:e,positionals:t,flags:s})=>e.interactions.focus({...tr(s),x:Number(t[0]),y:Number(t[1])})),[et.type]:tV(et.type,({client:e,positionals:t,flags:s})=>e.interactions.type({...tr(s),text:t.join(" "),delayMs:s.delayMs})),[et.fill]:tV(et.fill,({client:e,positionals:t,flags:s})=>e.interactions.fill({...function(e){if(e[0]?.startsWith("@")){let t=e.length>=3?e.slice(2).join(" "):e.slice(1).join(" ");return{ref:e[0],label:e.length>=3?e[1]:void 0,text:t}}let t=er(e,{preferTrailingValue:!0});return t?{selector:t.selectorExpression,text:t.rest.join(" ")}:{x:Number(e[0]),y:Number(e[1]),text:e.slice(2).join(" ")}}(t),...tT(s),...tr(s),delayMs:s.delayMs})),[et.scroll]:tV(et.scroll,({client:e,positionals:t,flags:s})=>e.interactions.scroll({...tr(s),direction:function(e){if("up"===e||"down"===e||"left"===e||"right"===e)return e;throw new $("INVALID_ARGS",`Unknown direction: ${String(e)}`)}(t[0]),amount:tq(t[1]),pixels:s.pixels})),[et.pinch]:tV(et.pinch,({client:e,positionals:t,flags:s})=>e.interactions.pinch({...tr(s),scale:Number(t[0]),x:tq(t[1]),y:tq(t[2])})),[et.triggerAppEvent]:tV(et.triggerAppEvent,({client:e,positionals:t,flags:s})=>e.apps.triggerEvent({...tr(s),event:tG(t[0],"trigger-app-event requires event"),payload:t[1]?function(e,t){try{let t=JSON.parse(e);if(t&&"object"==typeof t&&!Array.isArray(t))return t}catch{}throw new $("INVALID_ARGS",`${t} must be a JSON object`)}(t[1],"trigger-app-event payload"):void 0})),[et.record]:tV(et.record,({client:e,positionals:t,flags:s})=>e.recording.record({...tr(s),action:tU(t[0],"record"),path:t[1],fps:s.fps,quality:s.quality,hideTouches:s.hideTouches})),[et.trace]:tV(et.trace,({client:e,positionals:t,flags:s})=>e.recording.trace({...tr(s),action:tU(t[0],"trace"),path:t[1]})),[et.logs]:tV(et.logs,({client:e,positionals:t,flags:s})=>e.observability.logs({...tr(s),action:function(e){if(void 0!==e){if("path"===e||"start"===e||"stop"===e||"doctor"===e||"mark"===e||"clear"===e)return e;throw new $("INVALID_ARGS","logs requires path, start, stop, doctor, mark, or clear")}}(t[0]),message:t.slice(1).join(" ")||void 0,restart:s.restart})),[et.network]:tV(et.network,({client:e,positionals:t,flags:s})=>e.observability.network({...tr(s),action:function(e){if(void 0!==e){if("dump"===e||"log"===e)return e;throw new $("INVALID_ARGS","network requires dump or log")}}(t[0]),limit:tq(t[1]),include:s.networkInclude??function(e){if(void 0!==e){if("summary"===e||"headers"===e||"body"===e||"all"===e)return e;throw new $("INVALID_ARGS","network include mode must be summary, headers, body, or all")}}(t[2])})),[et.find]:tV(et.find,({client:e,positionals:t,flags:s})=>{var r;return e.interactions.find({...function(e){let t=function(e){if("text"===e||"label"===e||"value"===e||"role"===e||"id"===e)return e}(e[0]),s=void 0!==t,r=s?e[1]:e[0],o=s?2:1,n=e[o];if(void 0===n)return{locator:t,query:tG(r,"find requires query")};if("get"===n){let s=e[o+1];if("text"===s)return{locator:t,query:tG(r,"find requires query"),action:"getText"};if("attrs"===s)return{locator:t,query:tG(r,"find requires query"),action:"getAttrs"};throw new $("INVALID_ARGS","find get only supports text or attrs")}if("wait"===n)return{locator:t,query:tG(r,"find requires query"),action:"wait",timeoutMs:tq(e[o+1])};if("fill"===n||"type"===n)return{locator:t,query:tG(r,"find requires query"),action:n,value:e.slice(o+1).join(" ")};if("click"===n||"focus"===n||"exists"===n)return{locator:t,query:tG(r,"find requires query"),action:n};throw new $("INVALID_ARGS",`Unsupported find action: ${n}`)}(t),...{depth:(r=s).snapshotDepth,raw:r.snapshotRaw},...tr(s),first:s.findFirst,last:s.findLast})}),[et.is]:tV(et.is,({client:e,positionals:t,flags:s})=>e.interactions.is({...function(e){let t=e[0],s=er(e.slice(1),{preferTrailingValue:"text"===t});if(!s)throw new $("INVALID_ARGS","is requires a selector expression");if("text"===t)return{predicate:t,selector:s.selectorExpression,value:s.rest.join(" ")};if("visible"===t||"hidden"===t||"exists"===t||"editable"===t||"selected"===t)return{predicate:t,selector:s.selectorExpression};throw new $("INVALID_ARGS","is requires predicate: visible|hidden|exists|editable|selected|text")}(t),...tT(s),...tr(s)})),[et.settings]:tV(et.settings,({client:e,positionals:t,flags:s})=>e.settings.update(function(e,t){let s=tr(t),r=e[0],o=e[1];if(("wifi"===r||"airplane"===r||"location"===r||"animations"===r)&&("on"===o||"off"===o)||"appearance"===r&&("light"===o||"dark"===o||"toggle"===o)||("faceid"===r||"touchid"===r)&&("match"===o||"nonmatch"===o||"enroll"===o||"unenroll"===o)||"fingerprint"===r&&("match"===o||"nonmatch"===o))return{...s,setting:r,state:o};if("permission"===r&&("grant"===o||"deny"===o||"reset"===o))return{...s,setting:r,state:o,permission:function(e){switch(e){case"camera":case"microphone":case"photos":case"contacts":case"contacts-limited":case"notifications":case"calendar":case"location":case"location-always":case"media-library":case"motion":case"reminders":case"siri":case"accessibility":case"screen-recording":case"input-monitoring":return e;default:throw new $("INVALID_ARGS","settings permission requires a permission target.")}}(e[2]),mode:function(e){if(void 0===e||"full"===e||"limited"===e)return e;throw new $("INVALID_ARGS","settings permission mode must be full or limited.")}(e[3])};throw new $("INVALID_ARGS","Invalid settings arguments.")}(t,s)))};function tV(e,t){return async({positionals:s,flags:r,client:o})=>{let n=await t({client:o,positionals:s,flags:r}),a=function(e,t,s,r){if(s.json)return e===et.test?tP({suite:r,json:!0,reportJunit:s.reportJunit}):(e_({success:!0,data:r}),0);if(e===et.test)return tP({suite:r,verbose:s.verbose,reportJunit:s.reportJunit});if(e===et.batch)return!function(e){let t="number"==typeof e.total?e.total:0,s="number"==typeof e.executed?e.executed:0,r="number"==typeof e.totalDurationMs?e.totalDurationMs:void 0;for(let n of(process.stdout.write(`Batch completed: ${s}/${t} steps${void 0!==r?` in ${r}ms`:""}
|
|
57
57
|
`),Array.isArray(e.results)?e.results:[])){var o;if(!n||"object"!=typeof n)continue;let e="number"==typeof n.step?n.step:void 0,t="string"==typeof n.command?n.command:"step",s=!1!==n.ok,r="number"==typeof n.durationMs?n.durationMs:void 0,a=n.data&&"object"==typeof n.data?n.data:void 0,i=n.error&&"object"==typeof n.error?n.error:void 0,l=s?R(a)??t:(o=i,("string"==typeof o?.message&&o.message.length>0?o.message:null)??t),c=void 0!==e?`${e}. `:"- ",u=void 0!==r?` (${r}ms)`:"";process.stdout.write(`${c}${s?"OK":"FAILED"} ${l}${u}
|
|
58
|
-
`)}}(r),0;if(e===
|
|
58
|
+
`)}}(r),0;if(e===et.get){let e=t[0];if("text"===e)return process.stdout.write(`${"string"==typeof r.text?r.text:""}
|
|
59
59
|
`),0;if("attrs"===e)return process.stdout.write(`${JSON.stringify(r.node??{},null,2)}
|
|
60
|
-
`),0}if(e===
|
|
60
|
+
`),0}if(e===et.find){if("string"==typeof r.text)return process.stdout.write(`${r.text}
|
|
61
61
|
`),0;if("boolean"==typeof r.found)return process.stdout.write(`Found: ${r.found}
|
|
62
62
|
`),0;if(r.node)return process.stdout.write(`${JSON.stringify(r.node,null,2)}
|
|
63
|
-
`),0}if(e===
|
|
64
|
-
`),0;if(e===
|
|
65
|
-
`),0}if(e===
|
|
66
|
-
`),0}if(e===
|
|
63
|
+
`),0}if(e===et.is)return process.stdout.write(`Passed: is ${r.predicate??"assertion"}
|
|
64
|
+
`),0;if(e===et.boot){let e=r.platform??"unknown",t=r.device??r.id??"unknown";return process.stdout.write(`Boot ready: ${t} (${e})
|
|
65
|
+
`),0}if(e===et.record){let e="string"==typeof r.outPath?r.outPath:"";return e&&process.stdout.write(`${e}
|
|
66
|
+
`),0}if(e===et.logs)return function(e,t){let s="string"==typeof e.path?e.path:"";if(!s)return;process.stdout.write(`${s}
|
|
67
67
|
`);let r=["active","state","backend","sizeBytes"].map(t=>void 0!==e[t]&&null!==e[t]?`${t}=${e[t]}`:"").filter(Boolean).join(" ");r&&!t.json&&process.stderr.write(`${r}
|
|
68
68
|
`);let o=["started","stopped","marked","cleared","restarted","removedRotatedFiles"].map(t=>{let s=e[t];return!0===s?`${t}=true`:"number"==typeof s?`${t}=${s}`:""}).filter(Boolean).join(" ");if(o&&!t.json&&process.stderr.write(`${o}
|
|
69
69
|
`),e.hint&&!t.json&&process.stderr.write(`${e.hint}
|
|
70
70
|
`),Array.isArray(e.notes)&&!t.json)for(let t of e.notes)"string"==typeof t&&t.length>0&&process.stderr.write(`${t}
|
|
71
|
-
`)}(r,s),0;if(e===
|
|
71
|
+
`)}(r,s),0;if(e===et.network)return function(e){let t="string"==typeof e.path?e.path:"";t&&process.stdout.write(`${t}
|
|
72
72
|
`);let s=Array.isArray(e.entries)?e.entries:[];if(0===s.length)process.stdout.write("No recent HTTP(s) entries found.\n");else for(let e of s){let t="string"==typeof e.method?e.method:"HTTP",s="string"==typeof e.url?e.url:"<unknown-url>",r="number"==typeof e.status?` status=${e.status}`:"",o="string"==typeof e.timestamp?`${e.timestamp} `:"",n="number"==typeof e.durationMs?` durationMs=${e.durationMs}`:"";process.stdout.write(`${o}${t} ${s}${r}${n}
|
|
73
73
|
`),"string"==typeof e.headers&&process.stdout.write(` headers: ${e.headers}
|
|
74
74
|
`),"string"==typeof e.requestBody&&process.stdout.write(` request: ${e.requestBody}
|
|
75
75
|
`),"string"==typeof e.responseBody&&process.stdout.write(` response: ${e.responseBody}
|
|
76
76
|
`)}let r=["active","state","backend","include","scannedLines","matchedLines"].map(t=>void 0!==e[t]&&null!==e[t]?`${t}=${e[t]}`:"").filter(Boolean).join(" ");if(r&&process.stderr.write(`${r}
|
|
77
77
|
`),Array.isArray(e.notes))for(let t of e.notes)"string"==typeof t&&t.length>0&&process.stderr.write(`${t}
|
|
78
|
-
`)}(r),0;if(e===
|
|
79
|
-
`),0}if(e===
|
|
78
|
+
`)}(r),0;if(e===et.click||e===et.press){let e=r.ref??"",t=r.x,s=r.y;if(e&&"number"==typeof t&&"number"==typeof s)return process.stdout.write(`Tapped @${e} (${t}, ${s})
|
|
79
|
+
`),0}if(e===et.perf)return process.stdout.write(`${JSON.stringify(r,null,2)}
|
|
80
80
|
`),0;let o=R(r);return o&&process.stdout.write(`${o}
|
|
81
|
-
`),0}(e,s,r,n);return 0!==a&&process.exit(a),!0}}function tP(e){return{depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw}}function tO(e){if(e[0]?.startsWith("@"))return{ref:e[0],label:e.slice(1).join(" ")||void 0};let t=et(e);return t?{selector:t.selectorExpression}:{x:Number(e[0]),y:Number(e[1])}}function tM(e,t){if("start"===e||"stop"===e)return e;throw new I("INVALID_ARGS",`${t} requires start|stop`)}function tE(e,t){if(void 0===e||""===e)throw new I("INVALID_ARGS",t);return e}function tF(e){return void 0===e?void 0:Number(e)}let tj={...{session:ts,[Q.devices]:tr,[Q.apps]:ti,"ensure-simulator":tn,metro:ta,install:tl,reinstall:tc,"install-from-source":tu,connect:tg,disconnect:th,connection:ty,open:tm,close:tf,[Q.snapshot]:tk,[Q.screenshot]:tD,[Q.diff]:t$},...tS,...tC};async function tT(e){let t=tj[e.command];return!!t&&await t(e)}function tV(e,t={}){let s=tB(t),r={...e};return s.defaultPlatform&&void 0===r.platform&&(r.platform=s.defaultPlatform),r}function tB(e){var t,s,r,o;let n,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 I("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:(s=e.policyOverrides,r=a,o=l,(n=s?.sessionLock??s?.sessionLockConflicts??tU(r.AGENT_DEVICE_SESSION_LOCK)??tU(r.AGENT_DEVICE_SESSION_LOCK_CONFLICTS))||(s?.sessionLocked===!0||d(r.AGENT_DEVICE_SESSION_LOCKED)||o?"reject":void 0))}}function tU(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("reject"===t||"strip"===t)return t;throw new I("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}let tG=v.map(e=>e.key),tq={sendToDaemon:ee},tH=new Set(["launchUrl","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),tK=new Set(["connect","connection","close","devices","disconnect","ensure-simulator","metro","session"]);async function tJ(e,t=tq){let s=C(),r=M(),o=e.includes("--debug")||e.includes("--verbose")||e.includes("-v"),n=e.includes("--json"),a=function(e){for(let t=0;t<e.length;t+=1){let s=e[t];if(s.startsWith("--session=")){let e=s.slice(10).trim();return e.length>0?e:null}if("--session"===s){let s=e[t+1]?.trim();if(s&&!s.startsWith("-"))return s;break}}return null}(e)??process.env.AGENT_DEVICE_SESSION??"default";await B({session:a,requestId:s,command:e[0],debug:o},async()=>{var a,l,c,p,d,m,f,g,y,v,D,A,x,L,R,N;let C,_,P,O,M,j,T;try{let t,s,r,o,n,h,b,$;a={cwd:process.cwd(),env:process.env},t=function(e){let t={json:!1,help:!1,version:!1},s=null,r=[],o=[],n=!0;for(let a=0;a<e.length;a+=1){let i=e[a];if(n&&"--"===i){n=!1;continue}if(!n){s?r.push(i):s=eL(i);continue}let l=i.startsWith("--"),c=i.startsWith("-")&&i.length>1;if(!l&&!c){s?r.push(i):s=eL(i);continue}let[u,p]=l?eI(i):[i,void 0],d=ec.get(u);if(!d){if(function(e,t,s){var r;if(r=s,!/^-\d+(\.\d+)?$/.test(r)||!e)return!1;let o=ep(e);return!o||!!o.allowsExtraPositionals||0!==o.positionalArgs.length&&(t.length<o.positionalArgs.length||o.positionalArgs.some(e=>e.includes("?")))}(s,r,i)){s?r.push(i):s=i;continue}throw new I("INVALID_ARGS",`Unknown flag: ${u}`)}let m=function(e,t,s,r){if(void 0!==e.setValue){if(void 0!==s)throw new I("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==s)throw new I("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==s){if(0===s.trim().length)throw new I("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:s,consumeNext:!1}}return void 0===r||ex(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=s??r;if(void 0===o||void 0===s&&ex(o))throw new I("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:o,consumeNext:void 0===s};if("enum"===e.type){if(!e.enumValues?.includes(o))throw new I("INVALID_ARGS",`Invalid ${eA(t)}: ${o}`);return{value:o,consumeNext:void 0===s}}let n=Number(o);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new I("INVALID_ARGS",`Invalid ${eA(t)}: ${o}`);return{value:Math.floor(n),consumeNext:void 0===s}}(d,u,p,e[a+1]);m.consumeNext&&(a+=1);let f=t[d.key];if(d.multiple){let e=Array.isArray(f)?[...f,m.value]:void 0===f?[m.value]:[f,m.value];t[d.key]=e}else t[d.key]=m.value;o.push({key:d.key,token:u})}return{command:s,positionals:r,flags:t,warnings:[],providedFlags:o}}(e),s=a?.env??process.env,r=a?.cwd??process.cwd(),p=t.command,o=null!==p&&(l={remoteConfig:t.flags.remoteConfig,cwd:r,env:s}).remoteConfig?{...function(e){let t={};for(let s of tG){let r=e[s];void 0!==r&&(t[s]=r)}return t}(w({configPath:l.remoteConfig,cwd:l.cwd,env:l.env}).profile),remoteConfig:l.remoteConfig}:{},b=er((n=(c={command:t.command,cwd:r,cliFlags:t.flags,env:s}).env??process.env,h=er({},function(e){let t={};for(let s of e)er(t,function(e,t){let s,r;if(!u.existsSync(e)){if(t)throw new I("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{s=u.readFileSync(e,"utf8")}catch(t){throw new I("INVALID_ARGS",`Failed to read config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}try{r=JSON.parse(s)}catch(t){throw new I("INVALID_ARGS",`Invalid JSON in config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`Config file must contain a JSON object: ${e}`);return function(e,t){let s={};for(let[r,o]of Object.entries(e)){let e=eD.get(r);if(!e)throw new I("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new I("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);s[r]=k(eS(e),o,t,r)}return s}(r,`config file ${e}`)}(s.path,s.required));return t}((d=c.cwd,m=c.cliFlags.config,f=n,($=m??f.AGENT_DEVICE_CONFIG)?[{path:(g=$,y=d,v=f,W(g,{cwd:y,env:v})),required:!0}]:[{path:(D=f,i.join(X("~",{env:D}),".agent-device","config.json")),required:!1},{path:i.resolve(d,"agent-device.json"),required:!1}]))),er(h,function(e,t){var s,r,o;let n={};for(let a of ek.filter(e=>e.config.enabled&&e.supportsCommand(t))){let t=a.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(n[a.key]=(s=t.value,r=`environment variable ${t.name}`,o=t.name,k(eS(a),s,r,o)))}return n}(n,c.command))),o),C={...function(e,t){let s=t?.strictFlags??function(e){if(!e)return!1;let t=e.trim().toLowerCase();return"1"===t||"true"===t||"yes"===t||"on"===t}(process.env.AGENT_DEVICE_STRICT_FLAGS),r=[...e.warnings],o=er({json:!1,help:!1,version:!1},t?.defaultFlags??{});er(o,e.flags);let n=ep(e.command),a=e.providedFlags.filter(t=>!e$(t.key,e.command));if(a.length>0){var i,l;let t=a.map(e=>e.token),n=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(s)throw new I("INVALID_ARGS",n);for(let e of(r.push(`${n} Enable AGENT_DEVICE_STRICT_FLAGS=1 to fail fast.`),a))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 I("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),n?.defaults)for(let[e,t]of Object.entries(n.defaults))void 0===o[e]&&(o[e]=t);if("batch"===e.command&&1!=+!!o.steps+ +!!o.stepsFile)throw new I("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,...s}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:s,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:o,warnings:r})}(t,{strictFlags:a?.strictFlags,defaultFlags:b}),providedFlags:t.providedFlags}}catch(t){F({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=S(t,{diagnosticId:E().diagnosticId,logPath:G({force:!0})??void 0});n?eR({success:!1,error:e}):eN(e,{showDetails:o}),process.exit(1);return}for(let e of C.warnings)process.stderr.write(`Warning: ${e}
|
|
81
|
+
`),0}(e,s,r,n);return 0!==a&&process.exit(a),!0}}function tT(e){return{depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw}}function tB(e){if(e[0]?.startsWith("@"))return{ref:e[0],label:e.slice(1).join(" ")||void 0};let t=er(e);return t?{selector:t.selectorExpression}:{x:Number(e[0]),y:Number(e[1])}}function tU(e,t){if("start"===e||"stop"===e)return e;throw new $("INVALID_ARGS",`${t} requires start|stop`)}function tG(e,t){if(void 0===e||""===e)throw new $("INVALID_ARGS",t);return e}function tq(e){return void 0===e?void 0:Number(e)}let tK={...{session:ta,[et.devices]:ti,[et.apps]:tp,"ensure-simulator":tc,metro:tu,install:tg,reinstall:th,"install-from-source":ty,connect:tD,disconnect:tI,connection:tA,open:tv,close:tk,[et.snapshot]:tL,[et.screenshot]:tR,[et.diff]:tN},...tC,...tj};async function tH(e){let t=tK[e.command];return!!t&&await t(e)}async function tJ(e,t){let{flags:s}=e,r=function(e){if(!e?.metroProxyBaseUrl||"android"!==e.platform&&"android-instance"!==e.leaseBackend)return null;let t=e?.metroProxyBaseUrl,s=e?.metroBearerToken,r=e?.tenant,o=e?.runId,n=e?.leaseId,a=[];if(t||a.push("metroProxyBaseUrl"),s||a.push("metroBearerToken"),r||a.push("tenant"),o||a.push("runId"),n||a.push("leaseId"),a.length>0)throw new $("INVALID_ARGS",`react-devtools remote Android bridge requires ${a.join(", ")}.`,{missing:a});if(!t||!s||!r||!o||!n)throw new $("INVALID_ARGS","react-devtools remote Android bridge is incomplete.");return{serverBaseUrl:t,bearerToken:s,tenantId:r,runId:o,leaseId:n}}(s);if(!r)return t();let o=e.stateDir??process.cwd(),n=e.session??s?.session??"default",a=s?.remoteConfig??`${r.tenantId}:${r.runId}:${r.leaseId}`;await W({projectRoot:e.cwd??process.cwd(),stateDir:o,kind:"react-devtools",serverBaseUrl:r.serverBaseUrl,bearerToken:r.bearerToken,localBaseUrl:"http://127.0.0.1:8097",bridgeScope:{tenantId:r.tenantId,runId:r.runId,leaseId:r.leaseId},registerPath:"/api/react-devtools/companion/register",unregisterPath:"/api/react-devtools/companion/unregister",devicePort:8097,session:n,profileKey:a,consumerKey:n,env:e.env??process.env});try{return await t()}finally{await z({projectRoot:e.cwd??process.cwd(),stateDir:o,kind:"react-devtools",profileKey:a,consumerKey:n})}}async function tz(e,t={}){let s=t.cwd??process.cwd(),r=t.env??process.env;return await tJ(t,async()=>(await eo("npm",["exec","--yes","--package","agent-react-devtools@0.4.0","--","agent-react-devtools",...e],{cwd:s,env:r,allowFailure:!0,onStdoutChunk:e=>{process.stdout.write(e)},onStderrChunk:e=>{process.stderr.write(e)}})).exitCode)}function tW(e,t={}){let s=tY(t),r={...e};return s.defaultPlatform&&void 0===r.platform&&(r.platform=s.defaultPlatform),r}function tY(e){var t,s,r,o;let n,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 $("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:(s=e.policyOverrides,r=a,o=l,(n=s?.sessionLock??s?.sessionLockConflicts??tX(r.AGENT_DEVICE_SESSION_LOCK)??tX(r.AGENT_DEVICE_SESSION_LOCK_CONFLICTS))||(s?.sessionLocked===!0||d(r.AGENT_DEVICE_SESSION_LOCKED)||o?"reject":void 0))}}function tX(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("reject"===t||"strip"===t)return t;throw new $("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}let tZ=v.map(e=>e.key),tQ={sendToDaemon:es},t0=new Set(["launchUrl","metroBearerToken","metroKind","metroListenHost","metroNoInstallDeps","metroNoReuseExisting","metroPreparePort","metroProbeTimeoutMs","metroProjectRoot","metroProxyBaseUrl","metroPublicBaseUrl","metroRuntimeFile","metroStartupTimeoutMs","metroStatusHost"]),t1=new Set(["connect","connection","close","devices","disconnect","ensure-simulator","metro","session"]);async function t2(e,t=tQ){let s=C(),r=E(),o=e.includes("--debug")||e.includes("--verbose")||e.includes("-v"),n=e.includes("--json"),a=function(e){for(let t=0;t<e.length;t+=1){let s=e[t];if(s.startsWith("--session=")){let e=s.slice(10).trim();return e.length>0?e:null}if("--session"===s){let s=e[t+1]?.trim();if(s&&!s.startsWith("-"))return s;break}}return null}(e)??process.env.AGENT_DEVICE_SESSION??"default";await B({session:a,requestId:s,command:e[0],debug:o},async()=>{var a,l,c,p,d,m,f,g,y,v,D,S,x,L,R,N;let C,_,P,O,E,j,V;try{let t,s,r,o,n,h,b,I;a={cwd:process.cwd(),env:process.env},t=function(e){let t={json:!1,help:!1,version:!1},s=null,r=[],o=[],n=!0;for(let l=0;l<e.length;l+=1){var a,i;let c=e[l];if(n&&"--"===c){n=!1;continue}if(!n){s?r.push(c):s=eC(c);continue}let u=c.startsWith("--"),p=c.startsWith("-")&&c.length>1;if(!u&&!p){s?r.push(c):s=eC(c);continue}let[d,m]=u?eL(c):[c,void 0],f=ed.get(d);if(a=s,i=f,"react-devtools"===a&&(!i||!eS(i.key,a))){r.push(c);continue}if(!f){if(function(e,t,s){var r;if(r=s,!/^-\d+(\.\d+)?$/.test(r)||!e)return!1;let o=ef(e);return!o||!!o.allowsExtraPositionals||0!==o.positionalArgs.length&&(t.length<o.positionalArgs.length||o.positionalArgs.some(e=>e.includes("?")))}(s,r,c)){s?r.push(c):s=c;continue}throw new $("INVALID_ARGS",`Unknown flag: ${d}`)}let g=function(e,t,s,r){if(void 0!==e.setValue){if(void 0!==s)throw new $("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==s)throw new $("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==s){if(0===s.trim().length)throw new $("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:s,consumeNext:!1}}return void 0===r||eN(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=s??r;if(void 0===o||void 0===s&&eN(o))throw new $("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:o,consumeNext:void 0===s};if("enum"===e.type){if(!e.enumValues?.includes(o))throw new $("INVALID_ARGS",`Invalid ${eR(t)}: ${o}`);return{value:o,consumeNext:void 0===s}}let n=Number(o);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new $("INVALID_ARGS",`Invalid ${eR(t)}: ${o}`);return{value:Math.floor(n),consumeNext:void 0===s}}(f,d,m,e[l+1]);g.consumeNext&&(l+=1);let h=t[f.key];if(f.multiple){let e=Array.isArray(h)?[...h,g.value]:void 0===h?[g.value]:[h,g.value];t[f.key]=e}else t[f.key]=g.value;o.push({key:f.key,token:d})}return{command:s,positionals:r,flags:t,warnings:[],providedFlags:o}}(e),s=a?.env??process.env,r=a?.cwd??process.cwd(),p=t.command,o=null!==p&&(l={remoteConfig:t.flags.remoteConfig,cwd:r,env:s}).remoteConfig?{...function(e){let t={};for(let s of tZ){let r=e[s];void 0!==r&&(t[s]=r)}return t}(w({configPath:l.remoteConfig,cwd:l.cwd,env:l.env}).profile),remoteConfig:l.remoteConfig}:{},b=ea((n=(c={command:t.command,cwd:r,cliFlags:t.flags,env:s}).env??process.env,h=ea({},function(e){let t={};for(let s of e)ea(t,function(e,t){let s,r;if(!u.existsSync(e)){if(t)throw new $("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{s=u.readFileSync(e,"utf8")}catch(t){throw new $("INVALID_ARGS",`Failed to read config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}try{r=JSON.parse(s)}catch(t){throw new $("INVALID_ARGS",`Invalid JSON in config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}if(!r||"object"!=typeof r||Array.isArray(r))throw new $("INVALID_ARGS",`Config file must contain a JSON object: ${e}`);return function(e,t){let s={};for(let[r,o]of Object.entries(e)){if("installSource"===r){s.installSource=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new $("INVALID_ARGS",`${t} installSource must be an object.`);if("github-actions-artifact"!==tf(e.type,`${t} installSource.type`))throw new $("INVALID_ARGS",`${t} installSource.type must be "github-actions-artifact".`);let{owner:s,repo:r}=tm(tf(e.repo,`${t} installSource.repo`),`${t} installSource.repo`);return td(s,r,e.artifact,`${t} installSource.artifact`)}(o,t);continue}let e=e$.get(r);if(!e)throw new $("INVALID_ARGS",`Unknown config key "${r}" in ${t}.`);if(!e.config.enabled)throw new $("INVALID_ARGS",`Unsupported config key "${r}" in ${t}.`);s[r]=k(ex(e),o,t,r)}return s}(r,`config file ${e}`)}(s.path,s.required));return t}((d=c.cwd,m=c.cliFlags.config,f=n,(I=m??f.AGENT_DEVICE_CONFIG)?[{path:(g=I,y=d,v=f,X(g,{cwd:y,env:v})),required:!0}]:[{path:(D=f,i.join(Z("~",{env:D}),".agent-device","config.json")),required:!1},{path:i.resolve(d,"agent-device.json"),required:!1}]))),ea(h,function(e,t){var s,r,o;let n={};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&&(n[a.key]=(s=t.value,r=`environment variable ${t.name}`,o=t.name,k(ex(a),s,r,o)))}return n}(n,c.command))),o),C={...function(e,t){let s=t?.strictFlags??function(e){if(!e)return!1;let t=e.trim().toLowerCase();return"1"===t||"true"===t||"yes"===t||"on"===t}(process.env.AGENT_DEVICE_STRICT_FLAGS),r=[...e.warnings],o=ea({json:!1,help:!1,version:!1},t?.defaultFlags??{});ea(o,e.flags);let n=ef(e.command),a=e.providedFlags.filter(t=>!eS(t.key,e.command));if(a.length>0){var i,l;let t=a.map(e=>e.token),n=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(s)throw new $("INVALID_ARGS",n);for(let e of(r.push(`${n} Enable AGENT_DEVICE_STRICT_FLAGS=1 to fail fast.`),a))delete o[e.key]}for(let t of Object.keys(o))void 0!==o[t]&&(eS(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 $("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),n?.defaults)for(let[e,t]of Object.entries(n.defaults))void 0===o[e]&&(o[e]=t);if("batch"===e.command&&1!=+!!o.steps+ +!!o.stepsFile)throw new $("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,...s}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:s,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:o,warnings:r})}(t,{strictFlags:a?.strictFlags,defaultFlags:b}),providedFlags:t.providedFlags}}catch(t){F({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=A(t,{diagnosticId:M().diagnosticId,logPath:G({force:!0})??void 0});n?e_({success:!1,error:e}):eP(e,{showDetails:o}),process.exit(1);return}for(let e of C.warnings)process.stderr.write(`Warning: ${e}
|
|
82
82
|
`);C.flags.version&&(process.stdout.write(`${r}
|
|
83
|
-
`),process.exit(0));let B="help"===C.command,U=C.flags.help;if(B||U){B&&C.positionals.length>1&&(
|
|
84
|
-
`),process.exit(0));let t=function(e){var t,s;let r=
|
|
83
|
+
`),process.exit(0));let B="help"===C.command,U=C.flags.help;if(B||U){B&&C.positionals.length>1&&(eP(new $("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=B?C.positionals[0]:C.command;e||(process.stdout.write(`${ey}
|
|
84
|
+
`),process.exit(0));let t=function(e){var t,s;let r=ef(e);if(!r)return null;let o=(t=e,(s=r).usageOverride?s.usageOverride:[t,...s.positionalArgs.map(eh),...s.allowedFlags.flatMap(e=>(em.get(e)??[]).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`)].join(" ")),n=ew(new Set(r.allowedFlags)),a=ew(eu),i=[];return n.length>0&&i.push(eb("Command flags:",n)),i.push(eb("Global flags:",a)),`agent-device ${o}
|
|
85
85
|
|
|
86
86
|
${r.helpDescription}
|
|
87
87
|
|
|
@@ -89,9 +89,9 @@ Usage:
|
|
|
89
89
|
agent-device ${o}
|
|
90
90
|
|
|
91
91
|
${i.join("\n\n")}
|
|
92
|
-
`}(
|
|
93
|
-
`),process.exit(1)}C.command||(process.stdout.write(`${
|
|
94
|
-
`),process.exit(1));let{command:q,positionals:
|
|
92
|
+
`}(eC(e));t&&(process.stdout.write(t),process.exit(0)),eP(new $("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${ey}
|
|
93
|
+
`),process.exit(1)}C.command||(process.stdout.write(`${ey}
|
|
94
|
+
`),process.exit(1));let{command:q,positionals:K}=C,H=new Set(C.providedFlags.map(e=>e.key));try{P=(_=tY({policyOverrides:C.flags,configuredPlatform:C.flags.platform,configuredSession:C.flags.session})).lockPolicy?{...C.flags}:tW(C.flags,{policyOverrides:C.flags,configuredPlatform:C.flags.platform,configuredSession:C.flags.session}),O=T(P.stateDir),E=P.session??"default",S={command:q,explicitFlagKeys:H,stateDir:O.baseDir,session:E,remoteConfig:P.remoteConfig},V=(j="connect"===S.command||"connection"===S.command?null:function(e){let t=e.validateRemoteConfigHash??!0,s=e.remoteConfig?b({configPath:e.remoteConfig,cwd:e.cwd,env:e.env}):void 0,r=eq(e)??(e.allowActiveFallback?eX({stateDir:e.stateDir}):null);if(!r||s&&r.remoteConfigPath!==s)return null;if(t&&ez(r.remoteConfigPath)!==r.remoteConfigHash)throw new $("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 w({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:S.stateDir,session:S.session,remoteConfig:S.remoteConfig,cwd:process.cwd(),env:process.env,allowActiveFallback:!S.explicitFlagKeys.has("session")&&(!S.remoteConfig||"disconnect"===S.command),validateRemoteConfigHash:"disconnect"!==S.command}))?function(e,t,s){let r={...e};for(let[e,o]of Object.entries(t))void 0!==o&&(s.has(e)||(r[e]=o));return r}(P,j.flags,H):P}catch(t){let e=A(I(t),{diagnosticId:M().diagnosticId,logPath:G({force:!0})??void 0});C.flags.json?e_({success:!1,error:e}):eP(e,{showDetails:C.flags.verbose}),process.exit(1);return}let J=null;try{let e;if("react-devtools"===q){let e=await tz(K,{flags:V,stateDir:O.baseDir,session:V.session??E,cwd:process.cwd(),env:process.env});process.exit(e);return}en({command:q,currentVersion:r,stateDir:O.baseDir,flags:V});let o=j?.runtime,n=(e,t)=>({session:e.session??E,requestId:s,stateDir:e.stateDir,daemonBaseUrl:e.daemonBaseUrl,daemonAuthToken:e.daemonAuthToken,daemonTransport:e.daemonTransport,daemonServerMode:e.daemonServerMode,tenant:e.tenant,sessionIsolation:e.sessionIsolation,runId:e.runId,leaseId:e.leaseId,leaseBackend:e.leaseBackend,runtime:t,lockPolicy:_.lockPolicy,lockPlatform:_.defaultPlatform,cwd:process.cwd(),debug:!!e.verbose});if("batch"===q){if(K.length>0)throw new $("INVALID_ARGS","batch does not accept positional arguments.");e=function(e){let t="";if(e.steps)t=e.steps;else if(e.stepsFile)try{t=u.readFileSync(e.stepsFile,"utf8")}catch(s){let t=s instanceof Error?s.message:String(s);throw new $("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}return h(t)}(P)}if(V.remoteConfig&&(x=q,!t1.has(x))){let s=ee(n(V,o),{transport:t.sendToDaemon}),r=await e8({command:q,flags:V,client:s,runtime:o,batchSteps:e,forceRuntimePrepare:function(e){for(let t of t0)if(e.has(t))return!0;return!1}(H)});V=r.flags,o=r.runtime}L={command:q,flags:V,runtime:o,explicitFlagKeys:H,hadConnectionDefaults:!!j},!("open"===L.command&&!L.runtime&&!L.flags.bundleUrl&&!L.flags.metroHost&&!L.flags.metroPort&&!L.flags.remoteConfig&&!L.hadConnectionDefaults&&((R=L.explicitFlagKeys).has("daemonBaseUrl")||R.has("daemonTransport")||R.has("tenant")||R.has("sessionIsolation")||R.has("runId")||R.has("leaseId")||R.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 a=V.daemonBaseUrl;J=!V.verbose||V.json||a?null:function(e){try{let t=0,s=!1,r=setInterval(()=>{if(!s&&u.existsSync(e))try{let s=u.statSync(e);if(s.size<t&&(t=0),s.size<=t)return;let r=u.openSync(e,"r");try{let e=Buffer.alloc(s.size-t);u.readSync(r,e,0,e.length,t),t=s.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{u.closeSync(r)}}catch{}},200);return()=>{s=!0,clearInterval(r)}}catch{return null}}(O.logPath);let i=ee(n(V,o),{transport:t.sendToDaemon});if("batch"===q){if(!e)throw new $("INVALID_ARGS","batch requires --steps or --steps-file.");let t=e.map((e,t)=>({...e,flags:_.lockPolicy&&void 0===P.platform?{...e.flags??{}}:tW(e.flags??{},{policyOverrides:V,configuredPlatform:V.platform,configuredSession:V.session,inheritedPlatform:V.platform})}));if(await tH({command:q,positionals:K,flags:{...V,batchSteps:t},client:i}))return}else if("runtime"===q)throw new $("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 tH({command:q,positionals:K,flags:V,client:i}))return;throw new $("INVALID_ARGS",`Unknown command: ${q}`)}catch(s){let e=I(s),t=A(e,{diagnosticId:M().diagnosticId,logPath:G({force:!0})??void 0});if("close"===q&&"COMMAND_FAILED"===(N=e).code&&(N.details?.kind==="daemon_startup_failed"||N.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof N.details?.infoPath||"string"==typeof N.details?.lockPath))){V.json&&e_({success:!0,data:{closed:"session",source:"no-daemon"}});return}if(V.json)e_({success:!1,error:t});else if(eP(t,{showDetails:V.verbose}),V.verbose)try{let e=O.logPath;if(u.existsSync(e)){let t=u.readFileSync(e,"utf8").split("\n"),s=t.slice(Math.max(0,t.length-200)).join("\n");s.trim().length>0&&process.stderr.write(`
|
|
95
95
|
[daemon log]
|
|
96
96
|
${s}
|
|
97
|
-
`)}}catch{}J&&J(),process.exit(1)}finally{J&&J()}})}c(process.argv[1]??"").href===import.meta.url&&
|
|
97
|
+
`)}}catch{}J&&J(),process.exit(1)}finally{J&&J()}})}c(process.argv[1]??"").href===import.meta.url&&t2(process.argv.slice(2)).catch(e=>{eP(A(I(e)),{showDetails:!0}),process.exit(1)}),t2(process.argv.slice(2));
|