You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

agent-device

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

agent-device - npm Package Compare versions

Comparing version
0.7.22
to
0.8.0
+2
dist/src/daemon/request-lock-policy.d.ts
import type { SessionState, DaemonRequest } from './types.ts';
export declare function applyRequestLockPolicy(req: DaemonRequest, existingSession?: SessionState): DaemonRequest;
import { type CliFlags } from './command-schema.ts';
type EnvMap = Record<string, string | undefined>;
export declare function resolveConfigBackedFlagDefaults(options: {
command: string | null;
cwd: string;
cliFlags: CliFlags;
env?: EnvMap;
}): Partial<CliFlags>;
export {};
import { type FlagDefinition, type FlagKey } from './command-schema.ts';
export type OptionSpec = {
key: FlagKey;
flagDefinitions: readonly FlagDefinition[];
config: {
enabled: boolean;
key: string;
};
env: {
names: readonly string[];
};
supportsCommand(command: string | null): boolean;
};
export declare function getOptionSpecs(): readonly OptionSpec[];
export declare function getOptionSpec(key: FlagKey): OptionSpec | undefined;
export declare function getOptionSpecForToken(token: string): OptionSpec | undefined;
export declare function getConfigurableOptionSpecs(command: string | null): OptionSpec[];
export declare function isFlagSupportedForCommand(key: FlagKey, command: string | null): boolean;
export declare function parseOptionValueFromSource(spec: OptionSpec, value: unknown, sourceLabel: string, rawKey: string): unknown;
import type { CliFlags } from './command-schema.ts';
type EnvMap = Record<string, string | undefined>;
export declare function resolveCliOptions(argv: string[], options?: {
cwd?: string;
env?: EnvMap;
strictFlags?: boolean;
}): {
command: string | null;
positionals: string[];
flags: CliFlags;
warnings: string[];
};
export {};
import type { CliFlags } from './command-schema.ts';
import type { DaemonLockPolicy } from '../daemon/types.ts';
export type BindingSettings = {
defaultPlatform?: CliFlags['platform'];
lockPolicy?: DaemonLockPolicy;
};
type BindingPolicyOverrides = Pick<Partial<CliFlags>, 'sessionLock' | 'sessionLocked' | 'sessionLockConflicts'>;
type LockableFlags = Pick<Partial<CliFlags>, 'platform' | 'target' | 'device' | 'udid' | 'serial' | 'iosSimulatorDeviceSet' | 'androidDeviceAllowlist'>;
type BindingOptions = {
env?: NodeJS.ProcessEnv;
policyOverrides?: BindingPolicyOverrides;
configuredPlatform?: CliFlags['platform'];
configuredSession?: string;
inheritedPlatform?: CliFlags['platform'];
};
export declare function applyDefaultPlatformBinding<T extends LockableFlags>(flags: T, options?: BindingOptions): T;
export declare function resolveBindingSettings(options: BindingOptions): BindingSettings;
export {};
+2
-2

@@ -1,2 +0,2 @@

