agent-device 0.11.16 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,13 +19,17 @@ declare type FindAction = {
19
19
  timeoutMs?: number;
20
20
  };
21
21
 
22
- export declare function findBestMatchesByLocator(nodes: SnapshotNode[], locator: FindLocator, query: string, requireRect?: boolean): {
22
+ export declare function findBestMatchesByLocator(nodes: SnapshotNode[], locator: FindLocator, query: string, options?: boolean | FindMatchOptions): {
23
23
  matches: SnapshotNode[];
24
24
  score: number;
25
25
  };
26
26
 
27
27
  export declare type FindLocator = 'any' | 'text' | 'label' | 'value' | 'role' | 'id';
28
28
 
29
+ export declare type FindMatchOptions = {
30
+ requireRect?: boolean;
31
+ };
32
+
29
33
  export declare function normalizeRole(value: string): string;
30
34
 
31
35
  export declare function normalizeText(value: string): string;
@@ -68,7 +72,7 @@ declare type Rect = {
68
72
  height: number;
69
73
  };
70
74
 
71
- declare type SnapshotNode = RawSnapshotNode & {
75
+ export declare type SnapshotNode = RawSnapshotNode & {
72
76
  ref: string;
73
77
  };
74
78
 
@@ -1 +1 @@
1
- import{findBestMatchesByLocator as o}from"./556.js";function r(r,e,t,_){return o(r,e,t,{requireRect:_})}export{normalizeRole,normalizeText,parseFindArgs}from"./556.js";export{r as findBestMatchesByLocator};
1
+ import{findBestMatchesByLocator as e}from"./556.js";function o(o,r,t,_){return e(o,r,t,"boolean"==typeof _?{requireRect:_}:_)}export{normalizeRole,normalizeText,parseFindArgs}from"./556.js";export{o as findBestMatchesByLocator};
@@ -43,7 +43,6 @@ export declare type AgentDeviceClient = {
43
43
  type: (options: TypeTextOptions) => Promise<CommandRequestResult>;
44
44
  fill: (options: FillOptions) => Promise<CommandRequestResult>;
45
45
  scroll: (options: ScrollOptions_2) => Promise<CommandRequestResult>;
46
- scrollIntoView: (options: ScrollIntoViewOptions_2) => Promise<CommandRequestResult>;
47
46
  pinch: (options: PinchOptions) => Promise<CommandRequestResult>;
48
47
  get: (options: GetOptions) => Promise<CommandRequestResult>;
49
48
  is: (options: IsOptions) => Promise<CommandRequestResult>;
@@ -307,13 +306,6 @@ export declare type BatchStep = {
307
306
  flags?: Record<string, unknown>;
308
307
  };
309
308
 
310
- declare type BatchStep_2 = {
311
- command: string;
312
- positionals?: string[];
313
- flags?: Partial<CommandFlags>;
314
- runtime?: unknown;
315
- };
316
-
317
309
  export declare type CaptureDiffOptions = ClientCommandBaseOptions & Pick<CaptureSnapshotOptions, 'interactiveOnly' | 'compact' | 'depth' | 'scope' | 'raw'> & {
318
310
  kind: 'snapshot';
319
311
  out?: string;
@@ -357,110 +349,6 @@ export declare type ClickOptions = ClientCommandBaseOptions & SelectorSnapshotCo
357
349
 
358
350
  declare type ClientCommandBaseOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions;
359
351
 
360
- declare type CliFlags = {
361
- json: boolean;
362
- config?: string;
363
- remoteConfig?: string;
364
- stateDir?: string;
365
- daemonBaseUrl?: string;
366
- daemonAuthToken?: string;
367
- daemonTransport?: 'auto' | 'socket' | 'http';
368
- daemonServerMode?: 'socket' | 'http' | 'dual';
369
- tenant?: string;
370
- sessionIsolation?: 'none' | 'tenant';
371
- runId?: string;
372
- leaseId?: string;
373
- sessionLock?: 'reject' | 'strip';
374
- sessionLocked?: boolean;
375
- sessionLockConflicts?: 'reject' | 'strip';
376
- platform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
377
- target?: 'mobile' | 'tv' | 'desktop';
378
- device?: string;
379
- udid?: string;
380
- serial?: string;
381
- iosSimulatorDeviceSet?: string;
382
- androidDeviceAllowlist?: string;
383
- out?: string;
384
- session?: string;
385
- runtime?: string;
386
- metroHost?: string;
387
- metroPort?: number;
388
- metroProjectRoot?: string;
389
- metroKind?: 'auto' | 'react-native' | 'expo';
390
- metroPublicBaseUrl?: string;
391
- metroProxyBaseUrl?: string;
392
- metroBearerToken?: string;
393
- metroPreparePort?: number;
394
- metroListenHost?: string;
395
- metroStatusHost?: string;
396
- metroStartupTimeoutMs?: number;
397
- metroProbeTimeoutMs?: number;
398
- metroRuntimeFile?: string;
399
- metroNoReuseExisting?: boolean;
400
- metroNoInstallDeps?: boolean;
401
- bundleUrl?: string;
402
- launchUrl?: string;
403
- boot?: boolean;
404
- reuseExisting?: boolean;
405
- verbose?: boolean;
406
- snapshotInteractiveOnly?: boolean;
407
- snapshotDiff?: boolean;
408
- snapshotCompact?: boolean;
409
- snapshotDepth?: number;
410
- snapshotScope?: string;
411
- snapshotRaw?: boolean;
412
- networkInclude?: 'summary' | 'headers' | 'body' | 'all';
413
- overlayRefs?: boolean;
414
- screenshotFullscreen?: boolean;
415
- baseline?: string;
416
- threshold?: string;
417
- appsFilter?: 'user-installed' | 'all';
418
- count?: number;
419
- fps?: number;
420
- hideTouches?: boolean;
421
- intervalMs?: number;
422
- delayMs?: number;
423
- holdMs?: number;
424
- jitterPx?: number;
425
- pixels?: number;
426
- doubleTap?: boolean;
427
- clickButton?: 'primary' | 'secondary' | 'middle';
428
- backMode?: 'in-app' | 'system';
429
- pauseMs?: number;
430
- pattern?: 'one-way' | 'ping-pong';
431
- maxScrolls?: number;
432
- activity?: string;
433
- header?: string[];
434
- saveScript?: boolean | string;
435
- shutdown?: boolean;
436
- relaunch?: boolean;
437
- surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
438
- headless?: boolean;
439
- restart?: boolean;
440
- noRecord?: boolean;
441
- retainPaths?: boolean;
442
- retentionMs?: number;
443
- replayUpdate?: boolean;
444
- failFast?: boolean;
445
- timeoutMs?: number;
446
- retries?: number;
447
- artifactsDir?: string;
448
- reportJunit?: string;
449
- steps?: string;
450
- stepsFile?: string;
451
- findFirst?: boolean;
452
- findLast?: boolean;
453
- batchOnError?: 'stop';
454
- batchMaxSteps?: number;
455
- batchSteps?: Array<{
456
- command: string;
457
- positionals?: string[];
458
- flags?: Record<string, unknown>;
459
- }>;
460
- help: boolean;
461
- version: boolean;
462
- };
463
-
464
352
  export declare type ClipboardCommandOptions = (DeviceCommandBaseOptions & {
465
353
  action: 'read';
466
354
  }) | (DeviceCommandBaseOptions & {
@@ -480,10 +368,6 @@ declare type CommandActionResult<T extends string> = DaemonResponseData & {
480
368
  action?: T;
481
369
  };
482
370
 
483
- declare type CommandFlags = Omit<CliFlags, 'json' | 'help' | 'version' | 'batchSteps'> & {
484
- batchSteps?: BatchStep_2[];
485
- };
486
-
487
371
  export declare type CommandRequestResult = DaemonResponseData;
488
372
 
489
373
  export declare function createAgentDeviceClient(config?: AgentDeviceClientConfig, deps?: {
@@ -507,9 +391,7 @@ declare type DaemonError = {
507
391
  details?: Record<string, unknown>;
508
392
  };
509
393
 
510
- declare type DaemonInstallSource = MaterializeInstallSource;
511
-
512
- declare type DaemonInstallSource_2 = {
394
+ declare type DaemonInstallSource = {
513
395
  kind: 'url';
514
396
  url: string;
515
397
  headers?: Record<string, string>;
@@ -520,20 +402,13 @@ declare type DaemonInstallSource_2 = {
520
402
 
521
403
  declare type DaemonLockPolicy = 'reject' | 'strip';
522
404
 
523
- declare type DaemonRequest = Omit<DaemonRequest_2, 'token' | 'session' | 'flags' | 'meta'> & {
524
- token: string;
525
- session: string;
526
- flags?: CommandFlags;
527
- meta?: DaemonRequestMeta_2;
528
- };
529
-
530
- declare type DaemonRequest_2 = {
405
+ declare type DaemonRequest = {
531
406
  token?: string;
532
407
  session?: string;
533
408
  command: string;
534
409
  positionals: string[];
535
410
  flags?: Record<string, unknown>;
536
- runtime?: SessionRuntimeHints_2;
411
+ runtime?: SessionRuntimeHints;
537
412
  meta?: DaemonRequestMeta;
538
413
  };
539
414
 
@@ -549,7 +424,7 @@ declare type DaemonRequestMeta = {
549
424
  sessionIsolation?: 'none' | 'tenant';
550
425
  uploadedArtifactId?: string;
551
426
  clientArtifactPaths?: Record<string, string>;
552
- installSource?: DaemonInstallSource_2;
427
+ installSource?: DaemonInstallSource;
553
428
  retainMaterializedPaths?: boolean;
554
429
  materializedPathRetentionMs?: number;
555
430
  materializationId?: string;
@@ -557,25 +432,15 @@ declare type DaemonRequestMeta = {
557
432
  lockPlatform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
558
433
  };
559
434
 
560
- declare type DaemonRequestMeta_2 = Omit<DaemonRequestMeta, 'installSource' | 'lockPlatform'> & {
561
- installSource?: DaemonInstallSource;
562
- lockPlatform?: PlatformSelector;
563
- leaseBackend?: 'ios-simulator';
564
- };
565
-
566
- declare type DaemonResponse = DaemonResponse_2;
567
-
568
- declare type DaemonResponse_2 = {
435
+ declare type DaemonResponse = {
569
436
  ok: true;
570
- data?: DaemonResponseData_2;
437
+ data?: DaemonResponseData;
571
438
  } | {
572
439
  ok: false;
573
440
  error: DaemonError;
574
441
  };
575
442
 
576
- declare type DaemonResponseData = DaemonResponseData_2;
577
-
578
- declare type DaemonResponseData_2 = Record<string, unknown> & {
443
+ declare type DaemonResponseData = Record<string, unknown> & {
579
444
  artifacts?: DaemonArtifact[];
580
445
  };
581
446
 
@@ -708,15 +573,6 @@ export declare type MaterializationReleaseResult = {
708
573
  identifiers: AgentDeviceIdentifiers;
709
574
  };
710
575
 
711
- declare type MaterializeInstallSource = {
712
- kind: 'url';
713
- url: string;
714
- headers?: Record<string, string>;
715
- } | {
716
- kind: 'path';
717
- path: string;
718
- };
719
-
720
576
  declare type MetroBridgeResult = {
721
577
  enabled: boolean;
722
578
  baseUrl: string;
@@ -763,7 +619,7 @@ export declare type MetroPrepareOptions = {
763
619
  export declare type MetroPrepareResult = PrepareMetroRuntimeResult;
764
620
 
765
621
  /** Re-export of {@link SessionRuntimeHints} under the Metro-specific alias used by public API consumers. */
766
- declare type MetroRuntimeHints = SessionRuntimeHints_2;
622
+ declare type MetroRuntimeHints = SessionRuntimeHints;
767
623
 
768
624
  export declare type NetworkOptions = AgentDeviceRequestOverrides & {
769
625
  action?: 'dump' | 'log';
@@ -902,19 +758,6 @@ export declare type ScreenshotOverlayRef = {
902
758
  center: Point;
903
759
  };
904
760
 
905
- declare type ScrollIntoViewOptions_2 = ClientCommandBaseOptions & ({
906
- text: string;
907
- ref?: never;
908
- label?: never;
909
- } | {
910
- ref: string;
911
- label?: string;
912
- text?: never;
913
- }) & {
914
- maxScrolls?: number;
915
- };
916
- export { ScrollIntoViewOptions_2 as ScrollIntoViewOptions }
917
-
918
761
  declare type ScrollOptions_2 = ClientCommandBaseOptions & {
919
762
  direction: 'up' | 'down' | 'left' | 'right';
920
763
  amount?: number;
@@ -940,9 +783,7 @@ export declare type SessionCloseResult = {
940
783
 
941
784
  declare type SessionIsolationMode = 'none' | 'tenant';
942
785
 
943
- declare type SessionRuntimeHints = SessionRuntimeHints_2;
944
-
945
- declare type SessionRuntimeHints_2 = {
786
+ declare type SessionRuntimeHints = {
946
787
  platform?: 'ios' | 'android';
947
788
  metroHost?: string;
948
789
  metroPort?: number;
package/dist/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import e from"node:net";import t from"node:http";import a from"node:https";import r from"node:fs";import o from"node:path";import{fileURLToPath as n}from"node:url";import{AsyncLocalStorage as i}from"node:async_hooks";import s,{createHash as l}from"node:crypto";import"node:os";import{spawn as d}from"node:child_process";import{redactDiagnosticData as c,AppError as u}from"./152.js";import{resolveUserPath as p,expandUserHomePath as m}from"./267.js";import{runCmdDetached as f,runCmdSync as h}from"./818.js";import{prepareMetroRuntime as y,isAgentDeviceDaemonProcess as w,stopProcessForTakeover as v}from"./974.js";import{tryParseSelectorChain as g}from"./940.js";import{REMOTE_CONFIG_FIELD_SPECS as I,resolveRemoteConfigProfile as A,REMOTE_OPEN_PROFILE_KEYS as b}from"./924.js";function S(){let e=o.dirname(n(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=o.join(t,"package.json");if(r.existsSync(e))return t;t=o.dirname(t)}return e}let _=new i;function M(){return s.randomBytes(8).toString("hex")}function P(e){let t=_.getStore();if(!t)return;let a={ts:new Date().toISOString(),level:e.level??"info",phase:e.phase,session:t.session,requestId:t.requestId,command:t.command,durationMs:e.durationMs,data:e.data?c(e.data):void 0};if(t.events.push(a),!t.debug)return;let o=`[agent-device][diag] ${JSON.stringify(a)}
2
- `;try{t.logPath&&r.appendFile(t.logPath,o,()=>{}),t.traceLogPath&&r.appendFile(t.traceLogPath,o,()=>{}),t.logPath||t.traceLogPath||process.stderr.write(o)}catch{}}async function D(e,t,a){let r=Date.now();try{let o=await t();return P({level:"info",phase:e,durationMs:Date.now()-r,data:a}),o}catch(t){throw P({level:"error",phase:e,durationMs:Date.now()-r,data:{...a??{},error:t instanceof Error?t.message:String(t)}}),t}}function E(e){let t,a=(t=(e??"").trim())?p(t):o.join(m("~"),".agent-device");return{baseDir:a,infoPath:o.join(a,"daemon.json"),lockPath:o.join(a,"daemon.lock"),logPath:o.join(a,"daemon.log"),sessionsDir:o.join(a,"sessions")}}let k="sha256";async function T(e){let{localPath:n,baseUrl:i,token:s}=e,l=r.statSync(n),c=l.isDirectory(),p=o.basename(n),m=c?"app-bundle":"file",f=i.endsWith("/")?i:`${i}/`,h=c?void 0:await x(n);if(h){let e=await N({normalizedBase:f,token:s,hash:h,filename:p,sizeBytes:l.size,artifactType:m});if(e)return e}let y=new URL("upload",f),w="https:"===y.protocol?a:t,v={"x-artifact-type":m,"x-artifact-filename":p,"transfer-encoding":"chunked"};return h&&(v["x-artifact-hash"]=h,v["x-artifact-hash-algorithm"]=k),s&&(v.authorization=`Bearer ${s}`,v["x-agent-device-token"]=s),new Promise((e,t)=>{let a=w.request({protocol:y.protocol,host:y.hostname,port:y.port,method:"POST",path:y.pathname+y.search,headers:v},a=>{let r="";a.setEncoding("utf8"),a.on("data",e=>{r+=e}),a.on("end",()=>{clearTimeout(i);try{let a=JSON.parse(r);if(!a.ok||!a.uploadId)return void t(new u("COMMAND_FAILED",`Upload failed: ${r}`));e(a.uploadId)}catch{t(new u("COMMAND_FAILED",`Invalid upload response: ${r}`))}})}),i=setTimeout(()=>{a.destroy(),t(new u("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(a.on("error",e=>{clearTimeout(i),t(new u("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),c){let e=d("tar",["cf","-","-C",o.dirname(n),o.basename(n)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(a),e.on("error",e=>{a.destroy(),t(new u("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(a.destroy(),t(new u("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=r.createReadStream(n);e.pipe(a),e.on("error",e=>{a.destroy(),t(new u("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}async function N(e){var t;let a=new URL("upload/preflight",e.normalizedBase),r={"content-type":"application/json"};e.token&&(r.authorization=`Bearer ${e.token}`,r["x-agent-device-token"]=e.token);let o=await fetch(a,{method:"POST",headers:r,signal:AbortSignal.timeout(3e4),body:JSON.stringify({hash:e.hash,hashAlgorithm:k,fileName:e.filename,sizeBytes:e.sizeBytes,artifactType:e.artifactType})}).catch(()=>void 0);if(!o?.ok)return;let n=await o.json().catch(()=>void 0);return(t=n)&&"object"==typeof t&&!0===t.ok&&!0===t.cacheHit&&"string"==typeof t.uploadId?n.uploadId:void 0}async function x(e){let t=l(k);return await new Promise((a,o)=>{r.createReadStream(e).on("data",e=>t.update(e)).on("error",e=>{o(new u("COMMAND_FAILED","Failed to read local artifact",{},e))}).on("end",a)}),t.digest("hex")}let C=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,U=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,R=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function O(e,t,a){t.lastIndex=0;let r=null;for(;null!==(r=t.exec(e));){let e=r[1]?.trim();e?.startsWith(".")&&a.add(e)}}function L(e){try{return r.statSync(e).isFile()?e:null}catch{return null}}let F=ev(),$=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}(),j=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}(),q=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],B=new e.BlockList;async function z(t){let a=t.meta?.requestId??M(),r=!!(t.meta?.debug||t.flags?.verbose),o=function(t){let a,r,o,n=t.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR,i=function(e){let t;if(e){try{t=new URL(e)}catch(t){throw new u("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new u("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(t.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),s=t.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN;var l=i,d=s;if(!(!l||"localhost"===(a=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(e.isIPv4(a)?B.check(a,"ipv4"):!!e.isIPv6(a)&&B.check(a,"ipv6")))&&("string"!=typeof d||!(d.trim().length>0)))throw new u("INVALID_ARGS","Remote daemon base URL for non-loopback hosts requires daemon authentication",{daemonBaseUrl:l,hint:"Provide --daemon-auth-token or AGENT_DEVICE_DAEMON_AUTH_TOKEN when using a non-loopback remote daemon URL."});let c=t.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,p="auto"===(r=(c??"").trim().toLowerCase())?"auto":"socket"===r?"socket":"http"===r?"http":"auto";if(i&&"socket"===p)throw new u("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:i});let m="http"===(o=(t.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===c?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===o?"dual":"socket";return{paths:E(n),transportPreference:p,serverMode:m,remoteBaseUrl:i,remoteAuthToken:s}}(t),n=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return ev(t)}(t.command),i=await D("daemon_startup",async()=>await J(o),{requestId:a,session:t.session}),s=await V(t,i),l={...t,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...t.meta??{},requestId:a,debug:r,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,...s.uploadedArtifactId?{uploadedArtifactId:s.uploadedArtifactId}:{},...s.clientArtifactPaths?{clientArtifactPaths:s.clientArtifactPaths}:{},...s.installSource?{installSource:s.installSource}:{}}};return P({level:"info",phase:"daemon_request_prepare",data:{requestId:a,command:t.command,session:t.session}}),await D("daemon_request",async()=>await es(i,l,o.transportPreference,n),{requestId:a,command:t.command})}async function V(e,t){let a,n=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(ef(t)){let r=function(e,t){if("screenshot"===e.command){let a=K(e,"path",".png");return t[0]?{field:"path",localPath:a,positionalIndex:0,positionalPath:H("screenshot",".png")}:{field:"path",localPath:a,positionalIndex:0,flagPath:H("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=K(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:H("recording",o.extname(t)||".mp4")}}return null}(e,n);r&&(void 0!==r.positionalPath&&(n[r.positionalIndex]=r.positionalPath),void 0!==r.flagPath&&((i??={}).out=r.flagPath),l[r.field]=r.localPath);let d=await G(e,t);d&&(s=d.installSource,a=d.uploadedArtifactId??a)}if(!ef(t)||"install"!==e.command&&"reinstall"!==e.command||n.length<2)return{positionals:n,flags:i,installSource:s,uploadedArtifactId:a,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let d=n[1];if(d.startsWith("remote:"))return n[1]=d.slice(7),{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let c=o.isAbsolute(d)?d:o.resolve(e.meta?.cwd??process.cwd(),d);return r.existsSync(c)?{positionals:n,flags:i,installSource:s,uploadedArtifactId:a=await T({localPath:c,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function G(e,t){let a=e.meta?.installSource;if("install_source"!==e.command||!a||"path"!==a.kind)return null;let n=a.path.trim();if(!n)return{installSource:a};if(n.startsWith("remote:"))return{installSource:{...a,path:n.slice(7)}};let i=o.isAbsolute(n)?n:o.resolve(e.meta?.cwd??process.cwd(),n);if(!r.existsSync(i))return{installSource:{...a,path:i}};let s=await T({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...a,path:i},uploadedArtifactId:s}}function K(e,t,a,r=0){let n=e.positionals?.[r]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${a}`,s=n&&n.trim().length>0?n:i;return o.isAbsolute(s)?s:o.resolve(e.meta?.cwd??process.cwd(),s)}function H(e,t){let a=t.startsWith(".")?t:`.${t}`;return o.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${a}`)}async function J(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await eo(t,"http"))return t;throw new u("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 a=Z(e.paths.infoPath),n=function(){try{let e=S();return JSON.parse(r.readFileSync(o.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=S()){try{let a=o.resolve(t),n=[o.resolve(e)],i=new Set,l=[];for(;n.length>0;){let e=n.pop();if(!e||i.has(e))continue;i.add(e);let t=r.statSync(e);if(!t.isFile())continue;let s=o.relative(a,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let d=r.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return O(e,C,t),O(e,U,t),[...t]}(d)){let a=function(e,t){let a=o.resolve(o.dirname(e),t),r=L(a);if(r)return r;for(let e of R){let t=L(`${a}${e}`);if(t)return t}for(let e of R){let t=L(o.join(a,`index${e}`));if(t)return t}return null}(e,t);a&&n.push(a)}}let d=l.sort().join("|"),c=s.createHash("sha1").update(d).digest("hex");return`graph:${l.length}:${c}`}catch{return"unknown"}}((t=ei()).useSrc?t.srcPath:t.distPath,t.root),l=!!a&&await eo(a,e.transportPreference);if(a&&a.version===n&&a.codeSignature===i&&l)return a;a&&(a.version!==n||a.codeSignature!==i||!l)&&(await Y(a),er(e.paths.infoPath)),function(e){let t=et(e);if(!t.hasLock||t.hasInfo)return;let a=ee(e.lockPath);if(!a)return er(e.lockPath);w(a.pid,a.processStartTime)||er(e.lockPath)}(e.paths);let d=0;for(let t=1;t<=j;t+=1){await en(e);let a=await W($,e);if(a)return a;if(await X(e.paths)){d+=1;continue}let r=et(e.paths);if(!(t<j))break;if(!r.hasInfo&&!r.hasLock){await Q(150);continue}}let c=et(e.paths);throw new u("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:$,startupAttempts:j,lockRecoveryCount:d,metadataState:c,hint:function(e,t=E(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 W(e,t){let a=Date.now();for(;Date.now()-a<e;){let e=Z(t.paths.infoPath);if(e&&await eo(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function Q(e){await new Promise(t=>setTimeout(t,e))}async function X(e){let t=et(e);if(!t.hasLock||t.hasInfo)return!1;let a=ee(e.lockPath);return a&&w(a.pid,a.processStartTime)&&await v(a.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:a.processStartTime}),er(e.lockPath),!0}async function Y(e){await v(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function Z(e){let t=ea(e);if(!t||"object"!=typeof t)return null;let a="string"==typeof t.token&&t.token.length>0?t.token:null;if(!a)return null;let r=Number.isInteger(t.port)&&Number(t.port)>0,o=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!r&&!o)return null;let n=t.transport,i="string"==typeof t.version?t.version:void 0,s="string"==typeof t.codeSignature?t.codeSignature:void 0,l="string"==typeof t.processStartTime?t.processStartTime:void 0,d=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:a,port:r?Number(t.port):void 0,httpPort:o?Number(t.httpPort):void 0,transport:"socket"===n||"http"===n||"dual"===n?n:void 0,pid:d?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function ee(e){let t=ea(e);return t&&"object"==typeof t&&Number.isInteger(t.pid)&&Number(t.pid)>0?{pid:Number(t.pid),processStartTime:"string"==typeof t.processStartTime?t.processStartTime:void 0,startedAt:"number"==typeof t.startedAt?t.startedAt:void 0}:null}B.addSubnet("127.0.0.0",8,"ipv4"),B.addAddress("::1","ipv6"),B.addSubnet("::ffff:127.0.0.0",104,"ipv6");function et(e){return{hasInfo:r.existsSync(e.infoPath),hasLock:r.existsSync(e.lockPath)}}function ea(e){if(!r.existsSync(e))return null;try{return JSON.parse(r.readFileSync(e,"utf8"))}catch{return null}}function er(e){try{r.existsSync(e)&&r.unlinkSync(e)}catch{}}async function eo(r,o){var n;return"http"===el(r,o)?await function(e){let r=e.baseUrl?eh(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!r)return Promise.resolve(!1);let o=new URL(r),n="https:"===o.protocol?a:t,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=n.request({protocol:o.protocol,host:o.hostname,port:o.port,path:o.pathname+o.search,method:"GET",timeout:i},t=>{t.resume(),e((t.statusCode??500)<500)});t.on("timeout",()=>{t.destroy(),e(!1)}),t.on("error",()=>{e(!1)}),t.end()})}(r):await ((n=r.port)?new Promise(t=>{let a=e.createConnection({host:"127.0.0.1",port:n},()=>{a.destroy(),t(!0)});a.on("error",()=>{t(!1)})}):Promise.resolve(!1))}async function en(e){let t=ei(),a=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],r={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};f(process.execPath,a,{env:r})}function ei(){let e=S(),t=o.join(e,"dist","src","daemon.js"),a=o.join(e,"src","daemon.ts"),n=r.existsSync(t),i=r.existsSync(a);if(!n&&!i)throw new u("COMMAND_FAILED","Daemon entry not found",{distPath:t,srcPath:a});return{root:e,distPath:t,srcPath:a,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!n&&i}}async function es(e,t,a,r){return"http"===el(e,a)?await em(e,t,r):await ep(e,t,r)}function el(e,t){if(e.baseUrl){if("socket"===t)throw new u("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t||"socket"===t){var a=e,r=t;if(ed(a,r))return r;throw new u("COMMAND_FAILED","http"===r?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let o=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>ed(e,t));if(o)return o;throw new u("COMMAND_FAILED","Daemon metadata has no reachable transport")}function ed(e,t){return"http"===t?!!e.httpPort:!!e.port}function ec(e,t,a,r,o,n){let i=o?{terminated:0}:function(){let e=0;try{for(let t of q){let a=h("pkill",["-f",t],{allowFailure:!0});0===a.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}(),s=o?{forcedKill:!1}:function(e,t){let a=!1;try{w(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),a=!0)}catch{v(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{er(t.infoPath),er(t.lockPath)}return{forcedKill:a}}(e,t);return P({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:n,requestId:a,command:r,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:o?void 0:e.pid,daemonPidForceKilled:o?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new u("COMMAND_FAILED","Daemon request timed out",{timeoutMs:n,requestId:a,hint:o?"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."})}function eu(e,t,a){return P({level:"error",phase:"daemon_request_socket_error",data:{requestId:t,message:e instanceof Error?e.message:String(e)}}),new u("COMMAND_FAILED","Failed to communicate with daemon",{requestId:t,hint:a?"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 instanceof Error?e:void 0)}async function ep(t,a,r){let o=t.port;if(!o)throw new u("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((n,i)=>{let s=e.createConnection({host:"127.0.0.1",port:o},()=>{s.write(`${JSON.stringify(a)}
3
- `)}),l=E(a.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),d="number"==typeof r?setTimeout(()=>{s.destroy(),i(ec(t,l,a.meta?.requestId,a.command,!1,r))},r):void 0,c="";s.setEncoding("utf8"),s.on("data",e=>{let t=(c+=e).indexOf("\n");if(-1===t)return;let r=c.slice(0,t).trim();if(r)try{let e=JSON.parse(r);s.end(),d&&clearTimeout(d),n(e)}catch(e){d&&clearTimeout(d),i(new u("COMMAND_FAILED","Invalid daemon response",{requestId:a.meta?.requestId,line:r},e instanceof Error?e:void 0))}}),s.on("error",e=>{d&&clearTimeout(d),i(eu(e,a.meta?.requestId,!1))})})}async function em(e,r,o){let n=e.baseUrl?new URL(eh(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!n)throw new u("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:r.meta?.requestId??M(),method:"agent_device.command",params:r}),s={"content-type":"application/json","content-length":Buffer.byteLength(i)};return e.baseUrl&&e.token&&(s.authorization=`Bearer ${e.token}`,s["x-agent-device-token"]=e.token),await new Promise((l,d)=>{let c=E(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),p=("https:"===n.protocol?a:t).request({protocol:n.protocol,host:n.hostname,port:n.port,method:"POST",path:n.pathname+n.search,headers:s},t=>{let a="";t.setEncoding("utf8"),t.on("data",e=>{a+=e}),t.on("end",()=>{f&&clearTimeout(f);try{let t=JSON.parse(a);if(t.error){let e=t.error.data??{};d(new u(String(e.code??"COMMAND_FAILED"),String(e.message??t.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(!t.result||"object"!=typeof t.result)return void d(new u("COMMAND_FAILED","Invalid daemon RPC response",{requestId:r.meta?.requestId}));if(e.baseUrl&&t.result.ok)return void ey(e,r,t.result).then(l).catch(d);l(t.result)}catch(e){f&&clearTimeout(f),d(new u("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:a},e instanceof Error?e:void 0))}})}),m=ef(e),f="number"==typeof o?setTimeout(()=>{p.destroy(),d(ec(e,c,r.meta?.requestId,r.command,m,o))},o):void 0;p.on("error",e=>{f&&clearTimeout(f),d(eu(e,r.meta?.requestId,m))}),p.write(i),p.end()})}function ef(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function eh(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function ey(e,t,a){let r=Array.isArray(a.data?.artifacts)?a.data.artifacts:[];if(0===r.length||!e.baseUrl)return a;let n=a.data?{...a.data}:{},i=[];for(let a of r){if(!a||"object"!=typeof a||"string"!=typeof a.artifactId){i.push(a);continue}let r=function(e,t){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let a=e.fileName?.trim()||`${e.field}-${Date.now()}`;return o.resolve(t.meta?.cwd??process.cwd(),a)}(a,t);await ew({baseUrl:e.baseUrl,token:e.token,artifactId:a.artifactId,destinationPath:r,requestId:t.meta?.requestId}),n[a.field]=r,i.push({...a,localPath:r})}return n.artifacts=i,{ok:!0,data:n}}async function ew(e){var n,i;let s,l=new URL((n=e.baseUrl,i=e.artifactId,s=n.endsWith("/")?n:`${n}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),d="https:"===l.protocol?a:t;await r.promises.mkdir(o.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,a)=>{let o=!1,n=e.timeoutMs??F,i=n=>{if(!o){if(o=!0,clearTimeout(c),n)return void r.promises.rm(e.destinationPath,{force:!0}).finally(()=>a(n));t()}},s=d.request({protocol:l.protocol,host:l.hostname,port:l.port,method:"GET",path:l.pathname+l.search,headers:e.token?{authorization:`Bearer ${e.token}`,"x-agent-device-token":e.token}:void 0},t=>{if((t.statusCode??500)>=400){let a="";t.setEncoding("utf8"),t.on("data",e=>{a+=e}),t.on("end",()=>{i(new u("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:a}))});return}let a=r.createWriteStream(e.destinationPath);a.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 u("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),a.on("finish",()=>{a.close(()=>i())}),t.pipe(a)}),c=setTimeout(()=>{s.destroy(new u("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n}))},n);s.on("error",t=>{t instanceof u?i(t):i(new u("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n},t instanceof Error?t:void 0))}),s.end()})}function ev(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}let eg="clipboard",eI="wait",eA=I.map(e=>e.key);function eb(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function eS(e,t,a){return{deviceId:t,deviceName:a,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function e_(e,t,a,r){let o=a(e[t]);if(void 0===o)throw new u("COMMAND_FAILED",r,{response:e});return o}[...b];function eM(e,t){return e_(e,t,eN,`Daemon response is missing "${t}".`)}function eP(e,t){return eN(e[t])}function eD(e,t){var a;let r;return a=eN,null===(r=e[t])?null:a(r)}function eE(e,t){return e_(e,t,eC,`Daemon response has invalid "${t}".`)}function ek(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function eT(e,t){let a=e[t];if(!eO(a))return;let r="number"==typeof a.x?a.x:void 0,o="number"==typeof a.y?a.y:void 0,n="number"==typeof a.width?a.width:void 0,i="number"==typeof a.height?a.height:void 0;if(void 0!==r&&void 0!==o&&void 0!==n&&void 0!==i)return{x:r,y:o,width:n,height:i}}function eN(e){return"string"==typeof e&&e.length>0?e:void 0}function ex(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function eC(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function eU(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function eR(e){if(!eO(e))throw new u("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eO(e){return"object"==typeof e&&null!==e}function eL(e){let t={};for(let[a,r]of Object.entries(e))void 0!==r&&(t[a]=r);return t}function eF(e,t){let a=eP(e,"bundleId"),r=eP(e,"package");return{app:eM(e,"app"),appPath:eM(e,"appPath"),platform:eE(e,"platform"),appId:a??r,bundleId:a,package:r,identifiers:eb({session:t,bundleId:a,packageName:r})}}function e$(e){let t=eR(e),a=eE(t,"platform"),r=eM(t,"id"),o=eM(t,"name");return{platform:a,target:ek(t,"target"),kind:e_(t,"kind",eU,'Daemon response has invalid "kind".'),id:r,name:o,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:eS(a,r,o),ios:"ios"===a?{udid:r}:void 0,android:"android"===a?{serial:r}:void 0}}function ej(e){let t=eR(e),a=eE(t,"platform"),r=eM(t,"id"),o=eM(t,"name"),n=ek(t,"target"),i=eM(t,"device"),s={session:o,...eS(a,r,i)};return{name:o,createdAt:e_(t,"createdAt",ex,'Daemon response is missing numeric "createdAt".'),device:{platform:a,target:n,id:r,name:i,identifiers:s,ios:"ios"===a?{udid:r,simulatorSetPath:eD(t,"ios_simulator_device_set")}:void 0,android:"android"===a?{serial:r}:void 0},identifiers:s}}function eq(e){return e??"default"}function eB(e={},t={}){var a;let r,o=t.transport??z,n=eH(e),i=async(t,a=[],r={})=>{let i=eK(e,n,r),s=await o({session:eq(i.session),command:t,positionals:a,flags:eL({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,platform:i.platform,target:i.target,device:i.device,udid:i.udid,serial:i.serial,iosSimulatorDeviceSet:i.iosSimulatorDeviceSet,androidDeviceAllowlist:i.androidDeviceAllowlist,runtime:i.simulatorRuntimeId,boot:i.boot,reuseExisting:i.reuseExisting,surface:i.surface,activity:i.activity,relaunch:i.relaunch,shutdown:i.shutdown,saveScript:i.saveScript,noRecord:i.noRecord,backMode:i.backMode,metroHost:i.metroHost,metroPort:i.metroPort,bundleUrl:i.bundleUrl,launchUrl:i.launchUrl,snapshotInteractiveOnly:i.interactiveOnly,snapshotCompact:i.compact,snapshotDepth:i.depth,snapshotScope:i.scope,snapshotRaw:i.raw,screenshotFullscreen:i.screenshotFullscreen,overlayRefs:i.overlayRefs,appsFilter:i.appsFilter,out:i.out,count:i.count,fps:i.fps,hideTouches:i.hideTouches,intervalMs:i.intervalMs,delayMs:i.delayMs,holdMs:i.holdMs,jitterPx:i.jitterPx,pixels:i.pixels,doubleTap:i.doubleTap,clickButton:i.clickButton,pauseMs:i.pauseMs,pattern:i.pattern,maxScrolls:i.maxScrolls,headless:i.headless,restart:i.restart,replayUpdate:i.replayUpdate,failFast:i.failFast,timeoutMs:i.timeoutMs,retries:i.retries,artifactsDir:i.artifactsDir,reportJunit:i.reportJunit,findFirst:i.findFirst,findLast:i.findLast,networkInclude:i.networkInclude,batchOnError:i.batchOnError,batchMaxSteps:i.batchMaxSteps,batchSteps:i.batchSteps,verbose:i.debug}),runtime:i.runtime,meta:eL({requestId:i.requestId,cwd:i.cwd,debug:i.debug,lockPolicy:i.lockPolicy,lockPlatform:i.lockPlatform,tenantId:i.tenant,runId:i.runId,leaseId:i.leaseId,sessionIsolation:i.sessionIsolation,installSource:i.installSource,retainMaterializedPaths:i.retainMaterializedPaths,materializedPathRetentionMs:i.materializedPathRetentionMs,materializationId:i.materializationId})});return s.ok||function(e){throw new u(e.code,e.message,{...e.details??{},hint:e.hint,diagnosticId:e.diagnosticId,logPath:e.logPath})}(s.error),s.data??{}},s=async(e={})=>{let t=await i("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(ej)},l=async(e,t=[],a={})=>await i(e,t,a),d=(t={})=>eq(eK(e,n,t).session);return{command:(a=async e=>await i(e.command,e.positionals,e.options),r=async e=>await a(e),{wait:async e=>await r(function(e){if(1!==[void 0!==e.durationMs?"durationMs":void 0,void 0!==e.text?"text":void 0,void 0!==e.ref?"ref":void 0,void 0!==e.selector?"selector":void 0].filter(Boolean).length)throw new u("INVALID_ARGS","wait command requires exactly one of durationMs, text, ref, or selector.");if(void 0!==e.durationMs)return{command:eI,positionals:[String(e.durationMs)],options:e};let t=void 0!==e.timeoutMs?[String(e.timeoutMs)]:[];if(void 0!==e.text)return{command:eI,positionals:["text",e.text,...t],options:e};if(void 0!==e.ref)return{command:eI,positionals:[e.ref,...t],options:e};let a=e.selector;return function(e){if(!g(e))throw new u("INVALID_ARGS",`Invalid wait selector: ${e}`)}(a),{command:eI,positionals:[a,...t],options:e}}(e)),alert:async(e={})=>{var t;return await r({command:"alert",positionals:[(t=e).action??"get",...void 0!==t.timeoutMs?[String(t.timeoutMs)]:[]],options:t})},appState:async(e={})=>await r({command:"appstate",positionals:[],options:e}),back:async(e={})=>await r({command:"back",positionals:[],options:{...e,backMode:e.mode}}),home:async(e={})=>await r({command:"home",positionals:[],options:e}),rotate:async e=>await r({command:"rotate",positionals:[e.orientation],options:e}),appSwitcher:async(e={})=>await r({command:"app-switcher",positionals:[],options:e}),keyboard:async(e={})=>await r({command:"keyboard",positionals:e.action?[e.action]:[],options:e}),clipboard:async e=>{var t;return await r("read"===(t=e).action?{command:eg,positionals:["read"],options:t}:{command:eg,positionals:["write",t.text],options:t})}}),devices:{list:async(e={})=>{let t=await i("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(e$)},boot:async(e={})=>await l("boot",[],e)},sessions:{list:async(e={})=>await s(e),close:async(e={})=>{let t=d(e),a=(await i("close",[],e)).shutdown;return{session:t,shutdown:"object"==typeof a&&null!==a?a:void 0,identifiers:{session:t}}}},simulators:{ensure:async e=>{let{runtime:t,...a}=e,r=await i("ensure-simulator",[],{...a,simulatorRuntimeId:t}),o=eM(r,"udid"),n=eM(r,"device");return{udid:o,device:n,runtime:eM(r,"runtime"),created:!0===r.created,booted:!0===r.booted,iosSimulatorDeviceSet:eD(r,"ios_simulator_device_set"),identifiers:{deviceId:o,deviceName:n,udid:o}}}},apps:{install:async e=>eF(await i("install",[e.app,e.appPath],e),d(e)),reinstall:async e=>eF(await i("reinstall",[e.app,e.appPath],e),d(e)),installFromSource:async e=>(function(e,t){let a=eP(e,"bundleId"),r=eP(e,"packageName"),o=a??r??eP(e,"appId"),n=eP(e,"launchTarget")??r??a??o;if(!n)throw new u("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:eP(e,"appName"),appId:o,bundleId:a,packageName:r,launchTarget:n,installablePath:eP(e,"installablePath"),archivePath:eP(e,"archivePath"),materializationId:eP(e,"materializationId"),materializationExpiresAt:eP(e,"materializationExpiresAt"),identifiers:eb({session:t,bundleId:a,packageName:r,appId:o})}})(await i("install_source",[],{...e,installSource:e.source,retainMaterializedPaths:e.retainPaths,materializedPathRetentionMs:e.retentionMs}),d(e)),list:async(e={})=>{let t=await i("apps",[],e);return Array.isArray(t.apps)?t.apps.filter(e=>"string"==typeof e):[]},open:async e=>{let t=d(e),a=e.app?e.url?[e.app,e.url]:[e.app]:[],r=await i("open",a,e),o=function(e){let t=e.platform,a=eP(e,"id"),r=eP(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!a||!r)return;let o=ek(e,"target"),n=eS(t,a,r);return{platform:t,target:o,id:a,name:r,identifiers:n,ios:"ios"===t?{udid:eP(e,"device_udid")??a,simulatorSetPath:eD(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:eP(e,"serial")??a}:void 0}}(r),n=eP(r,"appBundleId");return{session:t,appName:eP(r,"appName"),appBundleId:n,appId:n,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:eP(e,"appTarget"),appBundleId:eP(e,"appBundleId")}}(r.startup),runtime:function(e){if(!eO(e))return;let t=e.platform,a=eP(e,"metroHost"),r="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:a,metroPort:r,bundleUrl:eP(e,"bundleUrl"),launchUrl:eP(e,"launchUrl")}}(r.runtime),device:o,identifiers:{session:t,deviceId:o?.id,deviceName:o?.name,udid:o?.ios?.udid,serial:o?.android?.serial,appId:n,appBundleId:n}}},close:async(e={})=>{let t=d(e),a=(await i("close",e.app?[e.app]:[],e)).shutdown;return{session:t,closedApp:e.app,shutdown:"object"==typeof a&&null!==a?a:void 0,identifiers:{session:t}}},push:async e=>{var t;return await l("push",[e.app,"string"==typeof(t=e.payload)?t:JSON.stringify(t)],e)},triggerEvent:async e=>{var t;return await l("trigger-app-event",[(t=e).event,...t.payload?[JSON.stringify(t.payload)]:[]],e)}},materializations:{release:async e=>{var t;return{released:!0===(t=await i("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:eM(t,"materializationId"),identifiers:{}}}},metro:{prepare:async t=>await y({projectRoot:t.projectRoot??e.cwd,kind:t.kind,publicBaseUrl:t.publicBaseUrl,proxyBaseUrl:t.proxyBaseUrl,proxyBearerToken:t.bearerToken,launchUrl:t.launchUrl,companionProfileKey:t.companionProfileKey,companionConsumerKey:t.companionConsumerKey,metroPort:t.port,listenHost:t.listenHost,statusHost:t.statusHost,startupTimeoutMs:t.startupTimeoutMs,probeTimeoutMs:t.probeTimeoutMs,reuseExisting:t.reuseExisting,installDependenciesIfNeeded:t.installDependenciesIfNeeded,runtimeFilePath:t.runtimeFilePath,logPath:t.logPath})},capture:{snapshot:async(e={})=>{var t;let a=d(e),r=await i("snapshot",[],e),o=eP(r,"appBundleId"),n="object"==typeof r.visibility&&null!==r.visibility?r.visibility:void 0;return{nodes:Array.isArray(t=r.nodes)?t:[],truncated:!0===r.truncated,appName:eP(r,"appName"),appBundleId:o,...n?{visibility:n}:{},warnings:Array.isArray(r.warnings)?r.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:a,appId:o,appBundleId:o}}},screenshot:async(e={})=>{let t=d(e),a=await i("screenshot",e.path?[e.path]:[],{...e,screenshotFullscreen:e.fullscreen});return{path:eM(a,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let a=[];for(let e of t){if(!eO(e))continue;let t=eP(e,"ref"),r=eT(e,"rect"),o=eT(e,"overlayRect"),n=function(e,t){let a=e[t];if(!eO(a))return;let r="number"==typeof a.x?a.x:void 0,o="number"==typeof a.y?a.y:void 0;if(void 0!==r&&void 0!==o)return{x:r,y:o}}(e,"center");t&&r&&o&&n&&a.push({ref:t,label:eP(e,"label"),rect:r,overlayRect:o,center:n})}return a}(a),identifiers:{session:t}}},diff:async e=>await l("diff",[e.kind],{...e,interactiveOnly:e.interactiveOnly,compact:e.compact,depth:e.depth,scope:e.scope,raw:e.raw})},interactions:{click:async e=>await l("click",ez(e),{...e,clickButton:e.button}),press:async e=>await l("press",ez(e),e),longPress:async e=>await l("longpress",[String(e.x),String(e.y),...eG(e.durationMs)],e),swipe:async e=>await l("swipe",[String(e.from.x),String(e.from.y),String(e.to.x),String(e.to.y),...eG(e.durationMs)],e),focus:async e=>await l("focus",[String(e.x),String(e.y)],e),type:async e=>await l("type",[e.text],e),fill:async e=>await l("fill",[...ez(e),e.text],e),scroll:async e=>await l("scroll",[e.direction,...eG(e.amount)],e),scrollIntoView:async e=>{var t;return await l("scrollintoview",void 0!==(t=e).ref?[t.ref,...eV(t.label)]:[t.text??""],e)},pinch:async e=>await l("pinch",[String(e.scale),...eG(e.x),...eG(e.y)],e),get:async e=>{var t;return await l("get",[e.format,...void 0!==(t=e).ref?[t.ref,...eV(t.label)]:[t.selector]],e)},is:async e=>await l("is",[e.predicate,e.selector,..."text"===e.predicate?[e.value]:[]],e),find:async e=>await l("find",function(e){let t=e.locator&&"any"!==e.locator?[e.locator,e.query]:[e.query];switch(e.action){case void 0:case"click":case"focus":case"exists":return e.action?[...t,e.action]:t;case"getText":return[...t,"get","text"];case"getAttrs":return[...t,"get","attrs"];case"wait":return[...t,"wait",...eG(e.timeoutMs)];case"fill":case"type":return[...t,e.action,e.value]}}(e),{...e,findFirst:e.first,findLast:e.last})},replay:{run:async e=>await l("replay",[e.path],{...e,replayUpdate:e.update}),test:async e=>await l("test",e.paths,{...e,replayUpdate:e.update})},batch:{run:async e=>await l("batch",[],{...e,batchSteps:e.steps,batchOnError:e.onError,batchMaxSteps:e.maxSteps})},observability:{perf:async(e={})=>await l("perf",[],e),logs:async(e={})=>{var t;return await l("logs",[(t=e).action??"path",...eV(t.message)],e)},network:async(e={})=>{var t;return await l("network",[...(t=e).action?[t.action]:[],...eG(t.limit)],{...e,networkInclude:e.include})}},recording:{record:async e=>await l("record",[e.action,...eV(e.path)],e),trace:async e=>await l("trace",[e.action,...eV(e.path)],e)},settings:{update:async e=>await l("settings",[e.setting,e.state,..."permission"in e?[e.permission]:[],..."mode"in e&&e.mode?[e.mode]:[]],e)}}}function ez(e){return void 0!==e.ref?[e.ref,...eV(e.label)]:void 0!==e.selector?[e.selector]:[String(e.x),String(e.y)]}function eV(e){return void 0===e?[]:[e]}function eG(e){return void 0===e?[]:[String(e)]}function eK(e,t,a){return a.remoteConfig&&a.remoteConfig!==e.remoteConfig?{...eH({...e,...a}),...e,...a}:{...t,...e,...a}}function eH(e){var t;if(!e.remoteConfig)return{};let{runtime:a,...r}=(t={remoteConfig:e.remoteConfig,cwd:e.cwd??process.cwd(),env:process.env}).remoteConfig?{...function(e){let t={};for(let a of eA){let r=e[a];void 0!==r&&(t[a]=r)}return t}(A({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}).profile),remoteConfig:t.remoteConfig}:{};return r}export{AppError}from"./152.js";export{centerOfRect}from"./57.js";export{eB as createAgentDeviceClient};
2
+ `;try{t.logPath&&r.appendFile(t.logPath,o,()=>{}),t.traceLogPath&&r.appendFile(t.traceLogPath,o,()=>{}),t.logPath||t.traceLogPath||process.stderr.write(o)}catch{}}async function D(e,t,a){let r=Date.now();try{let o=await t();return P({level:"info",phase:e,durationMs:Date.now()-r,data:a}),o}catch(t){throw P({level:"error",phase:e,durationMs:Date.now()-r,data:{...a??{},error:t instanceof Error?t.message:String(t)}}),t}}function E(e){let t,a=(t=(e??"").trim())?p(t):o.join(m("~"),".agent-device");return{baseDir:a,infoPath:o.join(a,"daemon.json"),lockPath:o.join(a,"daemon.lock"),logPath:o.join(a,"daemon.log"),sessionsDir:o.join(a,"sessions")}}let k="sha256";async function T(e){let{localPath:n,baseUrl:i,token:s}=e,l=r.statSync(n),c=l.isDirectory(),p=o.basename(n),m=c?"app-bundle":"file",f=i.endsWith("/")?i:`${i}/`,h=c?void 0:await x(n);if(h){let e=await N({normalizedBase:f,token:s,hash:h,filename:p,sizeBytes:l.size,artifactType:m});if(e)return e}let y=new URL("upload",f),w="https:"===y.protocol?a:t,v={"x-artifact-type":m,"x-artifact-filename":p,"transfer-encoding":"chunked"};return h&&(v["x-artifact-hash"]=h,v["x-artifact-hash-algorithm"]=k),s&&(v.authorization=`Bearer ${s}`,v["x-agent-device-token"]=s),new Promise((e,t)=>{let a=w.request({protocol:y.protocol,host:y.hostname,port:y.port,method:"POST",path:y.pathname+y.search,headers:v},a=>{let r="";a.setEncoding("utf8"),a.on("data",e=>{r+=e}),a.on("end",()=>{clearTimeout(i);try{let a=JSON.parse(r);if(!a.ok||!a.uploadId)return void t(new u("COMMAND_FAILED",`Upload failed: ${r}`));e(a.uploadId)}catch{t(new u("COMMAND_FAILED",`Invalid upload response: ${r}`))}})}),i=setTimeout(()=>{a.destroy(),t(new u("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(a.on("error",e=>{clearTimeout(i),t(new u("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),c){let e=d("tar",["cf","-","-C",o.dirname(n),o.basename(n)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(a),e.on("error",e=>{a.destroy(),t(new u("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(a.destroy(),t(new u("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=r.createReadStream(n);e.pipe(a),e.on("error",e=>{a.destroy(),t(new u("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}async function N(e){var t;let a=new URL("upload/preflight",e.normalizedBase),r={"content-type":"application/json"};e.token&&(r.authorization=`Bearer ${e.token}`,r["x-agent-device-token"]=e.token);let o=await fetch(a,{method:"POST",headers:r,signal:AbortSignal.timeout(3e4),body:JSON.stringify({hash:e.hash,hashAlgorithm:k,fileName:e.filename,sizeBytes:e.sizeBytes,artifactType:e.artifactType})}).catch(()=>void 0);if(!o?.ok)return;let n=await o.json().catch(()=>void 0);return(t=n)&&"object"==typeof t&&!0===t.ok&&!0===t.cacheHit&&"string"==typeof t.uploadId?n.uploadId:void 0}async function x(e){let t=l(k);return await new Promise((a,o)=>{r.createReadStream(e).on("data",e=>t.update(e)).on("error",e=>{o(new u("COMMAND_FAILED","Failed to read local artifact",{},e))}).on("end",a)}),t.digest("hex")}let C=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,U=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,R=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function O(e,t,a){t.lastIndex=0;let r=null;for(;null!==(r=t.exec(e));){let e=r[1]?.trim();e?.startsWith(".")&&a.add(e)}}function L(e){try{return r.statSync(e).isFile()?e:null}catch{return null}}let F=ev(),$=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}(),j=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}(),q=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],B=new e.BlockList;async function z(t){let a=t.meta?.requestId??M(),r=!!(t.meta?.debug||t.flags?.verbose),o=function(t){let a,r,o,n=t.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR,i=function(e){let t;if(e){try{t=new URL(e)}catch(t){throw new u("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new u("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(t.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),s=t.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN;var l=i,d=s;if(!(!l||"localhost"===(a=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(e.isIPv4(a)?B.check(a,"ipv4"):!!e.isIPv6(a)&&B.check(a,"ipv6")))&&("string"!=typeof d||!(d.trim().length>0)))throw new u("INVALID_ARGS","Remote daemon base URL for non-loopback hosts requires daemon authentication",{daemonBaseUrl:l,hint:"Provide --daemon-auth-token or AGENT_DEVICE_DAEMON_AUTH_TOKEN when using a non-loopback remote daemon URL."});let c=t.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,p="auto"===(r=(c??"").trim().toLowerCase())?"auto":"socket"===r?"socket":"http"===r?"http":"auto";if(i&&"socket"===p)throw new u("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:i});let m="http"===(o=(t.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===c?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===o?"dual":"socket";return{paths:E(n),transportPreference:p,serverMode:m,remoteBaseUrl:i,remoteAuthToken:s}}(t),n=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return ev(t)}(t.command),i=await D("daemon_startup",async()=>await J(o),{requestId:a,session:t.session}),s=await G(t,i),l={...t,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...t.meta??{},requestId:a,debug:r,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,...s.uploadedArtifactId?{uploadedArtifactId:s.uploadedArtifactId}:{},...s.clientArtifactPaths?{clientArtifactPaths:s.clientArtifactPaths}:{},...s.installSource?{installSource:s.installSource}:{}}};return P({level:"info",phase:"daemon_request_prepare",data:{requestId:a,command:t.command,session:t.session}}),await D("daemon_request",async()=>await es(i,l,o.transportPreference,n),{requestId:a,command:t.command})}async function G(e,t){let a,n=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(ef(t)){let r=function(e,t){if("screenshot"===e.command){let a=V(e,"path",".png");return t[0]?{field:"path",localPath:a,positionalIndex:0,positionalPath:H("screenshot",".png")}:{field:"path",localPath:a,positionalIndex:0,flagPath:H("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=V(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:H("recording",o.extname(t)||".mp4")}}return null}(e,n);r&&(void 0!==r.positionalPath&&(n[r.positionalIndex]=r.positionalPath),void 0!==r.flagPath&&((i??={}).out=r.flagPath),l[r.field]=r.localPath);let d=await K(e,t);d&&(s=d.installSource,a=d.uploadedArtifactId??a)}if(!ef(t)||"install"!==e.command&&"reinstall"!==e.command||n.length<2)return{positionals:n,flags:i,installSource:s,uploadedArtifactId:a,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let d=n[1];if(d.startsWith("remote:"))return n[1]=d.slice(7),{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let c=o.isAbsolute(d)?d:o.resolve(e.meta?.cwd??process.cwd(),d);return r.existsSync(c)?{positionals:n,flags:i,installSource:s,uploadedArtifactId:a=await T({localPath:c,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function K(e,t){let a=e.meta?.installSource;if("install_source"!==e.command||!a||"path"!==a.kind)return null;let n=a.path.trim();if(!n)return{installSource:a};if(n.startsWith("remote:"))return{installSource:{...a,path:n.slice(7)}};let i=o.isAbsolute(n)?n:o.resolve(e.meta?.cwd??process.cwd(),n);if(!r.existsSync(i))return{installSource:{...a,path:i}};let s=await T({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...a,path:i},uploadedArtifactId:s}}function V(e,t,a,r=0){let n=e.positionals?.[r]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${a}`,s=n&&n.trim().length>0?n:i;return o.isAbsolute(s)?s:o.resolve(e.meta?.cwd??process.cwd(),s)}function H(e,t){let a=t.startsWith(".")?t:`.${t}`;return o.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${a}`)}async function J(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await eo(t,"http"))return t;throw new u("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 a=Z(e.paths.infoPath),n=function(){try{let e=S();return JSON.parse(r.readFileSync(o.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=S()){try{let a=o.resolve(t),n=[o.resolve(e)],i=new Set,l=[];for(;n.length>0;){let e=n.pop();if(!e||i.has(e))continue;i.add(e);let t=r.statSync(e);if(!t.isFile())continue;let s=o.relative(a,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let d=r.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return O(e,C,t),O(e,U,t),[...t]}(d)){let a=function(e,t){let a=o.resolve(o.dirname(e),t),r=L(a);if(r)return r;for(let e of R){let t=L(`${a}${e}`);if(t)return t}for(let e of R){let t=L(o.join(a,`index${e}`));if(t)return t}return null}(e,t);a&&n.push(a)}}let d=l.sort().join("|"),c=s.createHash("sha1").update(d).digest("hex");return`graph:${l.length}:${c}`}catch{return"unknown"}}((t=ei()).useSrc?t.srcPath:t.distPath,t.root),l=!!a&&await eo(a,e.transportPreference);if(a&&a.version===n&&a.codeSignature===i&&l)return a;a&&(a.version!==n||a.codeSignature!==i||!l)&&(await Y(a),er(e.paths.infoPath)),function(e){let t=et(e);if(!t.hasLock||t.hasInfo)return;let a=ee(e.lockPath);if(!a)return er(e.lockPath);w(a.pid,a.processStartTime)||er(e.lockPath)}(e.paths);let d=0;for(let t=1;t<=j;t+=1){await en(e);let a=await W($,e);if(a)return a;if(await X(e.paths)){d+=1;continue}let r=et(e.paths);if(!(t<j))break;if(!r.hasInfo&&!r.hasLock){await Q(150);continue}}let c=et(e.paths);throw new u("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:$,startupAttempts:j,lockRecoveryCount:d,metadataState:c,hint:function(e,t=E(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 W(e,t){let a=Date.now();for(;Date.now()-a<e;){let e=Z(t.paths.infoPath);if(e&&await eo(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function Q(e){await new Promise(t=>setTimeout(t,e))}async function X(e){let t=et(e);if(!t.hasLock||t.hasInfo)return!1;let a=ee(e.lockPath);return a&&w(a.pid,a.processStartTime)&&await v(a.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:a.processStartTime}),er(e.lockPath),!0}async function Y(e){await v(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function Z(e){let t=ea(e);if(!t||"object"!=typeof t)return null;let a="string"==typeof t.token&&t.token.length>0?t.token:null;if(!a)return null;let r=Number.isInteger(t.port)&&Number(t.port)>0,o=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!r&&!o)return null;let n=t.transport,i="string"==typeof t.version?t.version:void 0,s="string"==typeof t.codeSignature?t.codeSignature:void 0,l="string"==typeof t.processStartTime?t.processStartTime:void 0,d=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:a,port:r?Number(t.port):void 0,httpPort:o?Number(t.httpPort):void 0,transport:"socket"===n||"http"===n||"dual"===n?n:void 0,pid:d?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function ee(e){let t=ea(e);return t&&"object"==typeof t&&Number.isInteger(t.pid)&&Number(t.pid)>0?{pid:Number(t.pid),processStartTime:"string"==typeof t.processStartTime?t.processStartTime:void 0,startedAt:"number"==typeof t.startedAt?t.startedAt:void 0}:null}B.addSubnet("127.0.0.0",8,"ipv4"),B.addAddress("::1","ipv6"),B.addSubnet("::ffff:127.0.0.0",104,"ipv6");function et(e){return{hasInfo:r.existsSync(e.infoPath),hasLock:r.existsSync(e.lockPath)}}function ea(e){if(!r.existsSync(e))return null;try{return JSON.parse(r.readFileSync(e,"utf8"))}catch{return null}}function er(e){try{r.existsSync(e)&&r.unlinkSync(e)}catch{}}async function eo(r,o){var n;return"http"===el(r,o)?await function(e){let r=e.baseUrl?eh(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!r)return Promise.resolve(!1);let o=new URL(r),n="https:"===o.protocol?a:t,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=n.request({protocol:o.protocol,host:o.hostname,port:o.port,path:o.pathname+o.search,method:"GET",timeout:i},t=>{t.resume(),e((t.statusCode??500)<500)});t.on("timeout",()=>{t.destroy(),e(!1)}),t.on("error",()=>{e(!1)}),t.end()})}(r):await ((n=r.port)?new Promise(t=>{let a=e.createConnection({host:"127.0.0.1",port:n},()=>{a.destroy(),t(!0)});a.on("error",()=>{t(!1)})}):Promise.resolve(!1))}async function en(e){let t=ei(),a=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],r={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};f(process.execPath,a,{env:r})}function ei(){let e=S(),t=o.join(e,"dist","src","daemon.js"),a=o.join(e,"src","daemon.ts"),n=r.existsSync(t),i=r.existsSync(a);if(!n&&!i)throw new u("COMMAND_FAILED","Daemon entry not found",{distPath:t,srcPath:a});return{root:e,distPath:t,srcPath:a,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!n&&i}}async function es(e,t,a,r){return"http"===el(e,a)?await em(e,t,r):await ep(e,t,r)}function el(e,t){if(e.baseUrl){if("socket"===t)throw new u("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t||"socket"===t){var a=e,r=t;if(ed(a,r))return r;throw new u("COMMAND_FAILED","http"===r?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let o=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>ed(e,t));if(o)return o;throw new u("COMMAND_FAILED","Daemon metadata has no reachable transport")}function ed(e,t){return"http"===t?!!e.httpPort:!!e.port}function ec(e,t,a,r,o,n){let i=o?{terminated:0}:function(){let e=0;try{for(let t of q){let a=h("pkill",["-f",t],{allowFailure:!0});0===a.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}(),s=o?{forcedKill:!1}:function(e,t){let a=!1;try{w(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),a=!0)}catch{v(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{er(t.infoPath),er(t.lockPath)}return{forcedKill:a}}(e,t);return P({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:n,requestId:a,command:r,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:o?void 0:e.pid,daemonPidForceKilled:o?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new u("COMMAND_FAILED","Daemon request timed out",{timeoutMs:n,requestId:a,hint:o?"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."})}function eu(e,t,a){return P({level:"error",phase:"daemon_request_socket_error",data:{requestId:t,message:e instanceof Error?e.message:String(e)}}),new u("COMMAND_FAILED","Failed to communicate with daemon",{requestId:t,hint:a?"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 instanceof Error?e:void 0)}async function ep(t,a,r){let o=t.port;if(!o)throw new u("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((n,i)=>{let s=e.createConnection({host:"127.0.0.1",port:o},()=>{s.write(`${JSON.stringify(a)}
3
+ `)}),l=E(a.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),d="number"==typeof r?setTimeout(()=>{s.destroy(),i(ec(t,l,a.meta?.requestId,a.command,!1,r))},r):void 0,c="";s.setEncoding("utf8"),s.on("data",e=>{let t=(c+=e).indexOf("\n");if(-1===t)return;let r=c.slice(0,t).trim();if(r)try{let e=JSON.parse(r);s.end(),d&&clearTimeout(d),n(e)}catch(e){d&&clearTimeout(d),i(new u("COMMAND_FAILED","Invalid daemon response",{requestId:a.meta?.requestId,line:r},e instanceof Error?e:void 0))}}),s.on("error",e=>{d&&clearTimeout(d),i(eu(e,a.meta?.requestId,!1))})})}async function em(e,r,o){let n=e.baseUrl?new URL(eh(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!n)throw new u("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:r.meta?.requestId??M(),method:"agent_device.command",params:r}),s={"content-type":"application/json","content-length":Buffer.byteLength(i)};return e.baseUrl&&e.token&&(s.authorization=`Bearer ${e.token}`,s["x-agent-device-token"]=e.token),await new Promise((l,d)=>{let c=E(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),p=("https:"===n.protocol?a:t).request({protocol:n.protocol,host:n.hostname,port:n.port,method:"POST",path:n.pathname+n.search,headers:s},t=>{let a="";t.setEncoding("utf8"),t.on("data",e=>{a+=e}),t.on("end",()=>{f&&clearTimeout(f);try{let t=JSON.parse(a);if(t.error){let e=t.error.data??{};d(new u(String(e.code??"COMMAND_FAILED"),String(e.message??t.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(!t.result||"object"!=typeof t.result)return void d(new u("COMMAND_FAILED","Invalid daemon RPC response",{requestId:r.meta?.requestId}));if(e.baseUrl&&t.result.ok)return void ey(e,r,t.result).then(l).catch(d);l(t.result)}catch(e){f&&clearTimeout(f),d(new u("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:a},e instanceof Error?e:void 0))}})}),m=ef(e),f="number"==typeof o?setTimeout(()=>{p.destroy(),d(ec(e,c,r.meta?.requestId,r.command,m,o))},o):void 0;p.on("error",e=>{f&&clearTimeout(f),d(eu(e,r.meta?.requestId,m))}),p.write(i),p.end()})}function ef(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function eh(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function ey(e,t,a){let r=Array.isArray(a.data?.artifacts)?a.data.artifacts:[];if(0===r.length||!e.baseUrl)return a;let n=a.data?{...a.data}:{},i=[];for(let a of r){if(!a||"object"!=typeof a||"string"!=typeof a.artifactId){i.push(a);continue}let r=function(e,t){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let a=e.fileName?.trim()||`${e.field}-${Date.now()}`;return o.resolve(t.meta?.cwd??process.cwd(),a)}(a,t);await ew({baseUrl:e.baseUrl,token:e.token,artifactId:a.artifactId,destinationPath:r,requestId:t.meta?.requestId}),n[a.field]=r,i.push({...a,localPath:r})}return n.artifacts=i,{ok:!0,data:n}}async function ew(e){var n,i;let s,l=new URL((n=e.baseUrl,i=e.artifactId,s=n.endsWith("/")?n:`${n}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),d="https:"===l.protocol?a:t;await r.promises.mkdir(o.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,a)=>{let o=!1,n=e.timeoutMs??F,i=n=>{if(!o){if(o=!0,clearTimeout(c),n)return void r.promises.rm(e.destinationPath,{force:!0}).finally(()=>a(n));t()}},s=d.request({protocol:l.protocol,host:l.hostname,port:l.port,method:"GET",path:l.pathname+l.search,headers:e.token?{authorization:`Bearer ${e.token}`,"x-agent-device-token":e.token}:void 0},t=>{if((t.statusCode??500)>=400){let a="";t.setEncoding("utf8"),t.on("data",e=>{a+=e}),t.on("end",()=>{i(new u("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:a}))});return}let a=r.createWriteStream(e.destinationPath);a.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 u("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),a.on("finish",()=>{a.close(()=>i())}),t.pipe(a)}),c=setTimeout(()=>{s.destroy(new u("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n}))},n);s.on("error",t=>{t instanceof u?i(t):i(new u("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:n},t instanceof Error?t:void 0))}),s.end()})}function ev(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}let eg="clipboard",eI="wait",eA=I.map(e=>e.key);function eb(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function eS(e,t,a){return{deviceId:t,deviceName:a,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function e_(e,t,a,r){let o=a(e[t]);if(void 0===o)throw new u("COMMAND_FAILED",r,{response:e});return o}[...b];function eM(e,t){return e_(e,t,eN,`Daemon response is missing "${t}".`)}function eP(e,t){return eN(e[t])}function eD(e,t){var a;let r;return a=eN,null===(r=e[t])?null:a(r)}function eE(e,t){return e_(e,t,eC,`Daemon response has invalid "${t}".`)}function ek(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function eT(e,t){let a=e[t];if(!eO(a))return;let r="number"==typeof a.x?a.x:void 0,o="number"==typeof a.y?a.y:void 0,n="number"==typeof a.width?a.width:void 0,i="number"==typeof a.height?a.height:void 0;if(void 0!==r&&void 0!==o&&void 0!==n&&void 0!==i)return{x:r,y:o,width:n,height:i}}function eN(e){return"string"==typeof e&&e.length>0?e:void 0}function ex(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function eC(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function eU(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function eR(e){if(!eO(e))throw new u("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eO(e){return"object"==typeof e&&null!==e}function eL(e){let t={};for(let[a,r]of Object.entries(e))void 0!==r&&(t[a]=r);return t}function eF(e,t){let a=eP(e,"bundleId"),r=eP(e,"package");return{app:eM(e,"app"),appPath:eM(e,"appPath"),platform:eE(e,"platform"),appId:a??r,bundleId:a,package:r,identifiers:eb({session:t,bundleId:a,packageName:r})}}function e$(e){let t=eR(e),a=eE(t,"platform"),r=eM(t,"id"),o=eM(t,"name");return{platform:a,target:ek(t,"target"),kind:e_(t,"kind",eU,'Daemon response has invalid "kind".'),id:r,name:o,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:eS(a,r,o),ios:"ios"===a?{udid:r}:void 0,android:"android"===a?{serial:r}:void 0}}function ej(e){let t=eR(e),a=eE(t,"platform"),r=eM(t,"id"),o=eM(t,"name"),n=ek(t,"target"),i=eM(t,"device"),s={session:o,...eS(a,r,i)};return{name:o,createdAt:e_(t,"createdAt",ex,'Daemon response is missing numeric "createdAt".'),device:{platform:a,target:n,id:r,name:i,identifiers:s,ios:"ios"===a?{udid:r,simulatorSetPath:eD(t,"ios_simulator_device_set")}:void 0,android:"android"===a?{serial:r}:void 0},identifiers:s}}function eq(e){return e??"default"}function eB(e={},t={}){var a;let r,o=t.transport??z,n=eH(e),i=async(t,a=[],r={})=>{let i=eV(e,n,r),s=await o({session:eq(i.session),command:t,positionals:a,flags:eL({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,platform:i.platform,target:i.target,device:i.device,udid:i.udid,serial:i.serial,iosSimulatorDeviceSet:i.iosSimulatorDeviceSet,androidDeviceAllowlist:i.androidDeviceAllowlist,runtime:i.simulatorRuntimeId,boot:i.boot,reuseExisting:i.reuseExisting,surface:i.surface,activity:i.activity,relaunch:i.relaunch,shutdown:i.shutdown,saveScript:i.saveScript,noRecord:i.noRecord,backMode:i.backMode,metroHost:i.metroHost,metroPort:i.metroPort,bundleUrl:i.bundleUrl,launchUrl:i.launchUrl,snapshotInteractiveOnly:i.interactiveOnly,snapshotCompact:i.compact,snapshotDepth:i.depth,snapshotScope:i.scope,snapshotRaw:i.raw,screenshotFullscreen:i.screenshotFullscreen,overlayRefs:i.overlayRefs,appsFilter:i.appsFilter,out:i.out,count:i.count,fps:i.fps,hideTouches:i.hideTouches,intervalMs:i.intervalMs,delayMs:i.delayMs,holdMs:i.holdMs,jitterPx:i.jitterPx,pixels:i.pixels,doubleTap:i.doubleTap,clickButton:i.clickButton,pauseMs:i.pauseMs,pattern:i.pattern,headless:i.headless,restart:i.restart,replayUpdate:i.replayUpdate,failFast:i.failFast,timeoutMs:i.timeoutMs,retries:i.retries,artifactsDir:i.artifactsDir,reportJunit:i.reportJunit,findFirst:i.findFirst,findLast:i.findLast,networkInclude:i.networkInclude,batchOnError:i.batchOnError,batchMaxSteps:i.batchMaxSteps,batchSteps:i.batchSteps,verbose:i.debug}),runtime:i.runtime,meta:eL({requestId:i.requestId,cwd:i.cwd,debug:i.debug,lockPolicy:i.lockPolicy,lockPlatform:i.lockPlatform,tenantId:i.tenant,runId:i.runId,leaseId:i.leaseId,sessionIsolation:i.sessionIsolation,installSource:i.installSource,retainMaterializedPaths:i.retainMaterializedPaths,materializedPathRetentionMs:i.materializedPathRetentionMs,materializationId:i.materializationId})});return s.ok||function(e){throw new u(e.code,e.message,{...e.details??{},hint:e.hint,diagnosticId:e.diagnosticId,logPath:e.logPath})}(s.error),s.data??{}},s=async(e={})=>{let t=await i("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(ej)},l=async(e,t=[],a={})=>await i(e,t,a),d=(t={})=>eq(eV(e,n,t).session);return{command:(a=async e=>await i(e.command,e.positionals,e.options),r=async e=>await a(e),{wait:async e=>await r(function(e){if(1!==[void 0!==e.durationMs?"durationMs":void 0,void 0!==e.text?"text":void 0,void 0!==e.ref?"ref":void 0,void 0!==e.selector?"selector":void 0].filter(Boolean).length)throw new u("INVALID_ARGS","wait command requires exactly one of durationMs, text, ref, or selector.");if(void 0!==e.durationMs)return{command:eI,positionals:[String(e.durationMs)],options:e};let t=void 0!==e.timeoutMs?[String(e.timeoutMs)]:[];if(void 0!==e.text)return{command:eI,positionals:["text",e.text,...t],options:e};if(void 0!==e.ref)return{command:eI,positionals:[e.ref,...t],options:e};let a=e.selector;return function(e){if(!g(e))throw new u("INVALID_ARGS",`Invalid wait selector: ${e}`)}(a),{command:eI,positionals:[a,...t],options:e}}(e)),alert:async(e={})=>{var t;return await r({command:"alert",positionals:[(t=e).action??"get",...void 0!==t.timeoutMs?[String(t.timeoutMs)]:[]],options:t})},appState:async(e={})=>await r({command:"appstate",positionals:[],options:e}),back:async(e={})=>await r({command:"back",positionals:[],options:{...e,backMode:e.mode}}),home:async(e={})=>await r({command:"home",positionals:[],options:e}),rotate:async e=>await r({command:"rotate",positionals:[e.orientation],options:e}),appSwitcher:async(e={})=>await r({command:"app-switcher",positionals:[],options:e}),keyboard:async(e={})=>await r({command:"keyboard",positionals:e.action?[e.action]:[],options:e}),clipboard:async e=>{var t;return await r("read"===(t=e).action?{command:eg,positionals:["read"],options:t}:{command:eg,positionals:["write",t.text],options:t})}}),devices:{list:async(e={})=>{let t=await i("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(e$)},boot:async(e={})=>await l("boot",[],e)},sessions:{list:async(e={})=>await s(e),close:async(e={})=>{let t=d(e),a=(await i("close",[],e)).shutdown;return{session:t,shutdown:"object"==typeof a&&null!==a?a:void 0,identifiers:{session:t}}}},simulators:{ensure:async e=>{let{runtime:t,...a}=e,r=await i("ensure-simulator",[],{...a,simulatorRuntimeId:t}),o=eM(r,"udid"),n=eM(r,"device");return{udid:o,device:n,runtime:eM(r,"runtime"),created:!0===r.created,booted:!0===r.booted,iosSimulatorDeviceSet:eD(r,"ios_simulator_device_set"),identifiers:{deviceId:o,deviceName:n,udid:o}}}},apps:{install:async e=>eF(await i("install",[e.app,e.appPath],e),d(e)),reinstall:async e=>eF(await i("reinstall",[e.app,e.appPath],e),d(e)),installFromSource:async e=>(function(e,t){let a=eP(e,"bundleId"),r=eP(e,"packageName"),o=a??r??eP(e,"appId"),n=eP(e,"launchTarget")??r??a??o;if(!n)throw new u("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:eP(e,"appName"),appId:o,bundleId:a,packageName:r,launchTarget:n,installablePath:eP(e,"installablePath"),archivePath:eP(e,"archivePath"),materializationId:eP(e,"materializationId"),materializationExpiresAt:eP(e,"materializationExpiresAt"),identifiers:eb({session:t,bundleId:a,packageName:r,appId:o})}})(await i("install_source",[],{...e,installSource:e.source,retainMaterializedPaths:e.retainPaths,materializedPathRetentionMs:e.retentionMs}),d(e)),list:async(e={})=>{let t=await i("apps",[],e);return Array.isArray(t.apps)?t.apps.filter(e=>"string"==typeof e):[]},open:async e=>{let t=d(e),a=e.app?e.url?[e.app,e.url]:[e.app]:[],r=await i("open",a,e),o=function(e){let t=e.platform,a=eP(e,"id"),r=eP(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!a||!r)return;let o=ek(e,"target"),n=eS(t,a,r);return{platform:t,target:o,id:a,name:r,identifiers:n,ios:"ios"===t?{udid:eP(e,"device_udid")??a,simulatorSetPath:eD(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:eP(e,"serial")??a}:void 0}}(r),n=eP(r,"appBundleId");return{session:t,appName:eP(r,"appName"),appBundleId:n,appId:n,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:eP(e,"appTarget"),appBundleId:eP(e,"appBundleId")}}(r.startup),runtime:function(e){if(!eO(e))return;let t=e.platform,a=eP(e,"metroHost"),r="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:a,metroPort:r,bundleUrl:eP(e,"bundleUrl"),launchUrl:eP(e,"launchUrl")}}(r.runtime),device:o,identifiers:{session:t,deviceId:o?.id,deviceName:o?.name,udid:o?.ios?.udid,serial:o?.android?.serial,appId:n,appBundleId:n}}},close:async(e={})=>{let t=d(e),a=(await i("close",e.app?[e.app]:[],e)).shutdown;return{session:t,closedApp:e.app,shutdown:"object"==typeof a&&null!==a?a:void 0,identifiers:{session:t}}},push:async e=>{var t;return await l("push",[e.app,"string"==typeof(t=e.payload)?t:JSON.stringify(t)],e)},triggerEvent:async e=>{var t;return await l("trigger-app-event",[(t=e).event,...t.payload?[JSON.stringify(t.payload)]:[]],e)}},materializations:{release:async e=>{var t;return{released:!0===(t=await i("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:eM(t,"materializationId"),identifiers:{}}}},metro:{prepare:async t=>await y({projectRoot:t.projectRoot??e.cwd,kind:t.kind,publicBaseUrl:t.publicBaseUrl,proxyBaseUrl:t.proxyBaseUrl,proxyBearerToken:t.bearerToken,launchUrl:t.launchUrl,companionProfileKey:t.companionProfileKey,companionConsumerKey:t.companionConsumerKey,metroPort:t.port,listenHost:t.listenHost,statusHost:t.statusHost,startupTimeoutMs:t.startupTimeoutMs,probeTimeoutMs:t.probeTimeoutMs,reuseExisting:t.reuseExisting,installDependenciesIfNeeded:t.installDependenciesIfNeeded,runtimeFilePath:t.runtimeFilePath,logPath:t.logPath})},capture:{snapshot:async(e={})=>{var t;let a=d(e),r=await i("snapshot",[],e),o=eP(r,"appBundleId"),n="object"==typeof r.visibility&&null!==r.visibility?r.visibility:void 0;return{nodes:Array.isArray(t=r.nodes)?t:[],truncated:!0===r.truncated,appName:eP(r,"appName"),appBundleId:o,...n?{visibility:n}:{},warnings:Array.isArray(r.warnings)?r.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:a,appId:o,appBundleId:o}}},screenshot:async(e={})=>{let t=d(e),a=await i("screenshot",e.path?[e.path]:[],{...e,screenshotFullscreen:e.fullscreen});return{path:eM(a,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let a=[];for(let e of t){if(!eO(e))continue;let t=eP(e,"ref"),r=eT(e,"rect"),o=eT(e,"overlayRect"),n=function(e,t){let a=e[t];if(!eO(a))return;let r="number"==typeof a.x?a.x:void 0,o="number"==typeof a.y?a.y:void 0;if(void 0!==r&&void 0!==o)return{x:r,y:o}}(e,"center");t&&r&&o&&n&&a.push({ref:t,label:eP(e,"label"),rect:r,overlayRect:o,center:n})}return a}(a),identifiers:{session:t}}},diff:async e=>await l("diff",[e.kind],{...e,interactiveOnly:e.interactiveOnly,compact:e.compact,depth:e.depth,scope:e.scope,raw:e.raw})},interactions:{click:async e=>await l("click",ez(e),{...e,clickButton:e.button}),press:async e=>await l("press",ez(e),e),longPress:async e=>await l("longpress",[String(e.x),String(e.y),...eK(e.durationMs)],e),swipe:async e=>await l("swipe",[String(e.from.x),String(e.from.y),String(e.to.x),String(e.to.y),...eK(e.durationMs)],e),focus:async e=>await l("focus",[String(e.x),String(e.y)],e),type:async e=>await l("type",[e.text],e),fill:async e=>await l("fill",[...ez(e),e.text],e),scroll:async e=>await l("scroll",[e.direction,...eK(e.amount)],e),pinch:async e=>await l("pinch",[String(e.scale),...eK(e.x),...eK(e.y)],e),get:async e=>{var t;return await l("get",[e.format,...void 0!==(t=e).ref?[t.ref,...eG(t.label)]:[t.selector]],e)},is:async e=>await l("is",[e.predicate,e.selector,..."text"===e.predicate?[e.value]:[]],e),find:async e=>await l("find",function(e){let t=e.locator&&"any"!==e.locator?[e.locator,e.query]:[e.query];switch(e.action){case void 0:case"click":case"focus":case"exists":return e.action?[...t,e.action]:t;case"getText":return[...t,"get","text"];case"getAttrs":return[...t,"get","attrs"];case"wait":return[...t,"wait",...eK(e.timeoutMs)];case"fill":case"type":return[...t,e.action,e.value]}}(e),{...e,findFirst:e.first,findLast:e.last})},replay:{run:async e=>await l("replay",[e.path],{...e,replayUpdate:e.update}),test:async e=>await l("test",e.paths,{...e,replayUpdate:e.update})},batch:{run:async e=>await l("batch",[],{...e,batchSteps:e.steps,batchOnError:e.onError,batchMaxSteps:e.maxSteps})},observability:{perf:async(e={})=>await l("perf",[],e),logs:async(e={})=>{var t;return await l("logs",[(t=e).action??"path",...eG(t.message)],e)},network:async(e={})=>{var t;return await l("network",[...(t=e).action?[t.action]:[],...eK(t.limit)],{...e,networkInclude:e.include})}},recording:{record:async e=>await l("record",[e.action,...eG(e.path)],e),trace:async e=>await l("trace",[e.action,...eG(e.path)],e)},settings:{update:async e=>await l("settings",[e.setting,e.state,..."permission"in e?[e.permission]:[],..."mode"in e&&e.mode?[e.mode]:[]],e)}}}function ez(e){return void 0!==e.ref?[e.ref,...eG(e.label)]:void 0!==e.selector?[e.selector]:[String(e.x),String(e.y)]}function eG(e){return void 0===e?[]:[e]}function eK(e){return void 0===e?[]:[String(e)]}function eV(e,t,a){return a.remoteConfig&&a.remoteConfig!==e.remoteConfig?{...eH({...e,...a}),...e,...a}:{...t,...e,...a}}function eH(e){var t;if(!e.remoteConfig)return{};let{runtime:a,...r}=(t={remoteConfig:e.remoteConfig,cwd:e.cwd??process.cwd(),env:process.env}).remoteConfig?{...function(e){let t={};for(let a of eA){let r=e[a];void 0!==r&&(t[a]=r)}return t}(A({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}).profile),remoteConfig:t.remoteConfig}:{};return r}export{AppError}from"./152.js";export{centerOfRect}from"./57.js";export{eB as createAgentDeviceClient};
@@ -1 +1 @@
1
- import t from"node:dns/promises";import e from"node:net";import{promises as a}from"node:fs";import r from"node:os";import o from"node:path";import{AppError as i}from"./152.js";import{runCmd as n}from"./818.js";import{expandUserHomePath as s}from"./267.js";let l=[".zip",".tar",".tar.gz",".tgz"],c=Object.freeze([...l]),h=function(t){if(!t)return 12e4;let e=Number(t);return Number.isFinite(e)?Math.max(1e3,Math.floor(e)):12e4}(process.env.AGENT_DEVICE_SOURCE_DOWNLOAD_TIMEOUT_MS),u=["1","true","yes","on"];async function d(t){let e=[];try{let a=await w(t.source,{signal:t.signal,downloadTimeoutMs:t.downloadTimeoutMs});e.push(a.cleanup);let r=await _(a.localPath,{archivePath:void 0,isInstallablePath:t.isInstallablePath,installableLabel:t.installableLabel,allowArchiveExtraction:!1!==t.allowArchiveExtraction,registerCleanup:t=>{e.push(t)}});return{archivePath:r.archivePath,installablePath:r.installablePath,cleanup:async()=>{await E(e)}}}catch(t){throw await E(e),t}}async function w(t,e){if("path"===t.kind)return{localPath:s(t.path),cleanup:async()=>{}};let i=await a.mkdtemp(o.join(r.tmpdir(),"agent-device-source-"));try{return{localPath:await p(i,t.url,t.headers,e),cleanup:async()=>{await a.rm(i,{recursive:!0,force:!0})}}}catch(t){throw await a.rm(i,{recursive:!0,force:!0}),t}}async function p(t,e,r,n){let s;try{s=new URL(e)}catch{throw new i("INVALID_ARGS",`Invalid source URL: ${e}`)}await f(s);let l=n?.signal;if(l?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"});let c=new AbortController,u=()=>{c.abort(l?.reason)};l?.addEventListener("abort",u,{once:!0});let d=n?.downloadTimeoutMs??h,w=setTimeout(()=>{c.abort(Error("download timeout"))},d);try{let e=await fetch(s,{headers:r,redirect:"follow",signal:c.signal});if(!e.ok)throw new i("COMMAND_FAILED",`Failed to download app source: ${e.status} ${e.statusText}`,{status:e.status,statusText:e.statusText,url:s.toString()});let n=function(t,e){let a=t.headers.get("content-disposition"),r=a?.match(/filename\*?=(?:UTF-8'')?"?([^";]+)"?/i),i=r?.[1]?.trim();if(i)return o.basename(i);let n=o.basename(e.pathname);return n||"downloaded-artifact.bin"}(e,s),l=o.join(t,n),h=e.body;if(!h)throw new i("COMMAND_FAILED","Download response body was empty",{url:s.toString()});let u=await a.open(l,"w");try{for await(let t of h)await u.write(t)}finally{await u.close()}return l}catch(t){if(l?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"},t);if(c.signal.aborted)throw new i("COMMAND_FAILED",`App source download timed out after ${d}ms`,{timeoutMs:d,url:s.toString()},t);throw t}finally{l?.removeEventListener("abort",u),clearTimeout(w)}}async function f(e){if("http:"!==e.protocol&&"https:"!==e.protocol)throw new i("INVALID_ARGS",`Unsupported source URL protocol: ${e.protocol}`);if(!u.includes((process.env.AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS??"").toLowerCase())){if(A(e.hostname.toLowerCase()))throw new i("INVALID_ARGS",`Source URL host is not allowed: ${e.hostname}`,{hint:"Use a public artifact URL, or set AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS=1 for trusted private-network daemons."});if((await t.lookup(e.hostname,{all:!0,verbatim:!0}).catch(()=>[])).some(t=>L(t.address)))throw new i("INVALID_ARGS",`Source URL host resolved to a private or loopback address: ${e.hostname}`,{hint:"Use a public artifact URL, or set AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS=1 for trusted private-network daemons."})}}function m(t){var e,a,r,o;let i=t instanceof URL?t:new URL(t),n=i.hostname.toLowerCase();if(!n)return!1;let s=i.pathname;return e=n,a=s,("api.github.com"===e?/^\/repos\/[^/]+\/[^/]+\/actions\/artifacts\/\d+\/zip$/i.test(a):"github.com"===e&&/^\/[^/]+\/[^/]+\/(?:actions\/runs\/\d+\/artifacts\/\d+|suites\/\d+\/artifacts\/\d+)$/i.test(a))||(r=n,o=s,("expo.dev"===r||!!r.endsWith(".expo.dev"))&&/^\/(?:artifacts\/eas\/|accounts\/[^/]+\/projects\/[^/]+\/builds\/)/i.test(o))}function A(t){return!!(!t||"localhost"===t||t.endsWith(".localhost"))||L(t)}function L(t){let a,r=e.isIP(t);return 4===r?function(t){let e=t.split(".").map(t=>Number.parseInt(t,10));if(4!==e.length||e.some(t=>Number.isNaN(t)||t<0||t>255))return!1;let[a,r]=e;return 10===a||127===a||169===a&&254===r||172===a&&!!(r>=16)&&!!(r<=31)||192===a&&168===r}(t):6===r&&!!("::1"===(a=t.toLowerCase())||a.startsWith("fc")||a.startsWith("fd")||a.startsWith("fe80:"))}async function _(t,e){let r=await a.stat(t).catch(()=>null);if(!r)throw new i("INVALID_ARGS",`App source not found: ${t}`);if(e.isInstallablePath(t,r))return{archivePath:e.archivePath,installablePath:t};if(r.isFile()&&v(t)){if(!e.allowArchiveExtraction)throw new i("INVALID_ARGS",`URL sources must point directly to a ${e.installableLabel}; archive extraction is not allowed`,{path:t});let a=await I(t);return e.registerCleanup(a.cleanup),await _(a.outputPath,{...e,archivePath:e.archivePath??t})}if(r.isDirectory()){let a=await b(t,e.isInstallablePath);if(1===a.length)return{archivePath:e.archivePath,installablePath:a[0]};if(a.length>1)throw new i("INVALID_ARGS",`Found multiple ${e.installableLabel} candidates under ${t}`,{matches:a});let r=await b(t,(t,e)=>e.isFile()&&v(t));if(1===r.length){if(!e.allowArchiveExtraction)throw new i("INVALID_ARGS",`URL sources must point directly to a ${e.installableLabel}; nested archives are not allowed`,{path:r[0]});let t=await I(r[0]);return e.registerCleanup(t.cleanup),await _(t.outputPath,{...e,archivePath:e.archivePath??r[0]})}if(r.length>1)throw new i("INVALID_ARGS",`Found multiple nested archives under ${t}; expected one ${e.installableLabel} source`,{matches:r})}throw new i("INVALID_ARGS",`Expected ${e.installableLabel} source, but got ${t}`)}async function b(t,e){let r=[],i=[{path:t,depth:0}];for(;i.length>0;){let t=i.shift();if(!t)continue;let n=await a.readdir(t.path,{withFileTypes:!0});for(let a of(n.sort((t,e)=>t.name.localeCompare(e.name)),n)){let n=o.join(t.path,a.name);if(e(n,a)){r.push(n);continue}a.isDirectory()&&t.depth<5&&i.push({path:n,depth:t.depth+1})}}return r}async function I(t){let e=await a.mkdtemp(o.join(r.tmpdir(),"agent-device-archive-"));try{return t.toLowerCase().endsWith(".zip")?await n("ditto",["-x","-k",t,e]):t.toLowerCase().endsWith(".tar.gz")||t.toLowerCase().endsWith(".tgz")?await n("tar",["-xzf",t,"-C",e]):await n("tar",["-xf",t,"-C",e]),{outputPath:e,cleanup:async()=>{await a.rm(e,{recursive:!0,force:!0})}}}catch(t){throw await a.rm(e,{recursive:!0,force:!0}),t}}function v(t){let e=t.toLowerCase();return l.some(t=>e.endsWith(t))}async function E(t){for(let e=t.length-1;e>=0;e-=1)await t[e]()}export{c as ARCHIVE_EXTENSIONS,L as isBlockedIpAddress,A as isBlockedSourceHostname,m as isTrustedInstallSourceUrl,d as materializeInstallablePath,f as validateDownloadSourceUrl};
1
+ import t from"node:dns/promises";import e from"node:net";import{promises as a}from"node:fs";import r from"node:os";import o from"node:path";import{AppError as i}from"./152.js";import{runCmd as n}from"./818.js";import{expandUserHomePath as s}from"./267.js";let l=[".zip",".tar",".tar.gz",".tgz"],c=Object.freeze([...l]),h=function(t){if(!t)return 12e4;let e=Number(t);return Number.isFinite(e)?Math.max(1e3,Math.floor(e)):12e4}(process.env.AGENT_DEVICE_SOURCE_DOWNLOAD_TIMEOUT_MS),u=["1","true","yes","on"];async function d(t){let e=[];try{let a=await w(t.source,{signal:t.signal,downloadTimeoutMs:t.downloadTimeoutMs});e.push(a.cleanup);let r=await _(a.localPath,{archivePath:void 0,isInstallablePath:t.isInstallablePath,installableLabel:t.installableLabel,allowArchiveExtraction:!1!==t.allowArchiveExtraction,registerCleanup:t=>{e.push(t)}});return{archivePath:r.archivePath,installablePath:r.installablePath,cleanup:async()=>{await C(e)}}}catch(t){throw await C(e),t}}async function w(t,e){if("path"===t.kind)return{localPath:s(t.path),cleanup:async()=>{}};let i=await a.mkdtemp(o.join(r.tmpdir(),"agent-device-source-"));try{return{localPath:await p(i,t.url,t.headers,e),cleanup:async()=>{await a.rm(i,{recursive:!0,force:!0})}}}catch(t){throw await a.rm(i,{recursive:!0,force:!0}),t}}async function p(t,e,r,n){let s;try{s=new URL(e)}catch{throw new i("INVALID_ARGS",`Invalid source URL: ${e}`)}await f(s);let l=n?.signal;if(l?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"});let c=new AbortController,u=()=>{c.abort(l?.reason)};l?.addEventListener("abort",u,{once:!0});let d=n?.downloadTimeoutMs??h,w=setTimeout(()=>{c.abort(Error("download timeout"))},d);try{let e=await fetch(s,{headers:r,redirect:"follow",signal:c.signal});if(!e.ok)throw new i("COMMAND_FAILED",`Failed to download app source: ${e.status} ${e.statusText}`,{status:e.status,statusText:e.statusText,url:s.toString()});let n=function(t,e){let a=t.headers.get("content-disposition"),r=a?.match(/filename\*?=(?:UTF-8'')?"?([^";]+)"?/i),i=r?.[1]?.trim();if(i)return o.basename(i);let n=o.basename(e.pathname);return n||"downloaded-artifact.bin"}(e,s),l=o.join(t,n),h=e.body;if(!h)throw new i("COMMAND_FAILED","Download response body was empty",{url:s.toString()});let u=await a.open(l,"w");try{for await(let t of h)await u.write(t)}finally{await u.close()}return l}catch(t){if(l?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"},t);if(c.signal.aborted)throw new i("COMMAND_FAILED",`App source download timed out after ${d}ms`,{timeoutMs:d,url:s.toString()},t);throw t}finally{l?.removeEventListener("abort",u),clearTimeout(w)}}async function f(e){if("http:"!==e.protocol&&"https:"!==e.protocol)throw new i("INVALID_ARGS",`Unsupported source URL protocol: ${e.protocol}`);if(!u.includes((process.env.AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS??"").toLowerCase())){if(A(e.hostname.toLowerCase()))throw new i("INVALID_ARGS",`Source URL host is not allowed: ${e.hostname}`,{hint:"Use a public artifact URL, or set AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS=1 for trusted private-network daemons."});if((await t.lookup(e.hostname,{all:!0,verbatim:!0}).catch(()=>[])).some(t=>L(t.address)))throw new i("INVALID_ARGS",`Source URL host resolved to a private or loopback address: ${e.hostname}`,{hint:"Use a public artifact URL, or set AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS=1 for trusted private-network daemons."})}}function m(t){var e,a,r,o;let i=t instanceof URL?t:new URL(t),n=i.hostname.toLowerCase();if(!n)return!1;let s=i.pathname;return e=n,a=s,("api.github.com"===e?/^\/repos\/[^/]+\/[^/]+\/actions\/artifacts\/\d+\/zip$/i.test(a):"github.com"===e&&/^\/[^/]+\/[^/]+\/(?:actions\/runs\/\d+\/artifacts\/\d+|suites\/\d+\/artifacts\/\d+)$/i.test(a))||(r=n,o=s,("expo.dev"===r||!!r.endsWith(".expo.dev"))&&/^\/(?:artifacts\/eas\/|accounts\/[^/]+\/projects\/[^/]+\/builds\/)/i.test(o))}function A(t){return!!(!t||"localhost"===t||t.endsWith(".localhost"))||L(t)}function L(t){let a,r=e.isIP(t);return 4===r?function(t){let e=t.split(".").map(t=>Number.parseInt(t,10));if(4!==e.length||e.some(t=>Number.isNaN(t)||t<0||t>255))return!1;let[a,r]=e;return 10===a||127===a||169===a&&254===r||172===a&&!!(r>=16)&&!!(r<=31)||192===a&&168===r}(t):6===r&&!!("::1"===(a=t.toLowerCase())||a.startsWith("fc")||a.startsWith("fd")||a.startsWith("fe80:"))}async function _(t,e){let r=await a.stat(t).catch(()=>null);if(!r)throw new i("INVALID_ARGS",`App source not found: ${t}`);if(e.isInstallablePath(t,r))return{archivePath:e.archivePath,installablePath:t};if(r.isFile()&&E(t)){if(!e.allowArchiveExtraction)throw new i("INVALID_ARGS",`URL sources must point directly to a ${e.installableLabel}; archive extraction is not allowed`,{path:t});let a=await I(t);return e.registerCleanup(a.cleanup),await _(a.outputPath,{...e,archivePath:e.archivePath??t})}if(r.isDirectory()){let a=await b(t,e.isInstallablePath);if(1===a.length)return{archivePath:e.archivePath,installablePath:a[0]};if(a.length>1)throw new i("INVALID_ARGS",`Found multiple ${e.installableLabel} candidates under ${t}`,{matches:a});let r=await b(t,(t,e)=>e.isFile()&&E(t));if(1===r.length){if(!e.allowArchiveExtraction)throw new i("INVALID_ARGS",`URL sources must point directly to a ${e.installableLabel}; nested archives are not allowed`,{path:r[0]});let t=await I(r[0]);return e.registerCleanup(t.cleanup),await _(t.outputPath,{...e,archivePath:e.archivePath??r[0]})}if(r.length>1)throw new i("INVALID_ARGS",`Found multiple nested archives under ${t}; expected one ${e.installableLabel} source`,{matches:r})}throw new i("INVALID_ARGS",`Expected ${e.installableLabel} source, but got ${t}`)}async function b(t,e){let r=[],i=[{path:t,depth:0}];for(;i.length>0;){let t=i.shift();if(!t)continue;let n=await a.readdir(t.path,{withFileTypes:!0});for(let a of(n.sort((t,e)=>t.name.localeCompare(e.name)),n)){let n=o.join(t.path,a.name);if(e(n,a)){r.push(n);continue}a.isDirectory()&&t.depth<5&&i.push({path:n,depth:t.depth+1})}}return r}async function I(t){let e=await a.mkdtemp(o.join(r.tmpdir(),"agent-device-archive-"));try{return t.toLowerCase().endsWith(".zip")?await v(t,e):t.toLowerCase().endsWith(".tar.gz")||t.toLowerCase().endsWith(".tgz")?await n("tar",["-xzf",t,"-C",e]):await n("tar",["-xf",t,"-C",e]),{outputPath:e,cleanup:async()=>{await a.rm(e,{recursive:!0,force:!0})}}}catch(t){throw await a.rm(e,{recursive:!0,force:!0}),t}}async function v(t,e){await n("unzip",["-q",t,"-d",e])}function E(t){let e=t.toLowerCase();return l.some(t=>e.endsWith(t))}async function C(t){for(let e=t.length-1;e>=0;e-=1)await t[e]()}export{c as ARCHIVE_EXTENSIONS,L as isBlockedIpAddress,A as isBlockedSourceHostname,m as isTrustedInstallSourceUrl,d as materializeInstallablePath,f as validateDownloadSourceUrl};
@@ -93,7 +93,7 @@ declare type SelectorTerm = {
93
93
 
94
94
  declare type SnapshotBackend = 'xctest' | 'android' | 'macos-helper' | 'linux-atspi';
95
95
 
96
- declare type SnapshotNode = RawSnapshotNode & {
96
+ export declare type SnapshotNode = RawSnapshotNode & {
97
97
  ref: string;
98
98
  };
99
99
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-device",
3
- "version": "0.11.16",
3
+ "version": "0.12.1",
4
4
  "description": "Unified control plane for physical and virtual devices via an agent-driven CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Callstack",
@@ -18,7 +18,7 @@ Use this skill as a router with mandatory defaults. Read this file first. For no
18
18
  - In React Native dev or debug builds, check early for visible warning or error overlays, tooltips, and toasts that can steal focus or intercept taps. If they are not part of the requested behavior, dismiss them and continue. If you saw them, report them in the final summary.
19
19
  - Do not browse the web or use external sources unless the user explicitly asks.
20
20
  - Re-snapshot after meaningful UI changes instead of reusing stale refs.
21
- - Treat refs in default snapshot output as actionable-now, not durable identities. If a target is off-screen, use `scrollintoview` or scroll and re-snapshot.
21
+ - Treat refs in default snapshot output as actionable-now, not durable identities. If a target appears only in an off-screen summary, use `scroll <direction>` and re-snapshot until the target is visible.
22
22
  - Prefer `@ref` or selector targeting over raw coordinates.
23
23
  - Ensure the correct target is pinned and an app session is open before interacting.
24
24
  - Keep the loop short: `open` -> inspect/act -> verify if needed -> `close`.
@@ -38,7 +38,7 @@ Open this file when the app or screen is already running and you need to discove
38
38
  - `press`
39
39
  - `fill`
40
40
  - `type`
41
- - `scrollintoview`
41
+ - `scroll`
42
42
  - `wait`
43
43
  - `keyboard dismiss` when the keyboard obscures the next target
44
44
 
@@ -115,10 +115,10 @@ App: com.apple.Preferences
115
115
  ## Refs vs selectors
116
116
 
117
117
  - Use refs for discovery, debugging, and short local loops.
118
- - Use `scrollintoview @ref` when the target is already known from the current snapshot and you want the command to re-snapshot after each swipe until the element reaches the viewport safe band.
119
- - If `scrollintoview @ref` succeeds, prefer the returned `currentRef` for the next action.
118
+ - When a target appears only in a visible-first off-screen summary, such as `[off-screen below] ... "Battery"`, use `scroll down` and then `snapshot -i`. For `[off-screen above]`, use `scroll up` and then `snapshot -i`.
119
+ - For more than two repeated scroll checks, create a short shell loop instead of issuing each command by hand. Stop when the label appears or the snapshot stops changing.
120
120
  - Visible-first off-screen summaries are intentionally compact. If you need the full off-screen tree instead of a short summary, retry with `snapshot --raw`.
121
- - Cap long searches with `--max-scrolls <n>` when the list may be unbounded or the target may not exist.
121
+ - Cap long searches in the loop when the list may be unbounded or the target may not exist.
122
122
  - Use selectors for deterministic scripts, assertions, and replay-friendly actions.
123
123
  - Prefer selector or `@ref` targeting over raw coordinates.
124
124
  - For tap interactions, `press` is canonical and `click` is an equivalent alias.
@@ -132,11 +132,25 @@ agent-device press 'id="camera_row" || label="Camera" role=button'
132
132
  agent-device is visible 'id="camera_settings_anchor"'
133
133
  ```
134
134
 
135
+ Example loop:
136
+
137
+ ```bash
138
+ previous=''
139
+ for _ in 1 2 3 4 5 6; do
140
+ current="$(agent-device snapshot -i)"
141
+ printf '%s\n' "$current"
142
+ printf '%s\n' "$current" | grep -q 'Battery' && break
143
+ [ "$current" = "$previous" ] && break
144
+ previous="$current"
145
+ agent-device scroll down 0.5 >/dev/null
146
+ done
147
+ ```
148
+
135
149
  ## Interaction fallbacks
136
150
 
137
151
  When `press @ref` fails:
138
152
 
139
- 1. If the error says the ref is off-screen, run `scrollintoview @ref` and reuse the returned `currentRef` or take one fresh snapshot.
153
+ 1. If the error says the ref is off-screen, use the off-screen summary direction to run `scroll <direction>`, then take a fresh `snapshot -i`.
140
154
  2. Re-snapshot if the UI may have changed.
141
155
  3. Retry `press @ref` or a selector-based `press`.
142
156
  4. If `screenshot --overlay-refs --json` returned a reliable `overlayRefs[].center`, use `agent-device press <x> <y>`.
@@ -85,3 +85,4 @@ Troubleshooting:
85
85
  - If `menubar` is missing the expected menu, retry with `open <app> --platform macos --surface menubar` for menu bar apps, or make the app frontmost first and retry the generic menubar surface.
86
86
  - If the wrong menu opened, retry secondary-clicking the row or cell wrapper rather than the nested text node.
87
87
  - If the app has multiple windows, make the correct window frontmost before relying on refs.
88
+ - If overriding the local helper, set `AGENT_DEVICE_MACOS_HELPER_BIN` to an absolute executable path; relative helper paths are rejected.