import{createRequestId as e,node_path as t,isAgentDeviceDaemonProcess as r,runCmdDetached as a,readVersion as n,findProjectRoot as o,node_https as i,runCmdSync as s,withDiagnosticTimer as d,resolveDaemonTransportPreference as l,emitDiagnostic as u,spawn as c,AppError as m,node_fs as p,resolveDaemonPaths as h,node_net as f,resolveDaemonServerMode as I,stopProcessForTakeover as w,node_http as A}from"./331.js";async function g(e){let{localPath:r,baseUrl:a,token:n}=e,o=p.statSync(r).isDirectory(),s=t.basename(r),d=new URL("upload",a.endsWith("/")?a:`${a}/`),l="https:"===d.protocol?i:A,u={"x-artifact-type":o?"app-bundle":"file","x-artifact-filename":s,"transfer-encoding":"chunked"};return n&&(u.authorization=`Bearer ${n}`,u["x-agent-device-token"]=n),new Promise((e,a)=>{let n=l.request({protocol:d.protocol,host:d.hostname,port:d.port,method:"POST",path:d.pathname+d.search,headers:u},t=>{let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{clearTimeout(i);try{let t=JSON.parse(r);if(!t.ok||!t.uploadId)return void a(new m("COMMAND_FAILED",`Upload failed: ${r}`));e(t.uploadId)}catch{a(new m("COMMAND_FAILED",`Invalid upload response: ${r}`))}})}),i=setTimeout(()=>{n.destroy(),a(new m("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(n.on("error",e=>{clearTimeout(i),a(new m("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),o){let e=c("tar",["cf","-","-C",t.dirname(r),t.basename(r)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(n),e.on("error",e=>{n.destroy(),a(new m("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(n.destroy(),a(new m("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=p.createReadStream(r);e.pipe(n),e.on("error",e=>{n.destroy(),a(new m("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}let D=function(e=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if(!e)return 9e4;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):9e4}(),v=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS){if(!e)return 15e3;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):15e3}(),y=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_ATTEMPTS){if(!e)return 2;let t=Number(e);return Number.isFinite(t)?Math.min(5,Math.max(1,Math.floor(t))):2}(),E=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"];async function _(t){let r=t.meta?.requestId??e(),a=!!(t.meta?.debug||t.flags?.verbose),n=function(e){let t=e.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR,r=function(e){let t;if(e){try{t=new URL(e)}catch(t){throw new m("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new m("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(e.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),a=e.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN,n=e.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,o=l(n);if(r&&"socket"===o)throw new m("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:r});let i=I(e.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===n?"dual":void 0));return{paths:h(t),transportPreference:o,serverMode:i,remoteBaseUrl:r,remoteAuthToken:a}}(t),o=await d("daemon_startup",async()=>await T(n),{requestId:r,session:t.session}),i=await M(t,o),s={...t,positionals:i.positionals,flags:i.flags,token:o.token,meta:{requestId:r,debug:a,cwd:t.meta?.cwd,tenantId:t.meta?.tenantId??t.flags?.tenant,runId:t.meta?.runId??t.flags?.runId,leaseId:t.meta?.leaseId??t.flags?.leaseId,sessionIsolation:t.meta?.sessionIsolation??t.flags?.sessionIsolation,...i.uploadedArtifactId?{uploadedArtifactId:i.uploadedArtifactId}:{},...i.clientArtifactPaths?{clientArtifactPaths:i.clientArtifactPaths}:{}}};return u({level:"info",phase:"daemon_request_prepare",data:{requestId:r,command:t.command,session:t.session}}),await d("daemon_request",async()=>await B(o,s,n.transportPreference),{requestId:r,command:t.command})}async function M(e,r){let a=[...e.positionals??[]],n=e.flags?{...e.flags}:void 0,o={};if(K(r)){let r=function(e,r){if("screenshot"===e.command){let t=P(e,"path",".png");return r[0]?{field:"path",localPath:t,positionalIndex:0,positionalPath:b("screenshot",".png")}:{field:"path",localPath:t,positionalIndex:0,flagPath:b("screenshot",".png")}}if("record"===e.command&&"start"===(r[0]??"").toLowerCase()){let r=P(e,"outPath",".mp4",1);return{field:"outPath",localPath:r,positionalIndex:1,positionalPath:b("recording",t.extname(r)||".mp4")}}return null}(e,a);r&&(void 0!==r.positionalPath&&(a[r.positionalIndex]=r.positionalPath),void 0!==r.flagPath&&((n??={}).out=r.flagPath),o[r.field]=r.localPath)}if(!K(r)||"install"!==e.command&&"reinstall"!==e.command||a.length<2)return{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}};let i=a[1];if(i.startsWith("remote:"))return a[1]=i.slice(7),{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}};let s=t.isAbsolute(i)?i:t.resolve(e.meta?.cwd??process.cwd(),i);return p.existsSync(s)?{positionals:a,flags:n,uploadedArtifactId:await g({localPath:s,baseUrl:r.baseUrl,token:r.token}),...Object.keys(o).length>0?{clientArtifactPaths:o}:{}}:{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}}}function P(e,r,a,n=0){let o=e.positionals?.[n]??e.flags?.out,i=`${"path"===r?"screenshot":"recording"}-${Date.now()}${a}`,s=o&&o.trim().length>0?o:i;return t.isAbsolute(s)?s:t.resolve(e.meta?.cwd??process.cwd(),s)}function b(e,r){let a=r.startsWith(".")?r:`.${r}`;return t.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${a}`)}async function T(e){let a;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await F(t,"http"))return t;throw new m("COMMAND_FAILED","Remote daemon is unavailable",{daemonBaseUrl:e.remoteBaseUrl,hint:"Verify AGENT_DEVICE_DAEMON_BASE_URL points to a reachable daemon with GET /health and POST /rpc."})}let i=R(e.paths.infoPath),s=n(),d=function(e,r=o()){try{let a=p.statSync(e),n=t.relative(r,e)||e;return`${n}:${a.size}:${Math.trunc(a.mtimeMs)}`}catch{return"unknown"}}((a=$()).useSrc?a.srcPath:a.distPath,a.root),l=!!i&&await F(i,e.transportPreference);if(i&&i.version===s&&i.codeSignature===d&&l)return i;i&&(i.version!==s||i.codeSignature!==d||!l)&&(await O(i),q(e.paths.infoPath)),function(e){let t=U(e);if(!t.hasLock||t.hasInfo)return;let a=C(e.lockPath);if(!a)return q(e.lockPath);r(a.pid,a.processStartTime)||q(e.lockPath)}(e.paths);let u=0;for(let t=1;t<=y;t+=1){await x(e);let r=await N(v,e);if(r)return r;if(await k(e.paths)){u+=1;continue}let a=U(e.paths);if(!(t<y))break;if(!a.hasInfo&&!a.hasLock){await S(150);continue}}let c=U(e.paths);throw new m("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:v,startupAttempts:y,lockRecoveryCount:u,metadataState:c,hint:function(e,t=h(process.env.AGENT_DEVICE_STATE_DIR)){return e.hasLock&&!e.hasInfo?`Detected ${t.lockPath} without ${t.infoPath}. If no agent-device daemon process is running, delete ${t.lockPath} and retry.`:e.hasLock&&e.hasInfo?`Daemon metadata may be stale. If no agent-device daemon process is running, delete ${t.infoPath} and ${t.lockPath}, then retry.`:`Daemon metadata is missing or stale. Delete ${t.infoPath} if present and retry.`}(c,e.paths)})}async function N(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=R(t.paths.infoPath);if(e&&await F(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function S(e){await new Promise(t=>setTimeout(t,e))}async function k(e){let t=U(e);if(!t.hasLock||t.hasInfo)return!1;let a=C(e.lockPath);return a&&r(a.pid,a.processStartTime)&&await w(a.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:a.processStartTime}),q(e.lockPath),!0}async function O(e){await w(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function R(e){let t=L(e);if(!t||"string"!=typeof t.token||0===t.token.length)return null;let r=Number.isInteger(t.port)&&Number(t.port)>0,a=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;return r||a?{...t,port:r?Number(t.port):void 0,httpPort:a?Number(t.httpPort):void 0,pid:Number.isInteger(t.pid)&&t.pid>0?t.pid:0}:null}function C(e){let t=L(e);return t&&Number.isInteger(t.pid)&&!(t.pid<=0)?t:null}function U(e){return{hasInfo:p.existsSync(e.infoPath),hasLock:p.existsSync(e.lockPath)}}function L(e){if(!p.existsSync(e))return null;try{return JSON.parse(p.readFileSync(e,"utf8"))}catch{return null}}function q(e){try{p.existsSync(e)&&p.unlinkSync(e)}catch{}}async function F(e,t){var r;return"http"===z(e,t)?await function(e){let t=e.baseUrl?J(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!t)return Promise.resolve(!1);let r=new URL(t),a="https:"===r.protocol?i:A,n=e.baseUrl?3e3:500;return new Promise(e=>{let t=a.request({protocol:r.protocol,host:r.hostname,port:r.port,path:r.pathname+r.search,method:"GET",timeout:n},t=>{t.resume(),e((t.statusCode??500)<500)});t.on("timeout",()=>{t.destroy(),e(!1)}),t.on("error",()=>{e(!1)}),t.end()})}(e):await ((r=e.port)?new Promise(e=>{let t=f.createConnection({host:"127.0.0.1",port:r},()=>{t.destroy(),e(!0)});t.on("error",()=>{e(!1)})}):Promise.resolve(!1))}async function x(e){let t=$(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],n={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};a(process.execPath,r,{env:n})}function $(){let e=o(),r=t.join(e,"dist","src","daemon.js"),a=t.join(e,"src","daemon.ts"),n=p.existsSync(r),i=p.existsSync(a);if(!n&&!i)throw new m("COMMAND_FAILED","Daemon entry not found",{distPath:r,srcPath:a});return{root:e,distPath:r,srcPath:a,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!n&&i}}async function B(e,t,r){return"http"===z(e,r)?await V(e,t):await G(e,t)}function z(e,t){if(e.baseUrl){if("socket"===t)throw new m("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t){if(!e.httpPort)throw new m("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");return"http"}if("socket"===t){if(!e.port)throw new m("COMMAND_FAILED","Daemon socket endpoint is unavailable");return"socket"}let r=e.transport;if("http"===r&&e.httpPort)return"http";if(("socket"===r||"dual"===r)&&e.port)return"socket";if(e.httpPort)return"http";if(e.port)return"socket";throw new m("COMMAND_FAILED","Daemon metadata has no reachable transport")}async function G(e,t){let r=e.port;if(!r)throw new m("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((a,n)=>{let o=f.createConnection({host:"127.0.0.1",port:r},()=>{o.write(`${JSON.stringify(t)}
`)}),i=setTimeout(()=>{o.destroy();let r=j(),a=H(e,h(t.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR));u({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:D,requestId:t.meta?.requestId,command:t.command,timedOutRunnerPidsTerminated:r.terminated,timedOutRunnerCleanupError:r.error,daemonPidReset:e.pid,daemonPidForceKilled:a.forcedKill}}),n(new m("COMMAND_FAILED","Daemon request timed out",{timeoutMs:D,requestId:t.meta?.requestId,hint:"Retry with --debug and check daemon diagnostics logs. Timed-out iOS runner xcodebuild processes were terminated when detected."}))},D),s="";o.setEncoding("utf8"),o.on("data",e=>{let r=(s+=e).indexOf("\n");if(-1===r)return;let d=s.slice(0,r).trim();if(d)try{let e=JSON.parse(d);o.end(),clearTimeout(i),a(e)}catch(e){clearTimeout(i),n(new m("COMMAND_FAILED","Invalid daemon response",{requestId:t.meta?.requestId,line:d},e instanceof Error?e:void 0))}}),o.on("error",e=>{clearTimeout(i),u({level:"error",phase:"daemon_request_socket_error",data:{requestId:t.meta?.requestId,message:e instanceof Error?e.message:String(e)}}),n(new m("COMMAND_FAILED","Failed to communicate with daemon",{requestId:t.meta?.requestId,hint:"Retry command. If this persists, clean stale daemon metadata and start a fresh session."},e))})})}async function V(t,r){let a=t.baseUrl?new URL(J(t.baseUrl,"rpc")):t.httpPort?new URL(`http://127.0.0.1:${t.httpPort}/rpc`):null;if(!a)throw new m("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let n=JSON.stringify({jsonrpc:"2.0",id:r.meta?.requestId??e(),method:"agent_device.command",params:r}),o={"content-type":"application/json","content-length":Buffer.byteLength(n)};return t.baseUrl&&t.token&&(o.authorization=`Bearer ${t.token}`,o["x-agent-device-token"]=t.token),await new Promise((e,s)=>{let d=h(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),l=("https:"===a.protocol?i:A).request({protocol:a.protocol,host:a.hostname,port:a.port,method:"POST",path:a.pathname+a.search,headers:o},a=>{let n="";a.setEncoding("utf8"),a.on("data",e=>{n+=e}),a.on("end",()=>{clearTimeout(c);try{let a=JSON.parse(n);if(a.error){let e=a.error.data??{};s(new m(String(e.code??"COMMAND_FAILED"),String(e.message??a.error.message??"Daemon RPC request failed"),{..."object"==typeof e.details&&e.details?e.details:{},hint:"string"==typeof e.hint?e.hint:void 0,diagnosticId:"string"==typeof e.diagnosticId?e.diagnosticId:void 0,logPath:"string"==typeof e.logPath?e.logPath:void 0,requestId:r.meta?.requestId}));return}if(!a.result||"object"!=typeof a.result)return void s(new m("COMMAND_FAILED","Invalid daemon RPC response",{requestId:r.meta?.requestId}));if(t.baseUrl&&a.result.ok)return void W(t,r,a.result).then(e).catch(s);e(a.result)}catch(e){clearTimeout(c),s(new m("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:n},e instanceof Error?e:void 0))}})}),c=setTimeout(()=>{l.destroy();let e=K(t)?{terminated:0}:j(),a=K(t)?{forcedKill:!1}:H(t,d);u({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:D,requestId:r.meta?.requestId,command:r.command,timedOutRunnerPidsTerminated:e.terminated,timedOutRunnerCleanupError:e.error,daemonPidReset:K(t)?void 0:t.pid,daemonPidForceKilled:K(t)?void 0:a.forcedKill,daemonBaseUrl:t.baseUrl}}),s(new m("COMMAND_FAILED","Daemon request timed out",{timeoutMs:D,requestId:r.meta?.requestId,hint:K(t)?"Retry with --debug and verify the remote daemon URL, auth token, and remote host logs.":"Retry with --debug and check daemon diagnostics logs. Timed-out iOS runner xcodebuild processes were terminated when detected."}))},D);l.on("error",e=>{clearTimeout(c),u({level:"error",phase:"daemon_request_socket_error",data:{requestId:r.meta?.requestId,message:e instanceof Error?e.message:String(e)}}),s(new m("COMMAND_FAILED","Failed to communicate with daemon",{requestId:r.meta?.requestId,hint:K(t)?"Retry command. If this persists, verify the remote daemon URL, auth token, and remote host reachability.":"Retry command. If this persists, clean stale daemon metadata and start a fresh session."},e))}),l.write(n),l.end()})}function j(){let e=0;try{for(let t of E){let r=s("pkill",["-f",t],{allowFailure:!0});0===r.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}function H(e,t){let a=!1;try{r(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),a=!0)}catch{w(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{q(t.infoPath),q(t.lockPath)}return{forcedKill:a}}function K(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function J(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function W(e,r,a){let n=Array.isArray(a.data?.artifacts)?a.data.artifacts:[];if(0===n.length||!e.baseUrl)return a;let o=a.data?{...a.data}:{},i=[];for(let a of n){if(!a||"object"!=typeof a||"string"!=typeof a.artifactId){i.push(a);continue}let n=function(e,r){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let a=e.fileName?.trim()||`${e.field}-${Date.now()}`;return t.resolve(r.meta?.cwd??process.cwd(),a)}(a,r);await Q({baseUrl:e.baseUrl,token:e.token,artifactId:a.artifactId,destinationPath:n,requestId:r.meta?.requestId}),o[a.field]=n,i.push({...a,localPath:n})}return o.artifacts=i,{ok:!0,data:o}}async function Q(e){var r,a;let n,o=new URL((r=e.baseUrl,a=e.artifactId,n=r.endsWith("/")?r:`${r}/`,new URL(`upload/${encodeURIComponent(a)}`,n).toString())),s="https:"===o.protocol?i:A;await p.promises.mkdir(t.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let a=!1,n=e.timeoutMs??D,i=n=>{if(!a){if(a=!0,clearTimeout(l),n)return void p.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(n));t()}},d=s.request({protocol:o.protocol,host:o.hostname,port:o.port,method:"GET",path:o.pathname+o.search,headers:e.token?{authorization:`Bearer ${e.token}`,"x-agent-device-token":e.token}:void 0},t=>{if((t.statusCode??500)>=400){let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=p.createWriteStream(e.destinationPath);r.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("aborted",()=>{i(new m("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),l=setTimeout(()=>{d.destroy(new m("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n}))},n);d.on("error",t=>{t instanceof m?i(t):i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n},t instanceof Error?t:void 0))}),d.end()})}function X(e,t){let r=es(e,"bundleId"),a=es(e,"package"),n=r??a;return{app:ei(e,"app"),appPath:ei(e,"appPath"),platform:el(e,"platform"),appId:n,bundleId:r,package:a,identifiers:{session:t,appId:n,appBundleId:r,package:a}}}function Y(e,t){return{session:t,configured:!0===e.configured,cleared:!0===e.cleared||void 0,runtime:et(e.runtime),identifiers:{session:t}}}function Z(e){let t=en(e),r=el(t,"platform"),a=ei(t,"id");return{platform:r,target:eu(t,"target"),kind:function(e,t){let r=e[t];if("simulator"===r||"emulator"===r||"device"===r)return r;throw new m("COMMAND_FAILED",`Daemon response has invalid "${t}".`,{response:e})}(t,"kind"),id:a,name:ei(t,"name"),booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:{deviceId:a,deviceName:ei(t,"name"),..."ios"===r?{udid:a}:{serial:a}},ios:"ios"===r?{udid:a}:void 0,android:"android"===r?{serial:a}:void 0}}function ee(e){let t=en(e),r=el(t,"platform"),a=ei(t,"id"),n=ei(t,"name"),o=eu(t,"target"),i=ei(t,"device"),s={session:n,deviceId:a,deviceName:i,..."ios"===r?{udid:a}:{serial:a}};return{name:n,createdAt:function(e,t){let r=e[t];if("number"!=typeof r||!Number.isFinite(r))throw new m("COMMAND_FAILED",`Daemon response is missing numeric "${t}".`,{response:e});return r}(t,"createdAt"),device:{platform:r,target:o,id:a,name:i,identifiers:s,ios:"ios"===r?{udid:a,simulatorSetPath:ed(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:a}:void 0},identifiers:s}}function et(e){if(!eo(e))return;let t=e.platform,r=es(e,"metroHost"),a="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:a,bundleUrl:es(e,"bundleUrl"),launchUrl:es(e,"launchUrl")}}function er(e,t){return t??e??"default"}function ea(e){let t={};for(let[r,a]of Object.entries(e))void 0!==a&&(t[r]=a);return t}function en(e){if(!eo(e))throw new m("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eo(e){return"object"==typeof e&&null!==e}function ei(e,t){let r=e[t];if("string"!=typeof r||0===r.length)throw new m("COMMAND_FAILED",`Daemon response is missing "${t}".`,{response:e});return r}function es(e,t){let r=e[t];return"string"==typeof r&&r.length>0?r:void 0}function ed(e,t){let r=e[t];return null===r?null:"string"==typeof r&&r.length>0?r:void 0}function el(e,t){let r=e[t];if("ios"===r||"android"===r)return r;throw new m("COMMAND_FAILED",`Daemon response has invalid "${t}".`,{response:e})}function eu(e,t){return"tv"===e[t]?"tv":"mobile"}function ec(e={},t={}){let r=t.transport??_,a=async(t,a=[],n={})=>{let o={...e,...n},i=await r({session:er(e.session,n.session),command:t,positionals:a,flags:ea({stateDir:o.stateDir,daemonBaseUrl:o.daemonBaseUrl,daemonAuthToken:o.daemonAuthToken,daemonTransport:o.daemonTransport,daemonServerMode:o.daemonServerMode,tenant:o.tenant,sessionIsolation:o.sessionIsolation,runId:o.runId,leaseId:o.leaseId,platform:o.platform,target:o.target,device:o.device,udid:o.udid,serial:o.serial,iosSimulatorDeviceSet:o.iosSimulatorDeviceSet,androidDeviceAllowlist:o.androidDeviceAllowlist,runtime:o.simulatorRuntimeId,boot:o.boot,reuseExisting:o.reuseExisting,activity:o.activity,relaunch:o.relaunch,shutdown:o.shutdown,saveScript:o.saveScript,noRecord:o.noRecord,metroHost:o.metroHost,metroPort:o.metroPort,bundleUrl:o.bundleUrl,launchUrl:o.launchUrl,snapshotInteractiveOnly:o.interactiveOnly,snapshotCompact:o.compact,snapshotDepth:o.depth,snapshotScope:o.scope,snapshotRaw:o.raw,verbose:o.debug}),runtime:o.runtime,meta:ea({requestId:o.requestId,cwd:o.cwd,debug:o.debug,tenantId:o.tenant,runId:o.runId,leaseId:o.leaseId,sessionIsolation:o.sessionIsolation,installSource:o.installSource,retainMaterializedPaths:o.retainMaterializedPaths,materializedPathRetentionMs:o.materializedPathRetentionMs,materializationId:o.materializationId})});if(!i.ok)throw new m(i.error.code,i.error.message,{...i.error.details??{},hint:i.error.hint,diagnosticId:i.error.diagnosticId,logPath:i.error.logPath});return i.data??{}},n=async(e={})=>{let t=await a("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(ee)};return{devices:{list:async(e={})=>{let t=await a("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(Z)}},sessions:{list:async(e={})=>await n(e),close:async(t={})=>{let r=er(e.session,t.session),n=(await a("close",[],t)).shutdown;return{session:r,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,n=await a("ensure-simulator",[],{...r,simulatorRuntimeId:t}),o=ei(n,"udid"),i=ei(n,"device");return{udid:o,device:i,runtime:ei(n,"runtime"),created:!0===n.created,booted:!0===n.booted,iosSimulatorDeviceSet:ed(n,"ios_simulator_device_set"),identifiers:{deviceId:o,deviceName:i,udid:o}}}},apps:{install:async t=>X(await a("install",[t.app,t.appPath],t),er(e.session,t.session)),reinstall:async t=>X(await a("reinstall",[t.app,t.appPath],t),er(e.session,t.session)),installFromSource:async t=>{var r,n;let o,i,s;return r=await a("install_source",[],{...t,installSource:t.source,retainMaterializedPaths:t.retainPaths,materializedPathRetentionMs:t.retentionMs}),n=er(e.session,t.session),o=es(r,"bundleId"),i=es(r,"packageName"),s=o??i,{appName:es(r,"appName"),appId:s,bundleId:o,packageName:i,launchTarget:ei(r,"launchTarget"),installablePath:es(r,"installablePath"),archivePath:es(r,"archivePath"),materializationId:es(r,"materializationId"),materializationExpiresAt:es(r,"materializationExpiresAt"),identifiers:{session:n,appId:s,appBundleId:o,package:i}}},open:async t=>{let r=er(e.session,t.session),n=t.url?[t.app,t.url]:[t.app],o=await a("open",n,t),i=function(e){let t=e.platform,r=es(e,"id"),a=es(e,"device");if("ios"!==t&&"android"!==t||!r||!a)return;let n=eu(e,"target"),o={deviceId:r,deviceName:a,..."ios"===t?{udid:r}:{serial:r}};return{platform:t,target:n,id:r,name:a,identifiers:o,ios:"ios"===t?{udid:es(e,"device_udid")??r,simulatorSetPath:ed(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:es(e,"serial")??r}:void 0}}(o),s=es(o,"appBundleId");return{session:r,appName:es(o,"appName"),appBundleId:s,appId:s,startup:function(e){if(eo(e)&&"number"==typeof e.durationMs&&"string"==typeof e.measuredAt&&"string"==typeof e.method)return{durationMs:e.durationMs,measuredAt:e.measuredAt,method:e.method,appTarget:es(e,"appTarget"),appBundleId:es(e,"appBundleId")}}(o.startup),runtime:et(o.runtime),device:i,identifiers:{session:r,deviceId:i?.id,deviceName:i?.name,udid:i?.ios?.udid,serial:i?.android?.serial,appId:s,appBundleId:s}}},close:async(t={})=>{let r=er(e.session,t.session),n=(await a("close",t.app?[t.app]:[],t)).shutdown;return{session:r,closedApp:t.app,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},materializations:{release:async e=>{var t;return{released:!0===(t=await a("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:ei(t,"materializationId"),identifiers:{}}}},runtime:{set:async t=>Y(await a("runtime",["set"],t),er(e.session,t.session)),show:async(t={})=>Y(await a("runtime",["show"],t),er(e.session,t.session))},capture:{snapshot:async(t={})=>{var r;let n=er(e.session,t.session),o=await a("snapshot",[],t),i=es(o,"appBundleId");return{nodes:Array.isArray(r=o.nodes)?r:[],truncated:!0===o.truncated,appName:es(o,"appName"),appBundleId:i,identifiers:{session:n,appId:i,appBundleId:i}}},screenshot:async(t={})=>{let r=er(e.session,t.session);return{path:ei(await a("screenshot",t.path?[t.path]:[],t),"path"),identifiers:{session:r}}}}}}export{ec as createAgentDeviceClient,_ as sendToDaemon};
import{createRequestId as e,node_path as t,isAgentDeviceDaemonProcess as r,runCmdDetached as a,readVersion as n,findProjectRoot as o,node_https as i,runCmdSync as s,withDiagnosticTimer as d,resolveDaemonTransportPreference as l,emitDiagnostic as c,spawn as u,AppError as m,node_fs as p,resolveDaemonPaths as h,node_net as f,resolveDaemonServerMode as I,stopProcessForTakeover as w,node_http as A}from"./331.js";async function g(e){let{localPath:r,baseUrl:a,token:n}=e,o=p.statSync(r).isDirectory(),s=t.basename(r),d=new URL("upload",a.endsWith("/")?a:`${a}/`),l="https:"===d.protocol?i:A,c={"x-artifact-type":o?"app-bundle":"file","x-artifact-filename":s,"transfer-encoding":"chunked"};return n&&(c.authorization=`Bearer ${n}`,c["x-agent-device-token"]=n),new Promise((e,a)=>{let n=l.request({protocol:d.protocol,host:d.hostname,port:d.port,method:"POST",path:d.pathname+d.search,headers:c},t=>{let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{clearTimeout(i);try{let t=JSON.parse(r);if(!t.ok||!t.uploadId)return void a(new m("COMMAND_FAILED",`Upload failed: ${r}`));e(t.uploadId)}catch{a(new m("COMMAND_FAILED",`Invalid upload response: ${r}`))}})}),i=setTimeout(()=>{n.destroy(),a(new m("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(n.on("error",e=>{clearTimeout(i),a(new m("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),o){let e=u("tar",["cf","-","-C",t.dirname(r),t.basename(r)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(n),e.on("error",e=>{n.destroy(),a(new m("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(n.destroy(),a(new m("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=p.createReadStream(r);e.pipe(n),e.on("error",e=>{n.destroy(),a(new m("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}let D=function(e=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if(!e)return 9e4;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):9e4}(),v=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS){if(!e)return 15e3;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):15e3}(),y=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_ATTEMPTS){if(!e)return 2;let t=Number(e);return Number.isFinite(t)?Math.min(5,Math.max(1,Math.floor(t))):2}(),E=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"];async function P(t){let r=t.meta?.requestId??e(),a=!!(t.meta?.debug||t.flags?.verbose),n=function(e){let t=e.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR,r=function(e){let t;if(e){try{t=new URL(e)}catch(t){throw new m("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new m("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(e.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),a=e.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN,n=e.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,o=l(n);if(r&&"socket"===o)throw new m("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:r});let i=I(e.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===n?"dual":void 0));return{paths:h(t),transportPreference:o,serverMode:i,remoteBaseUrl:r,remoteAuthToken:a}}(t),o=await d("daemon_startup",async()=>await T(n),{requestId:r,session:t.session}),i=await _(t,o),s={...t,positionals:i.positionals,flags:i.flags,token:o.token,meta:{requestId:r,debug:a,cwd:t.meta?.cwd,tenantId:t.meta?.tenantId??t.flags?.tenant,runId:t.meta?.runId??t.flags?.runId,leaseId:t.meta?.leaseId??t.flags?.leaseId,sessionIsolation:t.meta?.sessionIsolation??t.flags?.sessionIsolation,lockPolicy:t.meta?.lockPolicy,lockPlatform:t.meta?.lockPlatform,...i.uploadedArtifactId?{uploadedArtifactId:i.uploadedArtifactId}:{},...i.clientArtifactPaths?{clientArtifactPaths:i.clientArtifactPaths}:{}}};return c({level:"info",phase:"daemon_request_prepare",data:{requestId:r,command:t.command,session:t.session}}),await d("daemon_request",async()=>await B(o,s,n.transportPreference),{requestId:r,command:t.command})}async function _(e,r){let a=[...e.positionals??[]],n=e.flags?{...e.flags}:void 0,o={};if(K(r)){let r=function(e,r){if("screenshot"===e.command){let t=M(e,"path",".png");return r[0]?{field:"path",localPath:t,positionalIndex:0,positionalPath:b("screenshot",".png")}:{field:"path",localPath:t,positionalIndex:0,flagPath:b("screenshot",".png")}}if("record"===e.command&&"start"===(r[0]??"").toLowerCase()){let r=M(e,"outPath",".mp4",1);return{field:"outPath",localPath:r,positionalIndex:1,positionalPath:b("recording",t.extname(r)||".mp4")}}return null}(e,a);r&&(void 0!==r.positionalPath&&(a[r.positionalIndex]=r.positionalPath),void 0!==r.flagPath&&((n??={}).out=r.flagPath),o[r.field]=r.localPath)}if(!K(r)||"install"!==e.command&&"reinstall"!==e.command||a.length<2)return{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}};let i=a[1];if(i.startsWith("remote:"))return a[1]=i.slice(7),{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}};let s=t.isAbsolute(i)?i:t.resolve(e.meta?.cwd??process.cwd(),i);return p.existsSync(s)?{positionals:a,flags:n,uploadedArtifactId:await g({localPath:s,baseUrl:r.baseUrl,token:r.token}),...Object.keys(o).length>0?{clientArtifactPaths:o}:{}}:{positionals:a,flags:n,...Object.keys(o).length>0?{clientArtifactPaths:o}:{}}}function M(e,r,a,n=0){let o=e.positionals?.[n]??e.flags?.out,i=`${"path"===r?"screenshot":"recording"}-${Date.now()}${a}`,s=o&&o.trim().length>0?o:i;return t.isAbsolute(s)?s:t.resolve(e.meta?.cwd??process.cwd(),s)}function b(e,r){let a=r.startsWith(".")?r:`.${r}`;return t.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${a}`)}async function T(e){let a;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await F(t,"http"))return t;throw new m("COMMAND_FAILED","Remote daemon is unavailable",{daemonBaseUrl:e.remoteBaseUrl,hint:"Verify AGENT_DEVICE_DAEMON_BASE_URL points to a reachable daemon with GET /health and POST /rpc."})}let i=R(e.paths.infoPath),s=n(),d=function(e,r=o()){try{let a=p.statSync(e),n=t.relative(r,e)||e;return`${n}:${a.size}:${Math.trunc(a.mtimeMs)}`}catch{return"unknown"}}((a=$()).useSrc?a.srcPath:a.distPath,a.root),l=!!i&&await F(i,e.transportPreference);if(i&&i.version===s&&i.codeSignature===d&&l)return i;i&&(i.version!==s||i.codeSignature!==d||!l)&&(await O(i),q(e.paths.infoPath)),function(e){let t=U(e);if(!t.hasLock||t.hasInfo)return;let a=C(e.lockPath);if(!a)return q(e.lockPath);r(a.pid,a.processStartTime)||q(e.lockPath)}(e.paths);let c=0;for(let t=1;t<=y;t+=1){await x(e);let r=await N(v,e);if(r)return r;if(await S(e.paths)){c+=1;continue}let a=U(e.paths);if(!(t<y))break;if(!a.hasInfo&&!a.hasLock){await k(150);continue}}let u=U(e.paths);throw new m("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:v,startupAttempts:y,lockRecoveryCount:c,metadataState:u,hint:function(e,t=h(process.env.AGENT_DEVICE_STATE_DIR)){return e.hasLock&&!e.hasInfo?`Detected ${t.lockPath} without ${t.infoPath}. If no agent-device daemon process is running, delete ${t.lockPath} and retry.`:e.hasLock&&e.hasInfo?`Daemon metadata may be stale. If no agent-device daemon process is running, delete ${t.infoPath} and ${t.lockPath}, then retry.`:`Daemon metadata is missing or stale. Delete ${t.infoPath} if present and retry.`}(u,e.paths)})}async function N(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=R(t.paths.infoPath);if(e&&await F(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function k(e){await new Promise(t=>setTimeout(t,e))}async function S(e){let t=U(e);if(!t.hasLock||t.hasInfo)return!1;let a=C(e.lockPath);return a&&r(a.pid,a.processStartTime)&&await w(a.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:a.processStartTime}),q(e.lockPath),!0}async function O(e){await w(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function R(e){let t=L(e);if(!t||"string"!=typeof t.token||0===t.token.length)return null;let r=Number.isInteger(t.port)&&Number(t.port)>0,a=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;return r||a?{...t,port:r?Number(t.port):void 0,httpPort:a?Number(t.httpPort):void 0,pid:Number.isInteger(t.pid)&&t.pid>0?t.pid:0}:null}function C(e){let t=L(e);return t&&Number.isInteger(t.pid)&&!(t.pid<=0)?t:null}function U(e){return{hasInfo:p.existsSync(e.infoPath),hasLock:p.existsSync(e.lockPath)}}function L(e){if(!p.existsSync(e))return null;try{return JSON.parse(p.readFileSync(e,"utf8"))}catch{return null}}function q(e){try{p.existsSync(e)&&p.unlinkSync(e)}catch{}}async function F(e,t){var r;return"http"===z(e,t)?await function(e){let t=e.baseUrl?J(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!t)return Promise.resolve(!1);let r=new URL(t),a="https:"===r.protocol?i:A,n=e.baseUrl?3e3:500;return new Promise(e=>{let t=a.request({protocol:r.protocol,host:r.hostname,port:r.port,path:r.pathname+r.search,method:"GET",timeout:n},t=>{t.resume(),e((t.statusCode??500)<500)});t.on("timeout",()=>{t.destroy(),e(!1)}),t.on("error",()=>{e(!1)}),t.end()})}(e):await ((r=e.port)?new Promise(e=>{let t=f.createConnection({host:"127.0.0.1",port:r},()=>{t.destroy(),e(!0)});t.on("error",()=>{e(!1)})}):Promise.resolve(!1))}async function x(e){let t=$(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],n={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};a(process.execPath,r,{env:n})}function $(){let e=o(),r=t.join(e,"dist","src","daemon.js"),a=t.join(e,"src","daemon.ts"),n=p.existsSync(r),i=p.existsSync(a);if(!n&&!i)throw new m("COMMAND_FAILED","Daemon entry not found",{distPath:r,srcPath:a});return{root:e,distPath:r,srcPath:a,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!n&&i}}async function B(e,t,r){return"http"===z(e,r)?await V(e,t):await G(e,t)}function z(e,t){if(e.baseUrl){if("socket"===t)throw new m("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t){if(!e.httpPort)throw new m("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");return"http"}if("socket"===t){if(!e.port)throw new m("COMMAND_FAILED","Daemon socket endpoint is unavailable");return"socket"}let r=e.transport;if("http"===r&&e.httpPort)return"http";if(("socket"===r||"dual"===r)&&e.port)return"socket";if(e.httpPort)return"http";if(e.port)return"socket";throw new m("COMMAND_FAILED","Daemon metadata has no reachable transport")}async function G(e,t){let r=e.port;if(!r)throw new m("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((a,n)=>{let o=f.createConnection({host:"127.0.0.1",port:r},()=>{o.write(`${JSON.stringify(t)}
`)}),i=setTimeout(()=>{o.destroy();let r=j(),a=H(e,h(t.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR));c({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:D,requestId:t.meta?.requestId,command:t.command,timedOutRunnerPidsTerminated:r.terminated,timedOutRunnerCleanupError:r.error,daemonPidReset:e.pid,daemonPidForceKilled:a.forcedKill}}),n(new m("COMMAND_FAILED","Daemon request timed out",{timeoutMs:D,requestId:t.meta?.requestId,hint:"Retry with --debug and check daemon diagnostics logs. Timed-out iOS runner xcodebuild processes were terminated when detected."}))},D),s="";o.setEncoding("utf8"),o.on("data",e=>{let r=(s+=e).indexOf("\n");if(-1===r)return;let d=s.slice(0,r).trim();if(d)try{let e=JSON.parse(d);o.end(),clearTimeout(i),a(e)}catch(e){clearTimeout(i),n(new m("COMMAND_FAILED","Invalid daemon response",{requestId:t.meta?.requestId,line:d},e instanceof Error?e:void 0))}}),o.on("error",e=>{clearTimeout(i),c({level:"error",phase:"daemon_request_socket_error",data:{requestId:t.meta?.requestId,message:e instanceof Error?e.message:String(e)}}),n(new m("COMMAND_FAILED","Failed to communicate with daemon",{requestId:t.meta?.requestId,hint:"Retry command. If this persists, clean stale daemon metadata and start a fresh session."},e))})})}async function V(t,r){let a=t.baseUrl?new URL(J(t.baseUrl,"rpc")):t.httpPort?new URL(`http://127.0.0.1:${t.httpPort}/rpc`):null;if(!a)throw new m("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let n=JSON.stringify({jsonrpc:"2.0",id:r.meta?.requestId??e(),method:"agent_device.command",params:r}),o={"content-type":"application/json","content-length":Buffer.byteLength(n)};return t.baseUrl&&t.token&&(o.authorization=`Bearer ${t.token}`,o["x-agent-device-token"]=t.token),await new Promise((e,s)=>{let d=h(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),l=("https:"===a.protocol?i:A).request({protocol:a.protocol,host:a.hostname,port:a.port,method:"POST",path:a.pathname+a.search,headers:o},a=>{let n="";a.setEncoding("utf8"),a.on("data",e=>{n+=e}),a.on("end",()=>{clearTimeout(u);try{let a=JSON.parse(n);if(a.error){let e=a.error.data??{};s(new m(String(e.code??"COMMAND_FAILED"),String(e.message??a.error.message??"Daemon RPC request failed"),{..."object"==typeof e.details&&e.details?e.details:{},hint:"string"==typeof e.hint?e.hint:void 0,diagnosticId:"string"==typeof e.diagnosticId?e.diagnosticId:void 0,logPath:"string"==typeof e.logPath?e.logPath:void 0,requestId:r.meta?.requestId}));return}if(!a.result||"object"!=typeof a.result)return void s(new m("COMMAND_FAILED","Invalid daemon RPC response",{requestId:r.meta?.requestId}));if(t.baseUrl&&a.result.ok)return void W(t,r,a.result).then(e).catch(s);e(a.result)}catch(e){clearTimeout(u),s(new m("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:n},e instanceof Error?e:void 0))}})}),u=setTimeout(()=>{l.destroy();let e=K(t)?{terminated:0}:j(),a=K(t)?{forcedKill:!1}:H(t,d);c({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:D,requestId:r.meta?.requestId,command:r.command,timedOutRunnerPidsTerminated:e.terminated,timedOutRunnerCleanupError:e.error,daemonPidReset:K(t)?void 0:t.pid,daemonPidForceKilled:K(t)?void 0:a.forcedKill,daemonBaseUrl:t.baseUrl}}),s(new m("COMMAND_FAILED","Daemon request timed out",{timeoutMs:D,requestId:r.meta?.requestId,hint:K(t)?"Retry with --debug and verify the remote daemon URL, auth token, and remote host logs.":"Retry with --debug and check daemon diagnostics logs. Timed-out iOS runner xcodebuild processes were terminated when detected."}))},D);l.on("error",e=>{clearTimeout(u),c({level:"error",phase:"daemon_request_socket_error",data:{requestId:r.meta?.requestId,message:e instanceof Error?e.message:String(e)}}),s(new m("COMMAND_FAILED","Failed to communicate with daemon",{requestId:r.meta?.requestId,hint:K(t)?"Retry command. If this persists, verify the remote daemon URL, auth token, and remote host reachability.":"Retry command. If this persists, clean stale daemon metadata and start a fresh session."},e))}),l.write(n),l.end()})}function j(){let e=0;try{for(let t of E){let r=s("pkill",["-f",t],{allowFailure:!0});0===r.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}function H(e,t){let a=!1;try{r(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),a=!0)}catch{w(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{q(t.infoPath),q(t.lockPath)}return{forcedKill:a}}function K(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function J(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function W(e,r,a){let n=Array.isArray(a.data?.artifacts)?a.data.artifacts:[];if(0===n.length||!e.baseUrl)return a;let o=a.data?{...a.data}:{},i=[];for(let a of n){if(!a||"object"!=typeof a||"string"!=typeof a.artifactId){i.push(a);continue}let n=function(e,r){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let a=e.fileName?.trim()||`${e.field}-${Date.now()}`;return t.resolve(r.meta?.cwd??process.cwd(),a)}(a,r);await Q({baseUrl:e.baseUrl,token:e.token,artifactId:a.artifactId,destinationPath:n,requestId:r.meta?.requestId}),o[a.field]=n,i.push({...a,localPath:n})}return o.artifacts=i,{ok:!0,data:o}}async function Q(e){var r,a;let n,o=new URL((r=e.baseUrl,a=e.artifactId,n=r.endsWith("/")?r:`${r}/`,new URL(`upload/${encodeURIComponent(a)}`,n).toString())),s="https:"===o.protocol?i:A;await p.promises.mkdir(t.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let a=!1,n=e.timeoutMs??D,i=n=>{if(!a){if(a=!0,clearTimeout(l),n)return void p.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(n));t()}},d=s.request({protocol:o.protocol,host:o.hostname,port:o.port,method:"GET",path:o.pathname+o.search,headers:e.token?{authorization:`Bearer ${e.token}`,"x-agent-device-token":e.token}:void 0},t=>{if((t.statusCode??500)>=400){let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=p.createWriteStream(e.destinationPath);r.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("aborted",()=>{i(new m("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),l=setTimeout(()=>{d.destroy(new m("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n}))},n);d.on("error",t=>{t instanceof m?i(t):i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n},t instanceof Error?t:void 0))}),d.end()})}function X(e,t){let r=es(e,"bundleId"),a=es(e,"package"),n=r??a;return{app:ei(e,"app"),appPath:ei(e,"appPath"),platform:el(e,"platform"),appId:n,bundleId:r,package:a,identifiers:{session:t,appId:n,appBundleId:r,package:a}}}function Y(e,t){return{session:t,configured:!0===e.configured,cleared:!0===e.cleared||void 0,runtime:et(e.runtime),identifiers:{session:t}}}function Z(e){let t=en(e),r=el(t,"platform"),a=ei(t,"id");return{platform:r,target:ec(t,"target"),kind:function(e,t){let r=e[t];if("simulator"===r||"emulator"===r||"device"===r)return r;throw new m("COMMAND_FAILED",`Daemon response has invalid "${t}".`,{response:e})}(t,"kind"),id:a,name:ei(t,"name"),booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:{deviceId:a,deviceName:ei(t,"name"),..."ios"===r?{udid:a}:{serial:a}},ios:"ios"===r?{udid:a}:void 0,android:"android"===r?{serial:a}:void 0}}function ee(e){let t=en(e),r=el(t,"platform"),a=ei(t,"id"),n=ei(t,"name"),o=ec(t,"target"),i=ei(t,"device"),s={session:n,deviceId:a,deviceName:i,..."ios"===r?{udid:a}:{serial:a}};return{name:n,createdAt:function(e,t){let r=e[t];if("number"!=typeof r||!Number.isFinite(r))throw new m("COMMAND_FAILED",`Daemon response is missing numeric "${t}".`,{response:e});return r}(t,"createdAt"),device:{platform:r,target:o,id:a,name:i,identifiers:s,ios:"ios"===r?{udid:a,simulatorSetPath:ed(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:a}:void 0},identifiers:s}}function et(e){if(!eo(e))return;let t=e.platform,r=es(e,"metroHost"),a="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:a,bundleUrl:es(e,"bundleUrl"),launchUrl:es(e,"launchUrl")}}function er(e,t){return t??e??"default"}function ea(e){let t={};for(let[r,a]of Object.entries(e))void 0!==a&&(t[r]=a);return t}function en(e){if(!eo(e))throw new m("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eo(e){return"object"==typeof e&&null!==e}function ei(e,t){let r=e[t];if("string"!=typeof r||0===r.length)throw new m("COMMAND_FAILED",`Daemon response is missing "${t}".`,{response:e});return r}function es(e,t){let r=e[t];return"string"==typeof r&&r.length>0?r:void 0}function ed(e,t){let r=e[t];return null===r?null:"string"==typeof r&&r.length>0?r:void 0}function el(e,t){let r=e[t];if("ios"===r||"android"===r)return r;throw new m("COMMAND_FAILED",`Daemon response has invalid "${t}".`,{response:e})}function ec(e,t){return"tv"===e[t]?"tv":"mobile"}function eu(e={},t={}){let r=t.transport??P,a=async(t,a=[],n={})=>{let o={...e,...n},i=await r({session:er(e.session,n.session),command:t,positionals:a,flags:ea({stateDir:o.stateDir,daemonBaseUrl:o.daemonBaseUrl,daemonAuthToken:o.daemonAuthToken,daemonTransport:o.daemonTransport,daemonServerMode:o.daemonServerMode,tenant:o.tenant,sessionIsolation:o.sessionIsolation,runId:o.runId,leaseId:o.leaseId,platform:o.platform,target:o.target,device:o.device,udid:o.udid,serial:o.serial,iosSimulatorDeviceSet:o.iosSimulatorDeviceSet,androidDeviceAllowlist:o.androidDeviceAllowlist,runtime:o.simulatorRuntimeId,boot:o.boot,reuseExisting:o.reuseExisting,activity:o.activity,relaunch:o.relaunch,shutdown:o.shutdown,saveScript:o.saveScript,noRecord:o.noRecord,metroHost:o.metroHost,metroPort:o.metroPort,bundleUrl:o.bundleUrl,launchUrl:o.launchUrl,snapshotInteractiveOnly:o.interactiveOnly,snapshotCompact:o.compact,snapshotDepth:o.depth,snapshotScope:o.scope,snapshotRaw:o.raw,verbose:o.debug}),runtime:o.runtime,meta:ea({requestId:o.requestId,cwd:o.cwd,debug:o.debug,lockPolicy:o.lockPolicy,lockPlatform:o.lockPlatform,tenantId:o.tenant,runId:o.runId,leaseId:o.leaseId,sessionIsolation:o.sessionIsolation,installSource:o.installSource,retainMaterializedPaths:o.retainMaterializedPaths,materializedPathRetentionMs:o.materializedPathRetentionMs,materializationId:o.materializationId})});if(!i.ok)throw new m(i.error.code,i.error.message,{...i.error.details??{},hint:i.error.hint,diagnosticId:i.error.diagnosticId,logPath:i.error.logPath});return i.data??{}},n=async(e={})=>{let t=await a("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(ee)};return{devices:{list:async(e={})=>{let t=await a("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(Z)}},sessions:{list:async(e={})=>await n(e),close:async(t={})=>{let r=er(e.session,t.session),n=(await a("close",[],t)).shutdown;return{session:r,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,n=await a("ensure-simulator",[],{...r,simulatorRuntimeId:t}),o=ei(n,"udid"),i=ei(n,"device");return{udid:o,device:i,runtime:ei(n,"runtime"),created:!0===n.created,booted:!0===n.booted,iosSimulatorDeviceSet:ed(n,"ios_simulator_device_set"),identifiers:{deviceId:o,deviceName:i,udid:o}}}},apps:{install:async t=>X(await a("install",[t.app,t.appPath],t),er(e.session,t.session)),reinstall:async t=>X(await a("reinstall",[t.app,t.appPath],t),er(e.session,t.session)),installFromSource:async t=>{var r,n;let o,i,s;return r=await a("install_source",[],{...t,installSource:t.source,retainMaterializedPaths:t.retainPaths,materializedPathRetentionMs:t.retentionMs}),n=er(e.session,t.session),o=es(r,"bundleId"),i=es(r,"packageName"),s=o??i,{appName:es(r,"appName"),appId:s,bundleId:o,packageName:i,launchTarget:ei(r,"launchTarget"),installablePath:es(r,"installablePath"),archivePath:es(r,"archivePath"),materializationId:es(r,"materializationId"),materializationExpiresAt:es(r,"materializationExpiresAt"),identifiers:{session:n,appId:s,appBundleId:o,package:i}}},open:async t=>{let r=er(e.session,t.session),n=t.url?[t.app,t.url]:[t.app],o=await a("open",n,t),i=function(e){let t=e.platform,r=es(e,"id"),a=es(e,"device");if("ios"!==t&&"android"!==t||!r||!a)return;let n=ec(e,"target"),o={deviceId:r,deviceName:a,..."ios"===t?{udid:r}:{serial:r}};return{platform:t,target:n,id:r,name:a,identifiers:o,ios:"ios"===t?{udid:es(e,"device_udid")??r,simulatorSetPath:ed(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:es(e,"serial")??r}:void 0}}(o),s=es(o,"appBundleId");return{session:r,appName:es(o,"appName"),appBundleId:s,appId:s,startup:function(e){if(eo(e)&&"number"==typeof e.durationMs&&"string"==typeof e.measuredAt&&"string"==typeof e.method)return{durationMs:e.durationMs,measuredAt:e.measuredAt,method:e.method,appTarget:es(e,"appTarget"),appBundleId:es(e,"appBundleId")}}(o.startup),runtime:et(o.runtime),device:i,identifiers:{session:r,deviceId:i?.id,deviceName:i?.name,udid:i?.ios?.udid,serial:i?.android?.serial,appId:s,appBundleId:s}}},close:async(t={})=>{let r=er(e.session,t.session),n=(await a("close",t.app?[t.app]:[],t)).shutdown;return{session:r,closedApp:t.app,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},materializations:{release:async e=>{var t;return{released:!0===(t=await a("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:ei(t,"materializationId"),identifiers:{}}}},runtime:{set:async t=>Y(await a("runtime",["set"],t),er(e.session,t.session)),show:async(t={})=>Y(await a("runtime",["show"],t),er(e.session,t.session))},capture:{snapshot:async(t={})=>{var r;let n=er(e.session,t.session),o=await a("snapshot",[],t),i=es(o,"appBundleId");return{nodes:Array.isArray(r=o.nodes)?r:[],truncated:!0===o.truncated,appName:es(o,"appName"),appBundleId:i,identifiers:{session:n,appId:i,appBundleId:i}}},screenshot:async(t={})=>{let r=er(e.session,t.session);return{path:ei(await a("screenshot",t.path?[t.path]:[],t),"path"),identifiers:{session:r}}}}}}export{eu as createAgentDeviceClient,P as sendToDaemon};

@@ -1,11 +0,11 @@

import{formatSnapshotLine as e,SETTINGS_USAGE_OVERRIDE as t,styleText as s,parseBatchStepsJson as a,buildSnapshotDisplayLines as i}from"./274.js";import{createRequestId as o,asAppError as r,normalizeError as n,pathToFileURL as l,AppError as p,readVersion as d,node_fs as u,withDiagnosticsScope as c,getDiagnosticsMeta as g,flushDiagnosticsToSessionFile as m,resolveDaemonPaths as f,emitDiagnostic as h}from"./331.js";import{createAgentDeviceClient as y,sendToDaemon as v}from"./224.js";let w=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],b=["snapshotDepth","snapshotScope","snapshotRaw"],$=[{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:"platform",names:["--platform"],type:"enum",enumValues:["ios","android","apple"],usageLabel:"--platform ios|android|apple",usageDescription:"Platform to target (`apple` aliases the iOS/tvOS backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv"],usageLabel:"--target mobile|tv",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:"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:"runtime set: session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"runtime set: session-scoped Metro/debug port hint"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"runtime set: session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"runtime set: 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:"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:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{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:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{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:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{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:"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:"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:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"}],k=new Set(["json","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),A={boot:{description:"Ensure target device/simulator is booted and ready",positionalArgs:[],allowedFlags:["headless"]},open:{description:"Boot device/simulator; optionally launch app or deep link URL",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","saveScript","relaunch"]},close:{description:"Close app or just end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},reinstall:{description:"Uninstall + install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},install:{description:"Install app from binary path without uninstalling first",positionalArgs:["app","path"],allowedFlags:[]},push:{description:"Simulate push notification payload delivery",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},snapshot:{description:"Capture accessibility tree",positionalArgs:[],allowedFlags:[...w]},diff:{usageOverride:"diff snapshot",description:"Diff current accessibility snapshot against previous baseline",positionalArgs:["kind"],allowedFlags:[...w]},"ensure-simulator":{description:"Ensure an iOS simulator exists in a device set (create if missing)",positionalArgs:[],allowedFlags:["runtime","boot","reuseExisting"],skipCapabilityCheck:!0},devices:{description:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},apps:{description:"List installed apps (includes default/system apps by default)",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:"all"}},appstate:{description:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},runtime:{usageOverride:"runtime set|show|clear",description:"Manage session-scoped runtime hints",positionalArgs:["set|show|clear"],allowedFlags:["metroHost","metroPort","bundleUrl","launchUrl"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",description:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",description:"Inspect Android keyboard visibility/type or dismiss it",positionalArgs:["action?"],allowedFlags:[]},perf:{description:"Show session performance metrics (startup timing)",positionalArgs:[],allowedFlags:[]},back:{description:"Navigate back (where supported)",positionalArgs:[],allowedFlags:[]},home:{description:"Go to home screen (where supported)",positionalArgs:[],allowedFlags:[]},"app-switcher":{description:"Open app switcher (where supported)",positionalArgs:[],allowedFlags:[]},wait:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",description:"Wait for duration, text, ref, or selector to appear",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...b]},alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",description:"Inspect or handle alert (iOS simulator)",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",description:"Tap/click by coordinates, snapshot ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...b]},get:{usageOverride:"get text|attrs <@ref|selector>",description:"Return element text/attributes by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...b]},replay:{description:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",description:"Execute multiple commands in one daemon request",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",description:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...b]},longpress:{description:"Long press by coordinates (iOS and Android)",positionalArgs:["x","y","durationMs?"],allowedFlags:[]},swipe:{description:"Swipe coordinates with optional repeat pattern",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{description:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},type:{description:"Type text in focused field",positionalArgs:["text"],allowsExtraPositionals:!0,allowedFlags:[]},fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",description:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...b]},scroll:{description:"Scroll in direction (0-1 amount)",positionalArgs:["direction","amount?"],allowedFlags:[]},scrollintoview:{usageOverride:"scrollintoview <text|@ref>",description:"Scroll until text appears or a snapshot ref is brought into view",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:[]},pinch:{description:"Pinch/zoom gesture (iOS simulator)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},screenshot:{description:"Capture screenshot",positionalArgs:["path?"],allowedFlags:["out"]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",description:"Trigger app-defined event hook via deep link template",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] | record stop",description:"Start/stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps"]},trace:{usageOverride:"trace start [path] | trace stop [path]",description:"Start/stop trace log capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",description:"Session app log info, start/stop streaming, diagnostics, and markers",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] | network log [limit] [summary|headers|body|all]",description:"Dump recent HTTP(s) traffic parsed from the session app log",positionalArgs:["dump|log","limit?","include?"],allowedFlags:[]},find:{usageOverride:"find <locator|text> <action> [value]",description:"Find by text/label/value/role/id and run action",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw"]},is:{description:"Assert UI state (visible|hidden|exists|editable|selected|text)",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...b]},settings:{usageOverride:t,description:"Toggle OS settings, appearance, and app permissions (session app scope for permission actions)",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",description:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},S=new Map,D=new Map;for(let e of $){for(let t of e.names)S.set(t,e);let t=D.get(e.key);t?t.push(e):D.set(e.key,[e])}function x(e){if(e)return A[e]}function I(e){let t=e.endsWith("?"),s=t?e.slice(0,-1):e;return t?`[${s}]`:`<${s}>`}function L(e,t){return t.usageOverride?t.usageOverride:[e,...t.positionalArgs.map(I),...t.allowedFlags.flatMap(e=>(D.get(e)??[]).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`)].join(" ")}let F=function(){let e=`agent-device <command> [args] [--json]
import{formatSnapshotLine as e,SETTINGS_USAGE_OVERRIDE as t,styleText as s,parseBatchStepsJson as o,buildSnapshotDisplayLines as i}from"./274.js";import{createRequestId as a,node_path as r,asAppError as n,normalizeError as l,pathToFileURL as p,AppError as d,node_fs as u,node_os as c,readVersion as g,withDiagnosticsScope as m,getDiagnosticsMeta as f,flushDiagnosticsToSessionFile as h,resolveDaemonPaths as y,emitDiagnostic as v}from"./331.js";import{createAgentDeviceClient as w,sendToDaemon as b}from"./224.js";let k=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],$=["snapshotDepth","snapshotScope","snapshotRaw"],S=[{key:"config",names:["--config"],type:"string",usageLabel:"--config <path>",usageDescription:"Load CLI defaults from a specific config 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:"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","android","apple"],usageLabel:"--platform ios|android|apple",usageDescription:"Platform to target (`apple` aliases the iOS/tvOS backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv"],usageLabel:"--target mobile|tv",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:"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:"runtime set: session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"runtime set: session-scoped Metro/debug port hint"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"runtime set: session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"runtime set: 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:"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:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{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:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{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:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{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:"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:"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:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"}],A=new Set(["json","config","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","sessionLock","sessionLocked","sessionLockConflicts","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),I={boot:{description:"Ensure target device/simulator is booted and ready",positionalArgs:[],allowedFlags:["headless"]},open:{description:"Boot device/simulator; optionally launch app or deep link URL",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","saveScript","relaunch"]},close:{description:"Close app or just end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},reinstall:{description:"Uninstall + install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},install:{description:"Install app from binary path without uninstalling first",positionalArgs:["app","path"],allowedFlags:[]},push:{description:"Simulate push notification payload delivery",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},snapshot:{description:"Capture accessibility tree",positionalArgs:[],allowedFlags:[...k]},diff:{usageOverride:"diff snapshot",description:"Diff current accessibility snapshot against previous baseline",positionalArgs:["kind"],allowedFlags:[...k]},"ensure-simulator":{description:"Ensure an iOS simulator exists in a device set (create if missing)",positionalArgs:[],allowedFlags:["runtime","boot","reuseExisting"],skipCapabilityCheck:!0},devices:{description:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},apps:{description:"List installed apps (includes default/system apps by default)",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:"all"}},appstate:{description:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},runtime:{usageOverride:"runtime set|show|clear",description:"Manage session-scoped runtime hints",positionalArgs:["set|show|clear"],allowedFlags:["metroHost","metroPort","bundleUrl","launchUrl"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",description:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",description:"Inspect Android keyboard visibility/type or dismiss it",positionalArgs:["action?"],allowedFlags:[]},perf:{description:"Show session performance metrics (startup timing)",positionalArgs:[],allowedFlags:[]},back:{description:"Navigate back (where supported)",positionalArgs:[],allowedFlags:[]},home:{description:"Go to home screen (where supported)",positionalArgs:[],allowedFlags:[]},"app-switcher":{description:"Open app switcher (where supported)",positionalArgs:[],allowedFlags:[]},wait:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",description:"Wait for duration, text, ref, or selector to appear",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...$]},alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",description:"Inspect or handle alert (iOS simulator)",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",description:"Tap/click by coordinates, snapshot ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...$]},get:{usageOverride:"get text|attrs <@ref|selector>",description:"Return element text/attributes by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...$]},replay:{description:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",description:"Execute multiple commands in one daemon request",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",description:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...$]},longpress:{description:"Long press by coordinates (iOS and Android)",positionalArgs:["x","y","durationMs?"],allowedFlags:[]},swipe:{description:"Swipe coordinates with optional repeat pattern",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{description:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},type:{description:"Type text in focused field",positionalArgs:["text"],allowsExtraPositionals:!0,allowedFlags:[]},fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",description:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...$]},scroll:{description:"Scroll in direction (0-1 amount)",positionalArgs:["direction","amount?"],allowedFlags:[]},scrollintoview:{usageOverride:"scrollintoview <text|@ref>",description:"Scroll until text appears or a snapshot ref is brought into view",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:[]},pinch:{description:"Pinch/zoom gesture (iOS simulator)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},screenshot:{description:"Capture screenshot",positionalArgs:["path?"],allowedFlags:["out"]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",description:"Trigger app-defined event hook via deep link template",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] | record stop",description:"Start/stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps"]},trace:{usageOverride:"trace start [path] | trace stop [path]",description:"Start/stop trace log capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",description:"Session app log info, start/stop streaming, diagnostics, and markers",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] | network log [limit] [summary|headers|body|all]",description:"Dump recent HTTP(s) traffic parsed from the session app log",positionalArgs:["dump|log","limit?","include?"],allowedFlags:[]},find:{usageOverride:"find <locator|text> <action> [value]",description:"Find by text/label/value/role/id and run action",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw"]},is:{description:"Assert UI state (visible|hidden|exists|editable|selected|text)",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...$]},settings:{usageOverride:t,description:"Toggle OS settings, appearance, and app permissions (session app scope for permission actions)",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",description:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},D=new Map,L=new Map;for(let e of S){for(let t of e.names)D.set(t,e);let t=L.get(e.key);t?t.push(e):L.set(e.key,[e])}function x(e){if(e)return I[e]}function O(){return Object.keys(I)}function N(e){let t=e.endsWith("?"),s=t?e.slice(0,-1):e;return t?`[${s}]`:`<${s}>`}function _(e,t){return t.usageOverride?t.usageOverride:[e,...t.positionalArgs.map(N),...t.allowedFlags.flatMap(e=>(L.get(e)??[]).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`)].join(" ")}let F=function(){let e=`agent-device <command> [args] [--json]
CLI to control iOS and Android devices for AI agents.
`,t=Object.keys(A).map(e=>{let t=A[e];if(!t)throw Error(`Missing command schema for ${e}`);return{name:e,schema:t,usage:L(e,t)}}),s=Math.max(...t.map(e=>e.usage.length))+2,a=["Commands:"];for(let e of t)a.push(` ${e.usage.padEnd(s)}${e.schema.description}`);let i=N("Flags:",$.filter(e=>e.usageLabel&&e.usageDescription));return`${e}
${a.join("\n")}
`,t=O().map(e=>{let t=I[e];if(!t)throw Error(`Missing command schema for ${e}`);return{name:e,schema:t,usage:_(e,t)}}),s=Math.max(...t.map(e=>e.usage.length))+2,o=["Commands:"];for(let e of t)o.push(` ${e.usage.padEnd(s)}${e.schema.description}`);let i=C("Flags:",S.filter(e=>e.usageLabel&&e.usageDescription));return`${e}
${o.join("\n")}
${i}
`}();function O(e){return $.filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function N(e,t){if(0===t.length)return`${e}
(none)`;let s=Math.max(...t.map(e=>(e.usageLabel??"").length))+2,a=[e];for(let e of t)a.push(` ${(e.usageLabel??"").padEnd(s)}${e.usageDescription??""}`);return a.join("\n")}function _(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function R(e){return e.replace(/^-+/,"")}function j(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?_(e):[e,void 0];return void 0!==S.get(t)}function E(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}function C(e){process.stdout.write(`${JSON.stringify(e,null,2)}
`)}function P(e,t={}){let s=e instanceof p?n(e):e;process.stderr.write(`Error (${s.code}): ${s.message}
`}();function E(e){return S.filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function C(e,t){if(0===t.length)return`${e}
(none)`;let s=Math.max(...t.map(e=>(e.usageLabel??"").length))+2,o=[e];for(let e of t)o.push(` ${(e.usageLabel??"").padEnd(s)}${e.usageDescription??""}`);return o.join("\n")}let j=new Set(["config","help","version","batchSteps"]),R={iosSimulatorDeviceSet:["IOS_SIMULATOR_DEVICE_SET"],androidDeviceAllowlist:["ANDROID_DEVICE_ALLOWLIST"]},P=new Set(["1","true","yes","on"]),V=new Set(["0","false","no","off"]),T=function(){let e=new Map;for(let t of S){let s=e.get(t.key);s?s.push(t):e.set(t.key,[t])}let t=new Map;for(let e of A)t.set(e,new Set(["*"]));for(let e of O()){let s=x(e);if(s)for(let o of s.allowedFlags){let s=t.get(o);s&&s.has("*")||(s?s.add(e):t.set(o,new Set([e])))}}return[...e.entries()].map(([e,s])=>{var o;return{key:e,flagDefinitions:s,config:{enabled:!j.has(e),key:e},env:{names:[(o=e,`AGENT_DEVICE_${o.replace(/([A-Z])/g,"_$1").replace(/[^A-Za-z0-9_]/g,"_").toUpperCase()}`),...R[e]??[]]},supportsCommand(s){let o=t.get(e);return!!o&&(!!o.has("*")||!!s&&o.has(s))}}}).sort((e,t)=>e.key.localeCompare(t.key))}(),G=new Map(T.map(e=>[e.key,e]));function M(e,t){return G.get(e)?.supportsCommand(t)??!1}function U(e,t,s,o){let i=function(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}(e);if("boolean"===i.type){var a=t,r=s,n=o;if("boolean"==typeof a)return a;if("string"==typeof a){let e=B(a);if(void 0!==e)return e}throw new d("INVALID_ARGS",`Invalid value for "${n}" in ${r}. Expected boolean.`)}if("booleanOrString"===i.type){if("boolean"==typeof t)return t;if("string"==typeof t&&void 0!==B(t))return B(t);if("string"==typeof t&&t.trim().length>0)return t;throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Expected boolean or non-empty string.`)}if("string"===i.type){if("string"==typeof t&&t.trim().length>0)return t;throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Expected non-empty string.`)}if("enum"===i.type){if(void 0!==i.setValue){var l=i,p=t,u=s,c=o;let e=l.setValue;if(p===e)return e;if("string"==typeof p){let t=p.trim();if(""===t||"true"===t||"1"===t)return e;if("false"===t||"0"===t)return}if(!0===p)return e;if(!1!==p)throw new d("INVALID_ARGS",`Invalid value for "${c}" in ${u}. Expected boolean or ${String(e)}.`);return}if("string"!=typeof t||!i.enumValues?.includes(t))throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Expected one of: ${i.enumValues?.join(", ")}.`);return t}let g="number"==typeof t?t:"string"==typeof t?Number(t):NaN;if(!Number.isFinite(g)||!Number.isInteger(g))throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Expected integer.`);if("number"==typeof i.min&&g<i.min)throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Must be >= ${i.min}.`);if("number"==typeof i.max&&g>i.max)throw new d("INVALID_ARGS",`Invalid value for "${o}" in ${s}. Must be <= ${i.max}.`);return g}function B(e){let t=e.trim().toLowerCase();return!!P.has(t)||!V.has(t)&&void 0}function J(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function q(e){return e.replace(/^-+/,"")}function W(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?J(e):[e,void 0];return void 0!==D.get(t)}function H(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}function z(e,t){for(let[s,o]of Object.entries(t))void 0!==o&&(e[s]=o);return e}function K(e){process.stdout.write(`${JSON.stringify(e,null,2)}
`)}function Z(e,t={}){let s=e instanceof d?l(e):e;process.stderr.write(`Error (${s.code}): ${s.message}
`),s.hint&&process.stderr.write(`Hint: ${s.hint}

@@ -15,20 +15,20 @@ `),s.diagnosticId&&process.stderr.write(`Diagnostic ID: ${s.diagnosticId}

`),t.showDetails&&s.details&&process.stderr.write(`${JSON.stringify(s.details,null,2)}
`)}function T(t,s={}){let a=t.nodes,o=Array.isArray(a)?a:[],r=!!t.truncated,n="string"==typeof t.appName?t.appName:void 0,l="string"==typeof t.appBundleId?t.appBundleId:void 0,p=[];n&&p.push(`Page: ${n}`),l&&p.push(`App: ${l}`);let d=`Snapshot: ${o.length} nodes${r?" (truncated)":""}`,u=p.length>0?`${p.join("\n")}
`:"";if(0===o.length)return`${u}${d}
`;if(s.raw){let e=o.map(e=>JSON.stringify(e));return`${u}${d}
`)}function X(t,s={}){let o=t.nodes,a=Array.isArray(o)?o:[],r=!!t.truncated,n="string"==typeof t.appName?t.appName:void 0,l="string"==typeof t.appBundleId?t.appBundleId:void 0,p=[];n&&p.push(`Page: ${n}`),l&&p.push(`App: ${l}`);let d=`Snapshot: ${a.length} nodes${r?" (truncated)":""}`,u=p.length>0?`${p.join("\n")}
`:"";if(0===a.length)return`${u}${d}
`;if(s.raw){let e=a.map(e=>JSON.stringify(e));return`${u}${d}
${e.join("\n")}
`}if(s.flatten){let t=o.map(t=>e(t,0,!1));return`${u}${d}
`}if(s.flatten){let t=a.map(t=>e(t,0,!1));return`${u}${d}
${t.join("\n")}
`}let c=i(o).map(e=>e.text);return`${u}${d}
`}let c=i(a).map(e=>e.text);return`${u}${d}
${c.join("\n")}
`}function M(e){return"number"==typeof e&&Number.isFinite(e)?e:0}async function B(e){let t=V[e.command];return!!t&&await t(e)}let V={session:async({positionals:e,flags:t,client:s})=>{if("list"!==(e[0]??"list"))throw new p("INVALID_ARGS","session only supports list");let a={sessions:(await s.sessions.list()).map(W)};return t.json?C({success:!0,data:a}):process.stdout.write(`${JSON.stringify(a,null,2)}
`),!0},devices:async({flags:e,client:t})=>{let s=await t.devices.list(J(e)),a={devices:s.map(q)};return e.json?C({success:!0,data:a}):process.stdout.write(`${s.map(H).join("\n")}
`),!0},"ensure-simulator":async({flags:e,client:t})=>{var s;if(!e.device)throw new p("INVALID_ARGS","ensure-simulator requires --device <name>");let a=await t.simulators.ensure({device:e.device,runtime:e.runtime,boot:e.boot,reuseExisting:e.reuseExisting,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet}),i={udid:(s=a).udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:s.iosSimulatorDeviceSet??null,created:s.created,booted:s.booted};if(e.json)C({success:!0,data:i});else{let e=a.created?"Created":"Reused",t=a.booted?" (booted)":"";process.stdout.write(`${e}: ${a.device} ${a.udid}${t}
`),a.runtime&&process.stdout.write(`Runtime: ${a.runtime}
`)}return!0},runtime:async({positionals:e,flags:t,client:s})=>{let a=(e[0]??"show").toLowerCase();return"set"===a?(G(await s.runtime.set({platform:t.platform,metroHost:t.metroHost,metroPort:t.metroPort,bundleUrl:t.bundleUrl,launchUrl:t.launchUrl}),t),!0):"show"===a&&(G(await s.runtime.show(),t),!0)},install:async({positionals:e,flags:t,client:s})=>{let a=await U("install",e,t,s);return t.json&&C({success:!0,data:z(a)}),!0},reinstall:async({positionals:e,flags:t,client:s})=>{let a=await U("reinstall",e,t,s);return t.json&&C({success:!0,data:z(a)}),!0},open:async({positionals:e,flags:t,client:s})=>{var a;if(!e[0])return!1;let i=await s.apps.open({app:e[0],url:e[1],activity:t.activity,relaunch:t.relaunch,saveScript:t.saveScript,noRecord:t.noRecord,...J(t)});return t.json&&C({success:!0,data:{session:(a=i).session,...a.appName?{appName:a.appName}:{},...a.appBundleId?{appBundleId:a.appBundleId}:{},...a.startup?{startup:a.startup}:{},...a.runtime?{runtime:a.runtime}:{},...a.device?{platform:a.device.platform,target:a.device.target,device:a.device.name,id:a.device.id}:{},...a.device?.platform==="ios"?{device_udid:a.device.ios?.udid??a.device.id,ios_simulator_device_set:a.device.ios?.simulatorSetPath??null}:{},...a.device?.platform==="android"?{serial:a.device.android?.serial??a.device.id}:{}}}),!0},close:async({positionals:e,flags:t,client:s})=>{var a;let i=e[0]?await s.apps.close({app:e[0],shutdown:t.shutdown}):await s.sessions.close({shutdown:t.shutdown});return t.json&&C({success:!0,data:{session:(a=i).session,...a.shutdown?{shutdown:a.shutdown}:{}}}),!0},snapshot:async({flags:e,client:t})=>{var s;let a={nodes:(s=await t.capture.snapshot({...J(e),interactiveOnly:e.snapshotInteractiveOnly,compact:e.snapshotCompact,depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw})).nodes,truncated:s.truncated,...s.appName?{appName:s.appName}:{},...s.appBundleId?{appBundleId:s.appBundleId}:{}};return e.json?C({success:!0,data:a}):process.stdout.write(T(a,{raw:e.snapshotRaw,flatten:e.snapshotInteractiveOnly})),!0},screenshot:async({positionals:e,flags:t,client:s})=>{let a=await s.capture.screenshot({path:e[0]??t.out}),i={path:a.path};return t.json?C({success:!0,data:i}):process.stdout.write(`${a.path}
`),!0}};async function U(e,t,s,a){let i=t[0],o=t[1];if(!i||!o)throw new p("INVALID_ARGS",`${e} requires: ${e} <app> <path-to-app-binary>`);let r={app:i,appPath:o,...J(s)};return"install"===e?await a.apps.install(r):await a.apps.reinstall(r)}function G(e,t){var s;let a={session:(s=e).session,configured:s.configured,...s.cleared?{cleared:!0}:{},...s.runtime?{runtime:s.runtime}:{}};t.json?C({success:!0,data:a}):e.configured?process.stdout.write(`${JSON.stringify(e.runtime??{},null,2)}
`):process.stdout.write("No runtime hints configured\n")}function J(e){return{platform:e.platform,target:e.target,device:e.device,udid:e.udid,serial:e.serial,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet,androidDeviceAllowlist:e.androidDeviceAllowlist}}function W(e){return{name:e.name,platform:e.device.platform,target:e.device.target,device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.ios?.udid??e.device.id,ios_simulator_device_set:e.device.ios?.simulatorSetPath??null}}}function q(e){return{platform:e.platform,id:e.id,name:e.name,kind:e.kind,target:e.target,..."boolean"==typeof e.booted?{booted:e.booted}:{}}}function H(e){let t=e.kind?` ${e.kind}`:"",s=e.target?` target=${e.target}`:"",a="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${s})${a}`}function z(e){return{app:e.app,appPath:e.appPath,platform:e.platform,...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.package?{package:e.package}:{}}}let K={sendToDaemon:v};async function X(e,t=K){let i=o(),l=e.includes("--debug")||e.includes("--verbose")||e.includes("-v"),v=e.includes("--json"),w=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 c({session:w,requestId:i,command:e[0],debug:l},async()=>{var o,c;let w;try{w=function(e,t){let s=(void 0)??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),a={json:!1,help:!1,version:!1},i=null,o=[],r=[],n=[],l=!0;for(let t=0;t<e.length;t+=1){let s=e[t];if(l&&"--"===s){l=!1;continue}if(!l){i?o.push(s):i=E(s);continue}let r=s.startsWith("--"),d=s.startsWith("-")&&s.length>1;if(!r&&!d){i?o.push(s):i=E(s);continue}let[u,c]=r?_(s):[s,void 0],g=S.get(u);if(!g){if(function(e,t,s){var a;if(a=s,!/^-\d+(\.\d+)?$/.test(a)||!e)return!1;let i=x(e);return!i||!!i.allowsExtraPositionals||0!==i.positionalArgs.length&&(t.length<i.positionalArgs.length||i.positionalArgs.some(e=>e.includes("?")))}(i,o,s)){i?o.push(s):i=s;continue}throw new p("INVALID_ARGS",`Unknown flag: ${u}`)}let m=function(e,t,s,a){if(void 0!==e.setValue){if(void 0!==s)throw new p("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 p("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 p("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:s,consumeNext:!1}}return void 0===a||j(a)||!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("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let i=s??a;if(void 0===i||void 0===s&&j(i))throw new p("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:i,consumeNext:void 0===s};if("enum"===e.type){if(!e.enumValues?.includes(i))throw new p("INVALID_ARGS",`Invalid ${R(t)}: ${i}`);return{value:i,consumeNext:void 0===s}}let o=Number(i);if(!Number.isFinite(o)||"number"==typeof e.min&&o<e.min||"number"==typeof e.max&&o>e.max)throw new p("INVALID_ARGS",`Invalid ${R(t)}: ${i}`);return{value:Math.floor(o),consumeNext:void 0===s}}(g,u,c,e[t+1]);m.consumeNext&&(t+=1),a[g.key]=m.value,n.push({key:g.key,token:u})}let d=x(i),u=new Set([...k,...d?.allowedFlags??[]]),c=n.filter(e=>!u.has(e.key));if(c.length>0){var g,m;let e=(g=i,m=c.map(e=>e.token),g?1===m.length?`Flag ${m[0]} is not supported for command ${g}.`:`Flags ${m.join(", ")} are not supported for command ${g}.`:1===m.length?`Flag ${m[0]} requires a command that supports it.`:`Flags ${m.join(", ")} require a command that supports them.`);if(s)throw new p("INVALID_ARGS",e);for(let t of(r.push(`${e} Enable AGENT_DEVICE_STRICT_FLAGS=1 to fail fast.`),c))delete a[t.key]}if(d?.defaults)for(let[e,t]of Object.entries(d.defaults))void 0===a[e]&&(a[e]=t);if("batch"===i&&1!=+!!a.steps+ +!!a.stepsFile)throw new p("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return{command:i,positionals:o,flags:a,warnings:r}}(e)}catch(t){h({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=n(t,{diagnosticId:g().diagnosticId,logPath:m({force:!0})??void 0});v?C({success:!1,error:e}):P(e,{showDetails:l}),process.exit(1);return}for(let e of w.warnings)process.stderr.write(`Warning: ${e}
`);w.flags.version&&(process.stdout.write(`${d()}
`),process.exit(0));let b="help"===w.command,$=w.flags.help;if(b||$){b&&w.positionals.length>1&&(P(new p("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=b?w.positionals[0]:w.command;e||(process.stdout.write(`${F}
`),process.exit(0));let t=function(e){let t=x(e);if(!t)return null;let s=L(e,t),a=O(new Set(t.allowedFlags)),i=O(k),o=[];return a.length>0&&o.push(N("Command flags:",a)),o.push(N("Global flags:",i)),`agent-device ${s}
`}function Y(e){return"number"==typeof e&&Number.isFinite(e)?e:0}async function Q(e){let t=ee[e.command];return!!t&&await t(e)}let ee={session:async({positionals:e,flags:t,client:s})=>{if("list"!==(e[0]??"list"))throw new d("INVALID_ARGS","session only supports list");let o={sessions:(await s.sessions.list()).map(ei)};return t.json?K({success:!0,data:o}):process.stdout.write(`${JSON.stringify(o,null,2)}
`),!0},devices:async({flags:e,client:t})=>{let s=await t.devices.list(eo(e)),o={devices:s.map(ea)};return e.json?K({success:!0,data:o}):process.stdout.write(`${s.map(er).join("\n")}
`),!0},"ensure-simulator":async({flags:e,client:t})=>{var s;if(!e.device)throw new d("INVALID_ARGS","ensure-simulator requires --device <name>");let o=await t.simulators.ensure({device:e.device,runtime:e.runtime,boot:e.boot,reuseExisting:e.reuseExisting,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet}),i={udid:(s=o).udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:s.iosSimulatorDeviceSet??null,created:s.created,booted:s.booted};if(e.json)K({success:!0,data:i});else{let e=o.created?"Created":"Reused",t=o.booted?" (booted)":"";process.stdout.write(`${e}: ${o.device} ${o.udid}${t}
`),o.runtime&&process.stdout.write(`Runtime: ${o.runtime}
`)}return!0},runtime:async({positionals:e,flags:t,client:s})=>{let o=(e[0]??"show").toLowerCase();return"set"===o?(es(await s.runtime.set({platform:t.platform,metroHost:t.metroHost,metroPort:t.metroPort,bundleUrl:t.bundleUrl,launchUrl:t.launchUrl}),t),!0):"show"===o&&(es(await s.runtime.show(),t),!0)},install:async({positionals:e,flags:t,client:s})=>{let o=await et("install",e,t,s);return t.json&&K({success:!0,data:en(o)}),!0},reinstall:async({positionals:e,flags:t,client:s})=>{let o=await et("reinstall",e,t,s);return t.json&&K({success:!0,data:en(o)}),!0},open:async({positionals:e,flags:t,client:s})=>{var o;if(!e[0])return!1;let i=await s.apps.open({app:e[0],url:e[1],activity:t.activity,relaunch:t.relaunch,saveScript:t.saveScript,noRecord:t.noRecord,...eo(t)});return t.json&&K({success:!0,data:{session:(o=i).session,...o.appName?{appName:o.appName}:{},...o.appBundleId?{appBundleId:o.appBundleId}:{},...o.startup?{startup:o.startup}:{},...o.runtime?{runtime:o.runtime}:{},...o.device?{platform:o.device.platform,target:o.device.target,device:o.device.name,id:o.device.id}:{},...o.device?.platform==="ios"?{device_udid:o.device.ios?.udid??o.device.id,ios_simulator_device_set:o.device.ios?.simulatorSetPath??null}:{},...o.device?.platform==="android"?{serial:o.device.android?.serial??o.device.id}:{}}}),!0},close:async({positionals:e,flags:t,client:s})=>{var o;let i=e[0]?await s.apps.close({app:e[0],shutdown:t.shutdown}):await s.sessions.close({shutdown:t.shutdown});return t.json&&K({success:!0,data:{session:(o=i).session,...o.shutdown?{shutdown:o.shutdown}:{}}}),!0},snapshot:async({flags:e,client:t})=>{var s;let o={nodes:(s=await t.capture.snapshot({...eo(e),interactiveOnly:e.snapshotInteractiveOnly,compact:e.snapshotCompact,depth:e.snapshotDepth,scope:e.snapshotScope,raw:e.snapshotRaw})).nodes,truncated:s.truncated,...s.appName?{appName:s.appName}:{},...s.appBundleId?{appBundleId:s.appBundleId}:{}};return e.json?K({success:!0,data:o}):process.stdout.write(X(o,{raw:e.snapshotRaw,flatten:e.snapshotInteractiveOnly})),!0},screenshot:async({positionals:e,flags:t,client:s})=>{let o=await s.capture.screenshot({path:e[0]??t.out}),i={path:o.path};return t.json?K({success:!0,data:i}):process.stdout.write(`${o.path}
`),!0}};async function et(e,t,s,o){let i=t[0],a=t[1];if(!i||!a)throw new d("INVALID_ARGS",`${e} requires: ${e} <app> <path-to-app-binary>`);let r={app:i,appPath:a,...eo(s)};return"install"===e?await o.apps.install(r):await o.apps.reinstall(r)}function es(e,t){var s;let o={session:(s=e).session,configured:s.configured,...s.cleared?{cleared:!0}:{},...s.runtime?{runtime:s.runtime}:{}};t.json?K({success:!0,data:o}):e.configured?process.stdout.write(`${JSON.stringify(e.runtime??{},null,2)}
`):process.stdout.write("No runtime hints configured\n")}function eo(e){return{platform:e.platform,target:e.target,device:e.device,udid:e.udid,serial:e.serial,iosSimulatorDeviceSet:e.iosSimulatorDeviceSet,androidDeviceAllowlist:e.androidDeviceAllowlist}}function ei(e){return{name:e.name,platform:e.device.platform,target:e.device.target,device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.ios?.udid??e.device.id,ios_simulator_device_set:e.device.ios?.simulatorSetPath??null}}}function ea(e){return{platform:e.platform,id:e.id,name:e.name,kind:e.kind,target:e.target,..."boolean"==typeof e.booted?{booted:e.booted}:{}}}function er(e){let t=e.kind?` ${e.kind}`:"",s=e.target?` target=${e.target}`:"",o="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${s})${o}`}function en(e){return{app:e.app,appPath:e.appPath,platform:e.platform,...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.package?{package:e.package}:{}}}function el(e,t={}){let s=ep(t),o={...e};return s.defaultPlatform&&void 0===o.platform&&(o.platform=s.defaultPlatform),o}function ep(e){var t,s,o,i;let a,r=e.env??process.env,n=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 d("INVALID_ARGS",`Invalid AGENT_DEVICE_PLATFORM: ${e}. Use ios, android, or apple.`)}}(r.AGENT_DEVICE_PLATFORM),l="string"==typeof(t=e.configuredSession??r.AGENT_DEVICE_SESSION)&&t.trim().length>0;return{defaultPlatform:n,lockPolicy:(s=e.policyOverrides,o=r,i=l,(a=s?.sessionLock??s?.sessionLockConflicts??ed(o.AGENT_DEVICE_SESSION_LOCK)??ed(o.AGENT_DEVICE_SESSION_LOCK_CONFLICTS))||(s?.sessionLocked===!0||function(e){if(!e)return!1;switch(e.trim().toLowerCase()){case"1":case"true":case"yes":case"on":return!0;default:return!1}}(o.AGENT_DEVICE_SESSION_LOCKED)||i?"reject":void 0))}}function ed(e){if(void 0===e)return;let t=e.trim().toLowerCase();if(t){if("reject"===t||"strip"===t)return t;throw new d("INVALID_ARGS",`Invalid session lock mode: ${e}. Use reject or strip.`)}}function eu(e,t){for(let[s,o]of Object.entries(t))void 0!==o&&(e[s]=o);return e}let ec={sendToDaemon:b};async function eg(e,t=ec){let i=a(),p=e.includes("--debug")||e.includes("--verbose")||e.includes("-v"),b=e.includes("--json"),k=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 m({session:k,requestId:i,command:e[0],debug:p},async()=>{var a,m,k,$,S,I,L,O,N,j,R;let P;try{let t,s,o,i,n,l,p,g;a={cwd:process.cwd(),env:process.env},t=function(e){let t={json:!1,help:!1,version:!1},s=null,o=[],i=[],a=!0;for(let r=0;r<e.length;r+=1){let n=e[r];if(a&&"--"===n){a=!1;continue}if(!a){s?o.push(n):s=H(n);continue}let l=n.startsWith("--"),p=n.startsWith("-")&&n.length>1;if(!l&&!p){s?o.push(n):s=H(n);continue}let[u,c]=l?J(n):[n,void 0],g=D.get(u);if(!g){if(function(e,t,s){var o;if(o=s,!/^-\d+(\.\d+)?$/.test(o)||!e)return!1;let i=x(e);return!i||!!i.allowsExtraPositionals||0!==i.positionalArgs.length&&(t.length<i.positionalArgs.length||i.positionalArgs.some(e=>e.includes("?")))}(s,o,n)){s?o.push(n):s=n;continue}throw new d("INVALID_ARGS",`Unknown flag: ${u}`)}let m=function(e,t,s,o){if(void 0!==e.setValue){if(void 0!==s)throw new d("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 d("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 d("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:s,consumeNext:!1}}return void 0===o||W(o)||!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("\\"))}(o)?{value:!0,consumeNext:!1}:{value:o,consumeNext:!0}}let i=s??o;if(void 0===i||void 0===s&&W(i))throw new d("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:i,consumeNext:void 0===s};if("enum"===e.type){if(!e.enumValues?.includes(i))throw new d("INVALID_ARGS",`Invalid ${q(t)}: ${i}`);return{value:i,consumeNext:void 0===s}}let a=Number(i);if(!Number.isFinite(a)||"number"==typeof e.min&&a<e.min||"number"==typeof e.max&&a>e.max)throw new d("INVALID_ARGS",`Invalid ${q(t)}: ${i}`);return{value:Math.floor(a),consumeNext:void 0===s}}(g,u,c,e[r+1]);m.consumeNext&&(r+=1),t[g.key]=m.value,i.push({key:g.key,token:u})}return{command:s,positionals:o,flags:t,warnings:[],providedFlags:i}}(e),s=a?.env??process.env,o=a?.cwd??process.cwd(),i=(m={command:t.command,cwd:o,cliFlags:t.flags,env:s}).env??process.env,n=eu({},function(e){let t={};for(let s of e)eu(t,function(e,t){let s,o;if(!u.existsSync(e)){if(t)throw new d("INVALID_ARGS",`Config file not found: ${e}`);return{}}try{s=u.readFileSync(e,"utf8")}catch(t){throw new d("INVALID_ARGS",`Failed to read config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}try{o=JSON.parse(s)}catch(t){throw new d("INVALID_ARGS",`Invalid JSON in config file: ${e}`,{cause:t instanceof Error?t.message:String(t)})}if(!o||"object"!=typeof o||Array.isArray(o))throw new d("INVALID_ARGS",`Config file must contain a JSON object: ${e}`);return function(e,t){let s={};for(let[o,i]of Object.entries(e)){let e=G.get(o);if(!e)throw new d("INVALID_ARGS",`Unknown config key "${o}" in ${t}.`);if(!e.config.enabled)throw new d("INVALID_ARGS",`Unsupported config key "${o}" in ${t}.`);s[o]=U(e,i,t,o)}return s}(o,`config file ${e}`)}(s.path,s.required));return t}((k=m.cwd,$=m.cliFlags.config,S=i,(p=$??S.AGENT_DEVICE_CONFIG)?[{path:(I=p,L=k,O=S,r.isAbsolute(I)?I:I.startsWith("~")?r.join(O.HOME?.trim()||c.homedir(),I.slice(1)):r.resolve(L,I)),required:!0}]:[{path:(N=S,g=N.HOME?.trim()||c.homedir(),r.join(g,".agent-device","config.json")),required:!1},{path:r.resolve(k,"agent-device.json"),required:!1}]))),l=eu(n,function(e,t){let s={};for(let o of T.filter(e=>e.config.enabled&&e.supportsCommand(t))){let t=o.env.names.map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);t&&(s[o.key]=U(o,t.value,`environment variable ${t.name}`,t.name))}return s}(i,m.command)),P=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),o=[...e.warnings],i=z({json:!1,help:!1,version:!1},t?.defaultFlags??{});z(i,e.flags);let a=x(e.command),r=e.providedFlags.filter(t=>!M(t.key,e.command));if(r.length>0){var n,l;let t=r.map(e=>e.token),a=(n=e.command,l=t,n?1===l.length?`Flag ${l[0]} is not supported for command ${n}.`:`Flags ${l.join(", ")} are not supported for command ${n}.`: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 d("INVALID_ARGS",a);for(let e of(o.push(`${a} Enable AGENT_DEVICE_STRICT_FLAGS=1 to fail fast.`),r))delete i[e.key]}for(let t of Object.keys(i))void 0!==i[t]&&(M(t,e.command)||delete i[t]);if(a?.defaults)for(let[e,t]of Object.entries(a.defaults))void 0===i[e]&&(i[e]=t);if("batch"===e.command&&1!=+!!i.steps+ +!!i.stepsFile)throw new d("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return{command:e.command,positionals:e.positionals,flags:i,warnings:o}}(t,{strictFlags:a?.strictFlags,defaultFlags:l})}catch(t){v({level:"error",phase:"cli_parse_failed",data:{error:t instanceof Error?t.message:String(t)}});let e=l(t,{diagnosticId:f().diagnosticId,logPath:h({force:!0})??void 0});b?K({success:!1,error:e}):Z(e,{showDetails:p}),process.exit(1);return}for(let e of P.warnings)process.stderr.write(`Warning: ${e}
`);P.flags.version&&(process.stdout.write(`${g()}
`),process.exit(0));let V="help"===P.command,B=P.flags.help;if(V||B){V&&P.positionals.length>1&&(Z(new d("INVALID_ARGS","help accepts at most one command.")),process.exit(1));let e=V?P.positionals[0]:P.command;e||(process.stdout.write(`${F}
`),process.exit(0));let t=function(e){let t=x(e);if(!t)return null;let s=_(e,t),o=E(new Set(t.allowedFlags)),i=E(A),a=[];return o.length>0&&a.push(C("Command flags:",o)),a.push(C("Global flags:",i)),`agent-device ${s}

@@ -40,47 +40,47 @@ ${t.description}

${o.join("\n\n")}
`}(E(e));t&&(process.stdout.write(t),process.exit(0)),P(new p("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${F}
`),process.exit(1)}w.command||(process.stdout.write(`${F}
`),process.exit(1));let{command:A,positionals:D,flags:I}=w,V=function(e){let{json:t,help:s,version:a,...i}=e;return i}(I),U=f(I.stateDir??process.env.AGENT_DEVICE_STATE_DIR),G=I.session??process.env.AGENT_DEVICE_SESSION??"default",J=I.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL,W=!I.verbose||I.json||J?null:function(e){try{let t=0,s=!1,a=setInterval(()=>{if(!s&&u.existsSync(e))try{let s=u.statSync(e);if(s.size<t&&(t=0),s.size<=t)return;let a=u.openSync(e,"r");try{let e=Buffer.alloc(s.size-t);u.readSync(a,e,0,e.length,t),t=s.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{u.closeSync(a)}}catch{}},200);return()=>{s=!0,clearInterval(a)}}catch{return null}}(U.logPath),q=y({session:G,requestId:i,stateDir:I.stateDir,daemonBaseUrl:I.daemonBaseUrl,daemonAuthToken:I.daemonAuthToken,daemonTransport:I.daemonTransport,daemonServerMode:I.daemonServerMode,tenant:I.tenant,sessionIsolation:I.sessionIsolation,runId:I.runId,leaseId:I.leaseId,cwd:process.cwd(),debug:!!I.verbose},{transport:t.sendToDaemon}),H=async e=>await t.sendToDaemon({session:G,command:e.command,positionals:e.positionals,flags:e.flags,meta:{requestId:i,debug:!!I.verbose,cwd:process.cwd(),tenantId:I.tenant,runId:I.runId,leaseId:I.leaseId,sessionIsolation:I.sessionIsolation}});try{if("batch"===A){let e,t,s;if(D.length>0)throw new p("INVALID_ARGS","batch does not accept positional arguments.");let i=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 p("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}return a(t)}(I),r={...V,batchSteps:i};delete r.steps,delete r.stepsFile;let n=await H({command:"batch",positionals:D,flags:r});if(!n.ok)throw new p(n.error.code,n.error.message,{...n.error.details??{},hint:n.error.hint,diagnosticId:n.error.diagnosticId,logPath:n.error.logPath});I.json?C({success:!0,data:n.data??{}}):(o=n.data??{},e="number"==typeof o.total?o.total:0,t="number"==typeof o.executed?o.executed:0,s="number"==typeof o.totalDurationMs?o.totalDurationMs:void 0,process.stdout.write(`Batch completed: ${t}/${e} steps${void 0!==s?` in ${s}ms`:""}
`)),W&&W();return}if(await B({command:A,positionals:D,flags:I,client:q})){W&&W();return}let e=await H({command:A,positionals:D,flags:V});if(e.ok){if(I.json){C({success:!0,data:e.data??{}}),W&&W();return}if("snapshot"===A){process.stdout.write(T(e.data??{},{raw:I.snapshotRaw,flatten:I.snapshotInteractiveOnly})),W&&W();return}if("diff"===A&&"snapshot"===D[0]){process.stdout.write(function(e){var t,a,i,o;let r,n=!0===e.baselineInitialized,l=e.summary??{},p=M(l.additions),d=M(l.removals),u=M(l.unchanged),c=(r=process.env.FORCE_COLOR,"string"==typeof r?"0"!==r:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY);if(n)return`Baseline initialized (${u} lines).
`;let g=(function(e,t){if(0===e.length)return e;let s=e.map((e,t)=>({index:t,kind:e.kind})).filter(e=>"added"===e.kind||"removed"===e.kind).map(e=>e.index);if(0===s.length)return e;let a=Array(e.length).fill(!1);for(let t of s){let s=Math.max(0,t-1),i=Math.min(e.length-1,t+1);for(let e=s;e<=i;e+=1)a[e]=!0}return e.filter((e,t)=>a[t])})(Array.isArray(e.lines)?e.lines:[],1).map(e=>{var t,a,i,o;let r="string"==typeof e.text?e.text:"";if("added"===e.kind){let e=r.startsWith(" ")?`+${r}`:`+ ${r}`;return c?(t=e,a="green",s(a,t)):e}if("removed"===e.kind){let e=r.startsWith(" ")?`-${r}`:`- ${r}`;return c?(i=e,s("red",i)):e}return c?(o=r,s("dim",o)):r}),m=g.length>0?`${g.join("\n")}
${a.join("\n\n")}
`}(H(e));t&&(process.stdout.write(t),process.exit(0)),Z(new d("INVALID_ARGS",`Unknown command: ${e}`)),process.stdout.write(`${F}
`),process.exit(1)}P.command||(process.stdout.write(`${F}
`),process.exit(1));let{command:ee,positionals:et}=P,es=ep({policyOverrides:P.flags,configuredPlatform:P.flags.platform,configuredSession:P.flags.session}),eo=es.lockPolicy?{...P.flags}:el(P.flags,{policyOverrides:P.flags,configuredPlatform:P.flags.platform,configuredSession:P.flags.session}),ei=function(e){let{json:t,config:s,help:o,version:i,sessionLock:a,sessionLocked:r,sessionLockConflicts:n,...l}=e;return l}(eo),ea=y(eo.stateDir),er=eo.session??"default",en=eo.daemonBaseUrl,ed=!eo.verbose||eo.json||en?null:function(e){try{let t=0,s=!1,o=setInterval(()=>{if(!s&&u.existsSync(e))try{let s=u.statSync(e);if(s.size<t&&(t=0),s.size<=t)return;let o=u.openSync(e,"r");try{let e=Buffer.alloc(s.size-t);u.readSync(o,e,0,e.length,t),t=s.size,e.length>0&&process.stdout.write(e.toString("utf8"))}finally{u.closeSync(o)}}catch{}},200);return()=>{s=!0,clearInterval(o)}}catch{return null}}(ea.logPath),ec=w({session:er,requestId:i,stateDir:eo.stateDir,daemonBaseUrl:eo.daemonBaseUrl,daemonAuthToken:eo.daemonAuthToken,daemonTransport:eo.daemonTransport,daemonServerMode:eo.daemonServerMode,tenant:eo.tenant,sessionIsolation:eo.sessionIsolation,runId:eo.runId,leaseId:eo.leaseId,lockPolicy:es.lockPolicy,lockPlatform:es.defaultPlatform,cwd:process.cwd(),debug:!!eo.verbose},{transport:t.sendToDaemon}),eg=async e=>await t.sendToDaemon({session:er,command:e.command,positionals:e.positionals,flags:e.flags,meta:{requestId:i,debug:!!eo.verbose,cwd:process.cwd(),tenantId:eo.tenant,runId:eo.runId,leaseId:eo.leaseId,sessionIsolation:eo.sessionIsolation,lockPolicy:es.lockPolicy,lockPlatform:es.defaultPlatform}});try{if("batch"===ee){let e,t,s;if(et.length>0)throw new d("INVALID_ARGS","batch does not accept positional arguments.");let i=(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 d("INVALID_ARGS",`Failed to read --steps-file ${e.stepsFile}: ${t}`)}return o(t)})(eo).map((e,t)=>({...e,flags:es.lockPolicy&&void 0===eo.platform?{...e.flags??{}}:el(e.flags??{},{policyOverrides:eo,configuredPlatform:eo.platform,configuredSession:eo.session,inheritedPlatform:eo.platform})})),a={...ei,batchSteps:i};delete a.steps,delete a.stepsFile;let r=await eg({command:"batch",positionals:et,flags:a});if(!r.ok)throw new d(r.error.code,r.error.message,{...r.error.details??{},hint:r.error.hint,diagnosticId:r.error.diagnosticId,logPath:r.error.logPath});eo.json?K({success:!0,data:r.data??{}}):(j=r.data??{},e="number"==typeof j.total?j.total:0,t="number"==typeof j.executed?j.executed:0,s="number"==typeof j.totalDurationMs?j.totalDurationMs:void 0,process.stdout.write(`Batch completed: ${t}/${e} steps${void 0!==s?` in ${s}ms`:""}
`)),ed&&ed();return}if(await Q({command:ee,positionals:et,flags:eo,client:ec})){ed&&ed();return}let e=await eg({command:ee,positionals:et,flags:ei});if(e.ok){if(eo.json){K({success:!0,data:e.data??{}}),ed&&ed();return}if("snapshot"===ee){process.stdout.write(X(e.data??{},{raw:eo.snapshotRaw,flatten:eo.snapshotInteractiveOnly})),ed&&ed();return}if("diff"===ee&&"snapshot"===et[0]){process.stdout.write(function(e){var t,o,i,a;let r,n=!0===e.baselineInitialized,l=e.summary??{},p=Y(l.additions),d=Y(l.removals),u=Y(l.unchanged),c=(r=process.env.FORCE_COLOR,"string"==typeof r?"0"!==r:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY);if(n)return`Baseline initialized (${u} lines).
`;let g=(function(e,t){if(0===e.length)return e;let s=e.map((e,t)=>({index:t,kind:e.kind})).filter(e=>"added"===e.kind||"removed"===e.kind).map(e=>e.index);if(0===s.length)return e;let o=Array(e.length).fill(!1);for(let t of s){let s=Math.max(0,t-1),i=Math.min(e.length-1,t+1);for(let e=s;e<=i;e+=1)o[e]=!0}return e.filter((e,t)=>o[t])})(Array.isArray(e.lines)?e.lines:[],1).map(e=>{var t,o,i,a;let r="string"==typeof e.text?e.text:"";if("added"===e.kind){let e=r.startsWith(" ")?`+${r}`:`+ ${r}`;return c?(t=e,o="green",s(o,t)):e}if("removed"===e.kind){let e=r.startsWith(" ")?`-${r}`:`- ${r}`;return c?(i=e,s("red",i)):e}return c?(a=r,s("dim",a)):r}),m=g.length>0?`${g.join("\n")}
`:"";if(!c)return`${m}${p} additions, ${d} removals, ${u} unchanged
`;let f=`${(t=String(p),a="green",s(a,t))} additions, ${(i=String(d),s("red",i))} removals, ${(o=String(u),s("dim",o))} unchanged`;return`${m}${f}
`}(e.data??{})),W&&W();return}if("get"===A){let t=D[0];if("text"===t){let t=e.data?.text??"";process.stdout.write(`${t}
`),W&&W();return}if("attrs"===t){let t=e.data?.node??{};process.stdout.write(`${JSON.stringify(t,null,2)}
`),W&&W();return}}if("find"===A){let t=e.data;if("string"==typeof t?.text){process.stdout.write(`${t.text}
`),W&&W();return}if("boolean"==typeof t?.found){process.stdout.write(`Found: ${t.found}
`),W&&W();return}if(t?.node){process.stdout.write(`${JSON.stringify(t.node,null,2)}
`),W&&W();return}}if("is"===A){let t=e.data?.predicate??"assertion";process.stdout.write(`Passed: is ${t}
`),W&&W();return}if("boot"===A){let t=e.data?.platform??"unknown",s=e.data?.device??e.data?.id??"unknown";process.stdout.write(`Boot ready: ${s} (${t})
`),W&&W();return}if("ensure-simulator"===A){let t=e.data,s="string"==typeof t?.udid?t.udid:"unknown",a="string"==typeof t?.device?t.device:"unknown",i="string"==typeof t?.runtime?t.runtime:"",o=t?.created===!0,r=t?.booted===!0;process.stdout.write(`${o?"Created":"Reused"}: ${a} ${s}${r?" (booted)":""}
`;let f=`${(t=String(p),o="green",s(o,t))} additions, ${(i=String(d),s("red",i))} removals, ${(a=String(u),s("dim",a))} unchanged`;return`${m}${f}
`}(e.data??{})),ed&&ed();return}if("get"===ee){let t=et[0];if("text"===t){let t=e.data?.text??"";process.stdout.write(`${t}
`),ed&&ed();return}if("attrs"===t){let t=e.data?.node??{};process.stdout.write(`${JSON.stringify(t,null,2)}
`),ed&&ed();return}}if("find"===ee){let t=e.data;if("string"==typeof t?.text){process.stdout.write(`${t.text}
`),ed&&ed();return}if("boolean"==typeof t?.found){process.stdout.write(`Found: ${t.found}
`),ed&&ed();return}if(t?.node){process.stdout.write(`${JSON.stringify(t.node,null,2)}
`),ed&&ed();return}}if("is"===ee){let t=e.data?.predicate??"assertion";process.stdout.write(`Passed: is ${t}
`),ed&&ed();return}if("boot"===ee){let t=e.data?.platform??"unknown",s=e.data?.device??e.data?.id??"unknown";process.stdout.write(`Boot ready: ${s} (${t})
`),ed&&ed();return}if("ensure-simulator"===ee){let t=e.data,s="string"==typeof t?.udid?t.udid:"unknown",o="string"==typeof t?.device?t.device:"unknown",i="string"==typeof t?.runtime?t.runtime:"",a=t?.created===!0,r=t?.booted===!0;process.stdout.write(`${a?"Created":"Reused"}: ${o} ${s}${r?" (booted)":""}
`),i&&process.stdout.write(`Runtime: ${i}
`),W&&W();return}if("runtime"===A){let t=e.data,s=t?.cleared===!0,a=t?.configured===!0;if(s){process.stdout.write("Runtime hints cleared\n"),W&&W();return}if(!a){process.stdout.write("No runtime hints configured\n"),W&&W();return}process.stdout.write(`${JSON.stringify(t?.runtime??{},null,2)}
`),W&&W();return}if("screenshot"===A){let t="string"==typeof e.data?.path?e.data.path:"";t&&process.stdout.write(`${t}
`),W&&W();return}if("record"===A){let t=e.data,s="string"==typeof t?.outPath?t.outPath:"";s&&process.stdout.write(`${s}
`),W&&W();return}if("logs"===A){let t=e.data,s="string"==typeof t?.path?t.path:"";if(s){process.stdout.write(`${s}
`);let e="boolean"==typeof t?.active?t.active:void 0,a="string"==typeof t?.state?t.state:void 0,i="string"==typeof t?.backend?t.backend:void 0,o="number"==typeof t?.sizeBytes?t.sizeBytes:void 0,r=t?.started===!0,n=t?.stopped===!0,l=t?.marked===!0,p=t?.cleared===!0,d=t?.restarted===!0,u="number"==typeof t?.removedRotatedFiles?t.removedRotatedFiles:void 0;if(!I.json&&(void 0!==e||a||i||void 0!==o)){let t=[void 0!==e?`active=${e}`:"",a?`state=${a}`:"",i?`backend=${i}`:"",void 0!==o?`sizeBytes=${o}`:""].filter(Boolean).join(" ");t&&process.stderr.write(`${t}
`)}if(!I.json&&(r||n||l||p||d||void 0!==u)){let e=[r?"started=true":"",n?"stopped=true":"",l?"marked=true":"",p?"cleared=true":"",d?"restarted=true":"",void 0!==u?`removedRotatedFiles=${u}`:""].filter(Boolean).join(" ");e&&process.stderr.write(`${e}
`)}if(t?.hint&&!I.json&&process.stderr.write(`${t.hint}
`),Array.isArray(t?.notes)&&!I.json)for(let e of t.notes)"string"==typeof e&&e.length>0&&process.stderr.write(`${e}
`)}W&&W();return}if("clipboard"===A){let t=e.data,s=(D[0]??("string"==typeof t?.action?t.action:"")).toLowerCase();if("read"===s){let e="string"==typeof t?.text?t.text:"";process.stdout.write(`${e}
`),W&&W();return}if("write"===s){process.stdout.write("Clipboard updated\n"),W&&W();return}}if("network"===A){let t=e.data,s="string"==typeof t?.path?t.path:"";s&&process.stdout.write(`${s}
`);let a=Array.isArray(t?.entries)?t.entries:[];if(0===a.length)process.stdout.write("No recent HTTP(s) entries found.\n");else for(let e of a){let t="string"==typeof e.method?e.method:"HTTP",s="string"==typeof e.url?e.url:"<unknown-url>",a="number"==typeof e.status?` status=${e.status}`:"",i="string"==typeof e.timestamp?`${e.timestamp} `:"";process.stdout.write(`${i}${t} ${s}${a}
`),ed&&ed();return}if("runtime"===ee){let t=e.data,s=t?.cleared===!0,o=t?.configured===!0;if(s){process.stdout.write("Runtime hints cleared\n"),ed&&ed();return}if(!o){process.stdout.write("No runtime hints configured\n"),ed&&ed();return}process.stdout.write(`${JSON.stringify(t?.runtime??{},null,2)}
`),ed&&ed();return}if("screenshot"===ee){let t="string"==typeof e.data?.path?e.data.path:"";t&&process.stdout.write(`${t}
`),ed&&ed();return}if("record"===ee){let t=e.data,s="string"==typeof t?.outPath?t.outPath:"";s&&process.stdout.write(`${s}
`),ed&&ed();return}if("logs"===ee){let t=e.data,s="string"==typeof t?.path?t.path:"";if(s){process.stdout.write(`${s}
`);let e="boolean"==typeof t?.active?t.active:void 0,o="string"==typeof t?.state?t.state:void 0,i="string"==typeof t?.backend?t.backend:void 0,a="number"==typeof t?.sizeBytes?t.sizeBytes:void 0,r=t?.started===!0,n=t?.stopped===!0,l=t?.marked===!0,p=t?.cleared===!0,d=t?.restarted===!0,u="number"==typeof t?.removedRotatedFiles?t.removedRotatedFiles:void 0;if(!eo.json&&(void 0!==e||o||i||void 0!==a)){let t=[void 0!==e?`active=${e}`:"",o?`state=${o}`:"",i?`backend=${i}`:"",void 0!==a?`sizeBytes=${a}`:""].filter(Boolean).join(" ");t&&process.stderr.write(`${t}
`)}if(!eo.json&&(r||n||l||p||d||void 0!==u)){let e=[r?"started=true":"",n?"stopped=true":"",l?"marked=true":"",p?"cleared=true":"",d?"restarted=true":"",void 0!==u?`removedRotatedFiles=${u}`:""].filter(Boolean).join(" ");e&&process.stderr.write(`${e}
`)}if(t?.hint&&!eo.json&&process.stderr.write(`${t.hint}
`),Array.isArray(t?.notes)&&!eo.json)for(let e of t.notes)"string"==typeof e&&e.length>0&&process.stderr.write(`${e}
`)}ed&&ed();return}if("clipboard"===ee){let t=e.data,s=(et[0]??("string"==typeof t?.action?t.action:"")).toLowerCase();if("read"===s){let e="string"==typeof t?.text?t.text:"";process.stdout.write(`${e}
`),ed&&ed();return}if("write"===s){process.stdout.write("Clipboard updated\n"),ed&&ed();return}}if("network"===ee){let t=e.data,s="string"==typeof t?.path?t.path:"";s&&process.stdout.write(`${s}
`);let o=Array.isArray(t?.entries)?t.entries:[];if(0===o.length)process.stdout.write("No recent HTTP(s) entries found.\n");else for(let e of o){let t="string"==typeof e.method?e.method:"HTTP",s="string"==typeof e.url?e.url:"<unknown-url>",o="number"==typeof e.status?` status=${e.status}`:"",i="string"==typeof e.timestamp?`${e.timestamp} `:"";process.stdout.write(`${i}${t} ${s}${o}
`),"string"==typeof e.headers&&process.stdout.write(` headers: ${e.headers}
`),"string"==typeof e.requestBody&&process.stdout.write(` request: ${e.requestBody}
`),"string"==typeof e.responseBody&&process.stdout.write(` response: ${e.responseBody}
`)}let i="boolean"==typeof t?.active?t.active:void 0,o="string"==typeof t?.state?t.state:void 0,r="string"==typeof t?.backend?t.backend:void 0,n="number"==typeof t?.scannedLines?t.scannedLines:void 0,l="number"==typeof t?.matchedLines?t.matchedLines:void 0,p="string"==typeof t?.include?t.include:void 0,d=[void 0!==i?`active=${i}`:"",o?`state=${o}`:"",r?`backend=${r}`:"",p?`include=${p}`:"",void 0!==n?`scannedLines=${n}`:"",void 0!==l?`matchedLines=${l}`:""].filter(Boolean).join(" ");if(d&&process.stderr.write(`${d}
`)}let i="boolean"==typeof t?.active?t.active:void 0,a="string"==typeof t?.state?t.state:void 0,r="string"==typeof t?.backend?t.backend:void 0,n="number"==typeof t?.scannedLines?t.scannedLines:void 0,l="number"==typeof t?.matchedLines?t.matchedLines:void 0,p="string"==typeof t?.include?t.include:void 0,d=[void 0!==i?`active=${i}`:"",a?`state=${a}`:"",r?`backend=${r}`:"",p?`include=${p}`:"",void 0!==n?`scannedLines=${n}`:"",void 0!==l?`matchedLines=${l}`:""].filter(Boolean).join(" ");if(d&&process.stderr.write(`${d}
`),Array.isArray(t?.notes))for(let e of t.notes)"string"==typeof e&&e.length>0&&process.stderr.write(`${e}
`);W&&W();return}if("click"===A||"press"===A){let t=e.data?.ref??"",s=e.data?.x,a=e.data?.y;t&&"number"==typeof s&&"number"==typeof a&&process.stdout.write(`Tapped @${t} (${s}, ${a})
`),W&&W();return}if(e.data&&"object"==typeof e.data){let t=e.data;if("devices"===A){let e=(Array.isArray(t.devices)?t.devices:[]).map(e=>{let t=e?.name??e?.id??"unknown",s=e?.platform??"unknown",a=e?.kind?` ${e.kind}`:"",i=e?.target?` target=${e.target}`:"",o="boolean"==typeof e?.booted?` booted=${e.booted}`:"";return`${t} (${s}${a}${i})${o}`});process.stdout.write(`${e.join("\n")}
`),W&&W();return}if("apps"===A){let e=(Array.isArray(t.apps)?t.apps:[]).map(e=>{if("string"==typeof e)return e;if(e&&"object"==typeof e){let t=e.bundleId??e.package,s=e.name??e.label;return s&&t?`${s} (${t})`:t?String(t):JSON.stringify(e)}return String(e)});process.stdout.write(`${e.join("\n")}
`),W&&W();return}if("appstate"===A){let e=t?.platform,s=t?.appBundleId,a=t?.appName,i=t?.source,o=t?.package,r=t?.activity;if("ios"===e){process.stdout.write(`Foreground app: ${a??s??"unknown"}
`);ed&&ed();return}if("click"===ee||"press"===ee){let t=e.data?.ref??"",s=e.data?.x,o=e.data?.y;t&&"number"==typeof s&&"number"==typeof o&&process.stdout.write(`Tapped @${t} (${s}, ${o})
`),ed&&ed();return}if(e.data&&"object"==typeof e.data){let t=e.data;if("devices"===ee){let e=(Array.isArray(t.devices)?t.devices:[]).map(e=>{let t=e?.name??e?.id??"unknown",s=e?.platform??"unknown",o=e?.kind?` ${e.kind}`:"",i=e?.target?` target=${e.target}`:"",a="boolean"==typeof e?.booted?` booted=${e.booted}`:"";return`${t} (${s}${o}${i})${a}`});process.stdout.write(`${e.join("\n")}
`),ed&&ed();return}if("apps"===ee){let e=(Array.isArray(t.apps)?t.apps:[]).map(e=>{if("string"==typeof e)return e;if(e&&"object"==typeof e){let t=e.bundleId??e.package,s=e.name??e.label;return s&&t?`${s} (${t})`:t?String(t):JSON.stringify(e)}return String(e)});process.stdout.write(`${e.join("\n")}
`),ed&&ed();return}if("appstate"===ee){let e=t?.platform,s=t?.appBundleId,o=t?.appName,i=t?.source,a=t?.package,r=t?.activity;if("ios"===e){process.stdout.write(`Foreground app: ${o??s??"unknown"}
`),s&&process.stdout.write(`Bundle: ${s}
`),i&&process.stdout.write(`Source: ${i}
`),W&&W();return}if("android"===e){process.stdout.write(`Foreground app: ${o??"unknown"}
`),ed&&ed();return}if("android"===e){process.stdout.write(`Foreground app: ${a??"unknown"}
`),r&&process.stdout.write(`Activity: ${r}
`),W&&W();return}}if("perf"===A){process.stdout.write(`${JSON.stringify(t,null,2)}
`),W&&W();return}}W&&W();return}throw new p(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath})}catch(s){let e=r(s),t=n(e,{diagnosticId:g().diagnosticId,logPath:m({force:!0})??void 0});if("close"===A&&"COMMAND_FAILED"===(c=e).code&&(c.details?.kind==="daemon_startup_failed"||c.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof c.details?.infoPath||"string"==typeof c.details?.lockPath))){I.json&&C({success:!0,data:{closed:"session",source:"no-daemon"}}),W&&W();return}if(I.json)C({success:!1,error:t});else if(P(t,{showDetails:I.verbose}),I.verbose)try{let e=U.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(`
`),ed&&ed();return}}if("perf"===ee){process.stdout.write(`${JSON.stringify(t,null,2)}
`),ed&&ed();return}}ed&&ed();return}throw new d(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath})}catch(s){let e=n(s),t=l(e,{diagnosticId:f().diagnosticId,logPath:h({force:!0})??void 0});if("close"===ee&&"COMMAND_FAILED"===(R=e).code&&(R.details?.kind==="daemon_startup_failed"||R.message.toLowerCase().includes("failed to start daemon")&&("string"==typeof R.details?.infoPath||"string"==typeof R.details?.lockPath))){eo.json&&K({success:!0,data:{closed:"session",source:"no-daemon"}}),ed&&ed();return}if(eo.json)K({success:!1,error:t});else if(Z(t,{showDetails:eo.verbose}),eo.verbose)try{let e=ea.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(`
[daemon log]
${s}
`)}}catch{}W&&W(),process.exit(1)}})}l(process.argv[1]??"").href===import.meta.url&&X(process.argv.slice(2)).catch(e=>{P(n(r(e)),{showDetails:!0}),process.exit(1)}),X(process.argv.slice(2));
`)}}catch{}ed&&ed(),process.exit(1)}})}p(process.argv[1]??"").href===import.meta.url&&eg(process.argv.slice(2)).catch(e=>{Z(l(n(e)),{showDetails:!0}),process.exit(1)}),eg(process.argv.slice(2));

@@ -1,2 +0,2 @@

import type { DaemonInstallSource, DaemonRequest, DaemonResponse, SessionRuntimeHints } from './daemon/types.ts';
import type { DaemonInstallSource, DaemonLockPolicy, DaemonRequest, DaemonResponse, SessionRuntimeHints } from './daemon/types.ts';
import type { DeviceKind, DeviceTarget, Platform, PlatformSelector } from './utils/device.ts';

@@ -10,2 +10,4 @@ import type { SnapshotNode } from './utils/snapshot.ts';

session?: string;
lockPolicy?: DaemonLockPolicy;
lockPlatform?: PlatformSelector;
requestId?: string;

@@ -24,3 +26,3 @@ stateDir?: string;

};
export type AgentDeviceRequestOverrides = Pick<AgentDeviceClientConfig, 'session' | 'requestId' | 'tenant' | 'sessionIsolation' | 'runId' | 'leaseId' | 'cwd' | 'debug'>;
export type AgentDeviceRequestOverrides = Pick<AgentDeviceClientConfig, 'session' | 'lockPolicy' | 'lockPlatform' | 'requestId' | 'tenant' | 'sessionIsolation' | 'runId' | 'leaseId' | 'cwd' | 'debug'>;
export type AgentDeviceIdentifiers = {

@@ -27,0 +29,0 @@ session?: string;

@@ -9,2 +9,4 @@ import type { DaemonRequest as SharedDaemonRequest, DaemonResponse as SharedDaemonResponse } from './daemon/types.ts';

url?: string;
lockPolicy?: NonNullable<DaemonRequest['meta']>['lockPolicy'];
lockPlatform?: NonNullable<DaemonRequest['meta']>['lockPlatform'];
platform?: NonNullable<DaemonRequest['flags']>['platform'];

@@ -11,0 +13,0 @@ target?: NonNullable<DaemonRequest['flags']>['target'];

import type { CommandFlags } from '../core/dispatch.ts';
import type { SessionState } from './types.ts';
export type SessionSelectorConflictKey = 'platform' | 'target' | 'udid' | 'serial' | 'device' | 'iosSimulatorDeviceSet' | 'androidDeviceAllowlist';
export type SessionSelectorConflict = {
key: SessionSelectorConflictKey;
value: string;
};
export declare function assertSessionSelectorMatches(session: SessionState, flags?: CommandFlags): void;
export declare function listSessionSelectorConflicts(session: SessionState, flags?: CommandFlags): SessionSelectorConflict[];
export declare function formatSessionSelectorConflict(conflict: SessionSelectorConflict): string;

@@ -7,2 +7,3 @@ import type { MaterializeInstallSource } from '../platforms/install-source.ts';

export type DaemonInstallSource = MaterializeInstallSource;
export type DaemonLockPolicy = 'reject' | 'strip';
export type DaemonRequest = {

@@ -31,2 +32,4 @@ token: string;

materializationId?: string;
lockPolicy?: DaemonLockPolicy;
lockPlatform?: 'ios' | 'android' | 'apple';
};

@@ -33,0 +36,0 @@ };

@@ -1,2 +0,2 @@

import { type CliFlags } from './command-schema.ts';
import { type CliFlags, type FlagKey } from './command-schema.ts';
type ParsedArgs = {

@@ -11,6 +11,18 @@ command: string | null;

};
export declare function parseArgs(argv: string[], options?: ParseArgsOptions): ParsedArgs;
export declare function toDaemonFlags(flags: CliFlags): Omit<CliFlags, 'json' | 'help' | 'version'>;
type ParsedFlagRecord = {
key: FlagKey;
token: string;
};
type RawParsedArgs = ParsedArgs & {
providedFlags: ParsedFlagRecord[];
};
type FinalizeArgsOptions = ParseArgsOptions & {
defaultFlags?: Partial<CliFlags>;
};
export declare function parseArgs(argv: string[], options?: FinalizeArgsOptions): ParsedArgs;
export declare function parseRawArgs(argv: string[]): RawParsedArgs;
export declare function finalizeParsedArgs(parsed: RawParsedArgs, options?: FinalizeArgsOptions): ParsedArgs;
export declare function toDaemonFlags(flags: CliFlags): Omit<CliFlags, 'json' | 'config' | 'help' | 'version'>;
export declare function usage(): string;
export declare function usageForCommand(command: string): string | null;
export {};
export type CliFlags = {
json: boolean;
config?: string;
stateDir?: string;

@@ -12,2 +13,5 @@ daemonBaseUrl?: string;

leaseId?: string;
sessionLock?: 'reject' | 'strip';
sessionLocked?: boolean;
sessionLockConflicts?: 'reject' | 'strip';
platform?: 'ios' | 'android' | 'apple';

@@ -88,2 +92,3 @@ target?: 'mobile' | 'tv';

export declare function getFlagDefinition(token: string): FlagDefinition | undefined;
export declare function getFlagDefinitions(): readonly FlagDefinition[];
export declare function getCommandSchema(command: string | null): CommandSchema | undefined;

@@ -90,0 +95,0 @@ export declare function getCliCommandNames(): string[];

{
"name": "agent-device",
"version": "0.7.22",
"version": "0.8.0",
"description": "Unified control plane for physical and virtual devices via an agent-driven CLI.",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -43,3 +43,7 @@ <a href="https://www.callstack.com/open-source?utm_campaign=generic&utm_source=github&utm_medium=referral&utm_content=agent-device" align="center">

const client = createAgentDeviceClient({ session: 'qa-ios' });
const client = createAgentDeviceClient({
session: 'qa-ios',
lockPolicy: 'reject',
lockPlatform: 'ios',
});

@@ -152,2 +156,33 @@ const devices = await client.devices.list({ platform: 'ios' });

## Configuration
Create an `agent-device.json` file to set persistent CLI defaults instead of repeating flags.
Config file lookup order:
- `~/.agent-device/config.json`
- `./agent-device.json`
- `AGENT_DEVICE_*` environment variables
- CLI flags
Later sources override earlier ones. Use `--config <path>` or `AGENT_DEVICE_CONFIG` to load one explicit config file instead of the default locations.
Example:
```json
{
"platform": "ios",
"device": "iPhone 16",
"session": "qa-ios",
"snapshotDepth": 3,
"daemonBaseUrl": "http://mac-host.example:4310/agent-device"
}
```
Notes:
- Config keys use the existing camelCase flag names, for example `stateDir`, `daemonAuthToken`, `iosSimulatorDeviceSet`, and `androidDeviceAllowlist`.
- Environment overrides use `AGENT_DEVICE_*` uppercase snake case names, for example `AGENT_DEVICE_SESSION`, `AGENT_DEVICE_DAEMON_BASE_URL`, and `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET`.
- Bound-session routing defaults also work through config or env, for example `sessionLock` / `AGENT_DEVICE_SESSION_LOCK`.
- For options that have CLI aliases, config/env use the canonical value rather than the alias flag. Example: use `"appsFilter": "user-installed"` or `AGENT_DEVICE_APPS_FILTER=user-installed`, not `--user-installed`.
- Command-specific defaults are applied only when that command supports them, so a `snapshotDepth` default does not break `open` or `devices`.
Basic flow:

@@ -561,2 +596,11 @@

- `AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST=<serials>` (or `ANDROID_DEVICE_ALLOWLIST=<serials>`) to scope Android discovery to allowlisted serials.
- `AGENT_DEVICE_SESSION=<name>` sets the default CLI session when `--session` is omitted.
- `AGENT_DEVICE_PLATFORM=ios|android|apple` sets the default CLI platform when `--platform` is omitted.
- When `AGENT_DEVICE_SESSION` is set, the CLI treats the run as session-bound by default and sends a shared daemon lock policy with the request.
- `--session-lock reject|strip` sets the lock policy for the current CLI invocation and nested batch steps.
- `AGENT_DEVICE_SESSION_LOCK=reject|strip` sets the default lock policy for bound-session automation runs. `strip` ignores `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`, and restores the configured platform.
- The daemon is the source of truth for lock-policy enforcement across CLI requests, typed client calls, and direct RPC.
- Direct RPC callers can pass `meta.lockPolicy` and optional `meta.lockPlatform` on `agent_device.command` requests to use the same daemon-enforced session lock concept.
- `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS` remain supported as compatibility aliases.
- For `batch`, steps that omit `platform` continue to inherit the parent batch `--platform` even when session-bound defaults are configured.
- `AGENT_DEVICE_BUNDLETOOL_JAR=<path-to-bundletool-all.jar>` optional bundletool jar path used for Android `.aab` installs when `bundletool` is not in `PATH`.

@@ -563,0 +607,0 @@ - `AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE=<mode>` optional bundletool `build-apks --mode` override for Android `.aab` installs (default: `universal`).

@@ -53,2 +53,13 @@ # Remote Tenancy and Lease Admission

Example session-locked command request:
```bash
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
-H "content-type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"jsonrpc":"2.0","id":"cmd-1","method":"agent_device.command","params":{"session":"qa-ios","command":"snapshot","positionals":[],"meta":{"lockPolicy":"reject","lockPlatform":"ios","tenantId":"acme","runId":"run-123","leaseId":"<lease-id>"}}}'
```
Direct RPC callers can send the same session lock concept as the CLI and typed client through `meta.lockPolicy` and optional `meta.lockPlatform`.
## Command admission contract

@@ -55,0 +66,0 @@

@@ -17,2 +17,3 @@ # Session Management

- Use separate sessions for parallel work.
- For orchestrated QA runs, prefer a pre-bound session/platform over repeating per-command selectors.
- For remote tenant-scoped automation, run commands with:

@@ -30,2 +31,37 @@ `--tenant <id> --session-isolation tenant --run-id <id> --lease-id <id>`

## Session-bound automation
Use this when an external orchestrator must keep every CLI call on the same session/device without a wrapper script.
```bash
export AGENT_DEVICE_SESSION=qa-ios
export AGENT_DEVICE_PLATFORM=ios
export AGENT_DEVICE_SESSION_LOCK=strip
agent-device open MyApp --relaunch
agent-device snapshot -i
agent-device press @e3
agent-device close
```
- `AGENT_DEVICE_SESSION` and `AGENT_DEVICE_PLATFORM` provide the default binding when `--session` and `--platform` are omitted.
- A configured `AGENT_DEVICE_SESSION` enables lock policy enforcement by convention. The default mode is `reject`.
- `--session-lock reject|strip` or `AGENT_DEVICE_SESSION_LOCK=reject|strip` controls whether conflicting selectors fail or are ignored.
- The daemon enforces the same lock policy for CLI requests, typed client calls, and direct RPC commands.
- Conflicts include explicit retargeting selectors such as `--platform`, `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`.
- `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS` remain supported as compatibility aliases.
- Lock policy applies to nested `batch` steps too. If a step omits `platform`, it still inherits the parent batch `--platform` instead of being silently replaced by an environment default.
Android emulator variant:
```bash
export AGENT_DEVICE_SESSION=qa-android
export AGENT_DEVICE_PLATFORM=android
agent-device reinstall MyApp /path/to/app-debug.apk --serial emulator-5554
agent-device --session-lock reject open com.example.myapp --relaunch
agent-device snapshot -i
agent-device close --shutdown
```
## Scoped device isolation

@@ -32,0 +68,0 @@

@@ -38,2 +38,4 @@ ---

- In mixed-device environments, always pin the exact target with `--serial`, `--device`, `--udid`, or an isolation scope.
- For session-bound automation runs, prefer a pre-bound session/platform instead of repeating selectors on every command: set `AGENT_DEVICE_SESSION`, set `AGENT_DEVICE_PLATFORM`, and the daemon will enforce the shared lock policy across CLI, typed client, and RPC entry points.
- Use `--session-lock reject|strip` (or `AGENT_DEVICE_SESSION_LOCK`) only when you need to override the default reject behavior. Lock mode applies to nested `batch` steps too.

@@ -77,2 +79,31 @@ ## Canonical Flows

### 1c) Session-Bound Automation Flow
```bash
export AGENT_DEVICE_SESSION=qa-ios
export AGENT_DEVICE_PLATFORM=ios
export AGENT_DEVICE_SESSION_LOCK=strip
agent-device open MyApp --relaunch
agent-device snapshot -i
agent-device batch --steps-file /tmp/qa-steps.json --json
agent-device close
```
Use this for orchestrators that must preserve one bound session/device across many plain CLI calls without a wrapper script. In `strip` mode, conflicting selectors such as `--target`, `--device`, `--udid`, `--serial`, and isolation-scope overrides are ignored instead of retargeting the run.
### 1d) Android Emulator Session-Bound Flow
```bash
export AGENT_DEVICE_SESSION=qa-android
export AGENT_DEVICE_PLATFORM=android
agent-device reinstall MyApp /path/to/app-debug.apk --serial emulator-5554
agent-device --session-lock reject open com.example.myapp --relaunch
agent-device snapshot -i
agent-device close --shutdown
```
Use this when an Android emulator session must stay pinned while an agent or test runner issues plain CLI commands over time.
### 2) Debug/Crash Flow

@@ -152,2 +183,5 @@

Use `boot` only as fallback when `open` cannot find/connect to a ready target.
If the workspace repeats the same selectors or device/session flags, prefer a checked-in `agent-device.json` or `--config <path>` over repeating them inline.
Environment-level defaults follow the same fields via `AGENT_DEVICE_*` names, so persistent host-specific values belong there rather than in committed project config.
That includes bound-session defaults such as `sessionLock` / `AGENT_DEVICE_SESSION_LOCK` when automation should consistently reject or strip conflicting device routing flags.
For Android emulators by AVD name, use `boot --platform android --device <avd-name>`.

@@ -158,2 +192,3 @@ For Android emulators without GUI, add `--headless`.

For local iOS QA in mixed simulator/device environments, use `ensure-simulator` and pass `--device` or `--udid` so automation does not attach to a physical device by accident.
For session-bound automation, prefer `AGENT_DEVICE_SESSION` + `AGENT_DEVICE_PLATFORM`; that bound-session default now enables lock mode automatically.

@@ -165,2 +200,3 @@ Isolation scoping quick reference:

- With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
- In bound-session `strip` mode, conflicting per-call scope/selectors are ignored and the configured binding is restored for the request. Batch steps still inherit the parent `--platform` when they do not set their own.

@@ -167,0 +203,0 @@ Simulator provisioning quick reference:

Sorry, the diff of this file is too big to display