agent-device 0.11.15 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/src/152.js +1 -0
- package/dist/src/155.js +38 -0
- package/dist/src/267.js +1 -0
- package/dist/src/57.js +1 -0
- package/dist/src/818.js +1 -3
- package/dist/src/924.js +1 -1
- package/dist/src/974.js +2 -2
- package/dist/src/bin.js +36 -37
- package/dist/src/contracts.d.ts +59 -0
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon.js +15 -18
- package/dist/src/index.d.ts +15 -172
- package/dist/src/index.js +3 -2
- package/dist/src/metro.d.ts +6 -0
- package/dist/src/metro.js +1 -1
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +1 -1
- package/skills/agent-device/references/exploration.md +19 -5
- package/skills/agent-device/references/macos-desktop.md +1 -0
- package/dist/src/760.js +0 -33
- package/dist/src/957.js +0 -2
package/dist/src/index.d.ts
CHANGED
|
@@ -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>;
|
|
@@ -199,12 +198,14 @@ export declare type AppDeployResult = {
|
|
|
199
198
|
};
|
|
200
199
|
|
|
201
200
|
export declare class AppError extends Error {
|
|
202
|
-
code:
|
|
201
|
+
code: AppErrorCode;
|
|
203
202
|
details?: AppErrorDetails;
|
|
204
203
|
cause?: unknown;
|
|
205
|
-
constructor(code:
|
|
204
|
+
constructor(code: AppErrorCode, message: string, details?: AppErrorDetails, cause?: unknown);
|
|
206
205
|
}
|
|
207
206
|
|
|
207
|
+
declare type AppErrorCode = 'INVALID_ARGS' | 'DEVICE_NOT_FOUND' | 'TOOL_MISSING' | 'APP_NOT_INSTALLED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_OPERATION' | 'COMMAND_FAILED' | 'SESSION_NOT_FOUND' | 'UNAUTHORIZED' | 'UNKNOWN';
|
|
208
|
+
|
|
208
209
|
declare type AppErrorDetails = Record<string, unknown> & {
|
|
209
210
|
hint?: string;
|
|
210
211
|
diagnosticId?: string;
|
|
@@ -305,13 +306,6 @@ export declare type BatchStep = {
|
|
|
305
306
|
flags?: Record<string, unknown>;
|
|
306
307
|
};
|
|
307
308
|
|
|
308
|
-
declare type BatchStep_2 = {
|
|
309
|
-
command: string;
|
|
310
|
-
positionals?: string[];
|
|
311
|
-
flags?: Partial<CommandFlags>;
|
|
312
|
-
runtime?: unknown;
|
|
313
|
-
};
|
|
314
|
-
|
|
315
309
|
export declare type CaptureDiffOptions = ClientCommandBaseOptions & Pick<CaptureSnapshotOptions, 'interactiveOnly' | 'compact' | 'depth' | 'scope' | 'raw'> & {
|
|
316
310
|
kind: 'snapshot';
|
|
317
311
|
out?: string;
|
|
@@ -347,116 +341,14 @@ export declare type CaptureSnapshotResult = {
|
|
|
347
341
|
identifiers: AgentDeviceIdentifiers;
|
|
348
342
|
};
|
|
349
343
|
|
|
344
|
+
export declare function centerOfRect(rect: Rect): Point;
|
|
345
|
+
|
|
350
346
|
export declare type ClickOptions = ClientCommandBaseOptions & SelectorSnapshotCommandOptions & InteractionTarget & RepeatedPressOptions & {
|
|
351
347
|
button?: 'primary' | 'secondary' | 'middle';
|
|
352
348
|
};
|
|
353
349
|
|
|
354
350
|
declare type ClientCommandBaseOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions;
|
|
355
351
|
|
|
356
|
-
declare type CliFlags = {
|
|
357
|
-
json: boolean;
|
|
358
|
-
config?: string;
|
|
359
|
-
remoteConfig?: string;
|
|
360
|
-
stateDir?: string;
|
|
361
|
-
daemonBaseUrl?: string;
|
|
362
|
-
daemonAuthToken?: string;
|
|
363
|
-
daemonTransport?: 'auto' | 'socket' | 'http';
|
|
364
|
-
daemonServerMode?: 'socket' | 'http' | 'dual';
|
|
365
|
-
tenant?: string;
|
|
366
|
-
sessionIsolation?: 'none' | 'tenant';
|
|
367
|
-
runId?: string;
|
|
368
|
-
leaseId?: string;
|
|
369
|
-
sessionLock?: 'reject' | 'strip';
|
|
370
|
-
sessionLocked?: boolean;
|
|
371
|
-
sessionLockConflicts?: 'reject' | 'strip';
|
|
372
|
-
platform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
|
|
373
|
-
target?: 'mobile' | 'tv' | 'desktop';
|
|
374
|
-
device?: string;
|
|
375
|
-
udid?: string;
|
|
376
|
-
serial?: string;
|
|
377
|
-
iosSimulatorDeviceSet?: string;
|
|
378
|
-
androidDeviceAllowlist?: string;
|
|
379
|
-
out?: string;
|
|
380
|
-
session?: string;
|
|
381
|
-
runtime?: string;
|
|
382
|
-
metroHost?: string;
|
|
383
|
-
metroPort?: number;
|
|
384
|
-
metroProjectRoot?: string;
|
|
385
|
-
metroKind?: 'auto' | 'react-native' | 'expo';
|
|
386
|
-
metroPublicBaseUrl?: string;
|
|
387
|
-
metroProxyBaseUrl?: string;
|
|
388
|
-
metroBearerToken?: string;
|
|
389
|
-
metroPreparePort?: number;
|
|
390
|
-
metroListenHost?: string;
|
|
391
|
-
metroStatusHost?: string;
|
|
392
|
-
metroStartupTimeoutMs?: number;
|
|
393
|
-
metroProbeTimeoutMs?: number;
|
|
394
|
-
metroRuntimeFile?: string;
|
|
395
|
-
metroNoReuseExisting?: boolean;
|
|
396
|
-
metroNoInstallDeps?: boolean;
|
|
397
|
-
bundleUrl?: string;
|
|
398
|
-
launchUrl?: string;
|
|
399
|
-
boot?: boolean;
|
|
400
|
-
reuseExisting?: boolean;
|
|
401
|
-
verbose?: boolean;
|
|
402
|
-
snapshotInteractiveOnly?: boolean;
|
|
403
|
-
snapshotDiff?: boolean;
|
|
404
|
-
snapshotCompact?: boolean;
|
|
405
|
-
snapshotDepth?: number;
|
|
406
|
-
snapshotScope?: string;
|
|
407
|
-
snapshotRaw?: boolean;
|
|
408
|
-
networkInclude?: 'summary' | 'headers' | 'body' | 'all';
|
|
409
|
-
overlayRefs?: boolean;
|
|
410
|
-
screenshotFullscreen?: boolean;
|
|
411
|
-
baseline?: string;
|
|
412
|
-
threshold?: string;
|
|
413
|
-
appsFilter?: 'user-installed' | 'all';
|
|
414
|
-
count?: number;
|
|
415
|
-
fps?: number;
|
|
416
|
-
hideTouches?: boolean;
|
|
417
|
-
intervalMs?: number;
|
|
418
|
-
delayMs?: number;
|
|
419
|
-
holdMs?: number;
|
|
420
|
-
jitterPx?: number;
|
|
421
|
-
pixels?: number;
|
|
422
|
-
doubleTap?: boolean;
|
|
423
|
-
clickButton?: 'primary' | 'secondary' | 'middle';
|
|
424
|
-
backMode?: 'in-app' | 'system';
|
|
425
|
-
pauseMs?: number;
|
|
426
|
-
pattern?: 'one-way' | 'ping-pong';
|
|
427
|
-
maxScrolls?: number;
|
|
428
|
-
activity?: string;
|
|
429
|
-
header?: string[];
|
|
430
|
-
saveScript?: boolean | string;
|
|
431
|
-
shutdown?: boolean;
|
|
432
|
-
relaunch?: boolean;
|
|
433
|
-
surface?: 'app' | 'frontmost-app' | 'desktop' | 'menubar';
|
|
434
|
-
headless?: boolean;
|
|
435
|
-
restart?: boolean;
|
|
436
|
-
noRecord?: boolean;
|
|
437
|
-
retainPaths?: boolean;
|
|
438
|
-
retentionMs?: number;
|
|
439
|
-
replayUpdate?: boolean;
|
|
440
|
-
failFast?: boolean;
|
|
441
|
-
timeoutMs?: number;
|
|
442
|
-
retries?: number;
|
|
443
|
-
artifactsDir?: string;
|
|
444
|
-
reportJunit?: string;
|
|
445
|
-
steps?: string;
|
|
446
|
-
stepsFile?: string;
|
|
447
|
-
findFirst?: boolean;
|
|
448
|
-
findLast?: boolean;
|
|
449
|
-
batchOnError?: 'stop';
|
|
450
|
-
batchMaxSteps?: number;
|
|
451
|
-
batchSteps?: Array<{
|
|
452
|
-
command: string;
|
|
453
|
-
positionals?: string[];
|
|
454
|
-
flags?: Record<string, unknown>;
|
|
455
|
-
}>;
|
|
456
|
-
help: boolean;
|
|
457
|
-
version: boolean;
|
|
458
|
-
};
|
|
459
|
-
|
|
460
352
|
export declare type ClipboardCommandOptions = (DeviceCommandBaseOptions & {
|
|
461
353
|
action: 'read';
|
|
462
354
|
}) | (DeviceCommandBaseOptions & {
|
|
@@ -476,10 +368,6 @@ declare type CommandActionResult<T extends string> = DaemonResponseData & {
|
|
|
476
368
|
action?: T;
|
|
477
369
|
};
|
|
478
370
|
|
|
479
|
-
declare type CommandFlags = Omit<CliFlags, 'json' | 'help' | 'version' | 'batchSteps'> & {
|
|
480
|
-
batchSteps?: BatchStep_2[];
|
|
481
|
-
};
|
|
482
|
-
|
|
483
371
|
export declare type CommandRequestResult = DaemonResponseData;
|
|
484
372
|
|
|
485
373
|
export declare function createAgentDeviceClient(config?: AgentDeviceClientConfig, deps?: {
|
|
@@ -503,9 +391,7 @@ declare type DaemonError = {
|
|
|
503
391
|
details?: Record<string, unknown>;
|
|
504
392
|
};
|
|
505
393
|
|
|
506
|
-
declare type DaemonInstallSource =
|
|
507
|
-
|
|
508
|
-
declare type DaemonInstallSource_2 = {
|
|
394
|
+
declare type DaemonInstallSource = {
|
|
509
395
|
kind: 'url';
|
|
510
396
|
url: string;
|
|
511
397
|
headers?: Record<string, string>;
|
|
@@ -516,20 +402,13 @@ declare type DaemonInstallSource_2 = {
|
|
|
516
402
|
|
|
517
403
|
declare type DaemonLockPolicy = 'reject' | 'strip';
|
|
518
404
|
|
|
519
|
-
declare type DaemonRequest =
|
|
520
|
-
token: string;
|
|
521
|
-
session: string;
|
|
522
|
-
flags?: CommandFlags;
|
|
523
|
-
meta?: DaemonRequestMeta_2;
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
declare type DaemonRequest_2 = {
|
|
405
|
+
declare type DaemonRequest = {
|
|
527
406
|
token?: string;
|
|
528
407
|
session?: string;
|
|
529
408
|
command: string;
|
|
530
409
|
positionals: string[];
|
|
531
410
|
flags?: Record<string, unknown>;
|
|
532
|
-
runtime?:
|
|
411
|
+
runtime?: SessionRuntimeHints;
|
|
533
412
|
meta?: DaemonRequestMeta;
|
|
534
413
|
};
|
|
535
414
|
|
|
@@ -545,7 +424,7 @@ declare type DaemonRequestMeta = {
|
|
|
545
424
|
sessionIsolation?: 'none' | 'tenant';
|
|
546
425
|
uploadedArtifactId?: string;
|
|
547
426
|
clientArtifactPaths?: Record<string, string>;
|
|
548
|
-
installSource?:
|
|
427
|
+
installSource?: DaemonInstallSource;
|
|
549
428
|
retainMaterializedPaths?: boolean;
|
|
550
429
|
materializedPathRetentionMs?: number;
|
|
551
430
|
materializationId?: string;
|
|
@@ -553,25 +432,15 @@ declare type DaemonRequestMeta = {
|
|
|
553
432
|
lockPlatform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
|
|
554
433
|
};
|
|
555
434
|
|
|
556
|
-
declare type
|
|
557
|
-
installSource?: DaemonInstallSource;
|
|
558
|
-
lockPlatform?: PlatformSelector;
|
|
559
|
-
leaseBackend?: 'ios-simulator';
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
declare type DaemonResponse = DaemonResponse_2;
|
|
563
|
-
|
|
564
|
-
declare type DaemonResponse_2 = {
|
|
435
|
+
declare type DaemonResponse = {
|
|
565
436
|
ok: true;
|
|
566
|
-
data?:
|
|
437
|
+
data?: DaemonResponseData;
|
|
567
438
|
} | {
|
|
568
439
|
ok: false;
|
|
569
440
|
error: DaemonError;
|
|
570
441
|
};
|
|
571
442
|
|
|
572
|
-
declare type DaemonResponseData =
|
|
573
|
-
|
|
574
|
-
declare type DaemonResponseData_2 = Record<string, unknown> & {
|
|
443
|
+
declare type DaemonResponseData = Record<string, unknown> & {
|
|
575
444
|
artifacts?: DaemonArtifact[];
|
|
576
445
|
};
|
|
577
446
|
|
|
@@ -609,8 +478,6 @@ export declare type EnsureSimulatorResult = {
|
|
|
609
478
|
identifiers: AgentDeviceIdentifiers;
|
|
610
479
|
};
|
|
611
480
|
|
|
612
|
-
declare type ErrorCode = 'INVALID_ARGS' | 'DEVICE_NOT_FOUND' | 'TOOL_MISSING' | 'APP_NOT_INSTALLED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_OPERATION' | 'COMMAND_FAILED' | 'SESSION_NOT_FOUND' | 'UNAUTHORIZED' | 'UNKNOWN';
|
|
613
|
-
|
|
614
481
|
export declare type FillOptions = ClientCommandBaseOptions & SelectorSnapshotCommandOptions & InteractionTarget & {
|
|
615
482
|
text: string;
|
|
616
483
|
delayMs?: number;
|
|
@@ -706,15 +573,6 @@ export declare type MaterializationReleaseResult = {
|
|
|
706
573
|
identifiers: AgentDeviceIdentifiers;
|
|
707
574
|
};
|
|
708
575
|
|
|
709
|
-
declare type MaterializeInstallSource = {
|
|
710
|
-
kind: 'url';
|
|
711
|
-
url: string;
|
|
712
|
-
headers?: Record<string, string>;
|
|
713
|
-
} | {
|
|
714
|
-
kind: 'path';
|
|
715
|
-
path: string;
|
|
716
|
-
};
|
|
717
|
-
|
|
718
576
|
declare type MetroBridgeResult = {
|
|
719
577
|
enabled: boolean;
|
|
720
578
|
baseUrl: string;
|
|
@@ -761,7 +619,7 @@ export declare type MetroPrepareOptions = {
|
|
|
761
619
|
export declare type MetroPrepareResult = PrepareMetroRuntimeResult;
|
|
762
620
|
|
|
763
621
|
/** Re-export of {@link SessionRuntimeHints} under the Metro-specific alias used by public API consumers. */
|
|
764
|
-
declare type MetroRuntimeHints =
|
|
622
|
+
declare type MetroRuntimeHints = SessionRuntimeHints;
|
|
765
623
|
|
|
766
624
|
export declare type NetworkOptions = AgentDeviceRequestOverrides & {
|
|
767
625
|
action?: 'dump' | 'log';
|
|
@@ -900,19 +758,6 @@ export declare type ScreenshotOverlayRef = {
|
|
|
900
758
|
center: Point;
|
|
901
759
|
};
|
|
902
760
|
|
|
903
|
-
declare type ScrollIntoViewOptions_2 = ClientCommandBaseOptions & ({
|
|
904
|
-
text: string;
|
|
905
|
-
ref?: never;
|
|
906
|
-
label?: never;
|
|
907
|
-
} | {
|
|
908
|
-
ref: string;
|
|
909
|
-
label?: string;
|
|
910
|
-
text?: never;
|
|
911
|
-
}) & {
|
|
912
|
-
maxScrolls?: number;
|
|
913
|
-
};
|
|
914
|
-
export { ScrollIntoViewOptions_2 as ScrollIntoViewOptions }
|
|
915
|
-
|
|
916
761
|
declare type ScrollOptions_2 = ClientCommandBaseOptions & {
|
|
917
762
|
direction: 'up' | 'down' | 'left' | 'right';
|
|
918
763
|
amount?: number;
|
|
@@ -938,9 +783,7 @@ export declare type SessionCloseResult = {
|
|
|
938
783
|
|
|
939
784
|
declare type SessionIsolationMode = 'none' | 'tenant';
|
|
940
785
|
|
|
941
|
-
declare type SessionRuntimeHints =
|
|
942
|
-
|
|
943
|
-
declare type SessionRuntimeHints_2 = {
|
|
786
|
+
declare type SessionRuntimeHints = {
|
|
944
787
|
platform?: 'ios' | 'android';
|
|
945
788
|
metroHost?: string;
|
|
946
789
|
metroPort?: number;
|
package/dist/src/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import e from"node:net";import t from"node:http";import r from"node:https";import a from"node:fs";import n from"node:path";import{fileURLToPath as o}from"node:url";import{spawn as i}from"node:child_process";import s,{createHash as l}from"node:crypto";import{resolveUserPath as c,createRequestId as d,emitDiagnostic as u,withDiagnosticTimer as p,expandUserHomePath as m,AppError as f}from"./957.js";import{stopProcessForTakeover as h,prepareMetroRuntime as w,runCmdSync as y,isAgentDeviceDaemonProcess as v,runCmdDetached as I}from"./974.js";import{REMOTE_CONFIG_FIELD_SPECS as g,resolveRemoteConfigProfile as A,REMOTE_OPEN_PROFILE_KEYS as b}from"./924.js";function S(){let e=n.dirname(o(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(a.existsSync(e))return t;t=n.dirname(t)}return e}function D(e){let t,r=(t=(e??"").trim())?c(t):n.join(m("~"),".agent-device");return{baseDir:r,infoPath:n.join(r,"daemon.json"),lockPath:n.join(r,"daemon.lock"),logPath:n.join(r,"daemon.log"),sessionsDir:n.join(r,"sessions")}}let _="sha256";async function M(e){let{localPath:o,baseUrl:s,token:l}=e,c=a.statSync(o),d=c.isDirectory(),u=n.basename(o),p=d?"app-bundle":"file",m=s.endsWith("/")?s:`${s}/`,h=d?void 0:await E(o);if(h){let e=await k({normalizedBase:m,token:l,hash:h,filename:u,sizeBytes:c.size,artifactType:p});if(e)return e}let w=new URL("upload",m),y="https:"===w.protocol?r:t,v={"x-artifact-type":p,"x-artifact-filename":u,"transfer-encoding":"chunked"};return h&&(v["x-artifact-hash"]=h,v["x-artifact-hash-algorithm"]=_),l&&(v.authorization=`Bearer ${l}`,v["x-agent-device-token"]=l),new Promise((e,t)=>{let r=y.request({protocol:w.protocol,host:w.hostname,port:w.port,method:"POST",path:w.pathname+w.search,headers:v},r=>{let a="";r.setEncoding("utf8"),r.on("data",e=>{a+=e}),r.on("end",()=>{clearTimeout(s);try{let r=JSON.parse(a);if(!r.ok||!r.uploadId)return void t(new f("COMMAND_FAILED",`Upload failed: ${a}`));e(r.uploadId)}catch{t(new f("COMMAND_FAILED",`Invalid upload response: ${a}`))}})}),s=setTimeout(()=>{r.destroy(),t(new f("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(r.on("error",e=>{clearTimeout(s),t(new f("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),d){let e=i("tar",["cf","-","-C",n.dirname(o),n.basename(o)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(r),e.on("error",e=>{r.destroy(),t(new f("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(r.destroy(),t(new f("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=a.createReadStream(o);e.pipe(r),e.on("error",e=>{r.destroy(),t(new f("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}async function k(e){var t;let r=new URL("upload/preflight",e.normalizedBase),a={"content-type":"application/json"};e.token&&(a.authorization=`Bearer ${e.token}`,a["x-agent-device-token"]=e.token);let n=await fetch(r,{method:"POST",headers:a,signal:AbortSignal.timeout(3e4),body:JSON.stringify({hash:e.hash,hashAlgorithm:_,fileName:e.filename,sizeBytes:e.sizeBytes,artifactType:e.artifactType})}).catch(()=>void 0);if(!n?.ok)return;let o=await n.json().catch(()=>void 0);return(t=o)&&"object"==typeof t&&!0===t.ok&&!0===t.cacheHit&&"string"==typeof t.uploadId?o.uploadId:void 0}async function E(e){let t=l(_);return await new Promise((r,n)=>{a.createReadStream(e).on("data",e=>t.update(e)).on("error",e=>{n(new f("COMMAND_FAILED","Failed to read local artifact",{},e))}).on("end",r)}),t.digest("hex")}let P=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,N=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,T=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function x(e,t,r){t.lastIndex=0;let a=null;for(;null!==(a=t.exec(e));){let e=a[1]?.trim();e?.startsWith(".")&&r.add(e)}}function R(e){try{return a.statSync(e).isFile()?e:null}catch{return null}}let C=ef(),U=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}(),L=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}(),O=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],F=new e.BlockList;async function $(t){let r=t.meta?.requestId??d(),a=!!(t.meta?.debug||t.flags?.verbose),n=function(t){let r,a,n,o=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 f("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new f("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,c=s;if(!(!l||"localhost"===(r=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(e.isIPv4(r)?F.check(r,"ipv4"):!!e.isIPv6(r)&&F.check(r,"ipv6")))&&("string"!=typeof c||!(c.trim().length>0)))throw new f("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 d=t.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,u="auto"===(a=(d??"").trim().toLowerCase())?"auto":"socket"===a?"socket":"http"===a?"http":"auto";if(i&&"socket"===u)throw new f("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:i});let p="http"===(n=(t.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===d?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===n?"dual":"socket";return{paths:D(o),transportPreference:u,serverMode:p,remoteBaseUrl:i,remoteAuthToken:s}}(t),o=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return ef(t)}(t.command),i=await p("daemon_startup",async()=>await G(n),{requestId:r,session:t.session}),s=await j(t,i),l={...t,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...t.meta??{},requestId:r,debug:a,cwd:t.meta?.cwd,tenantId:t.meta?.tenantId??t.flags?.tenant,runId:t.meta?.runId??t.flags?.runId,leaseId:t.meta?.leaseId??t.flags?.leaseId,sessionIsolation:t.meta?.sessionIsolation??t.flags?.sessionIsolation,lockPolicy:t.meta?.lockPolicy,lockPlatform:t.meta?.lockPlatform,...s.uploadedArtifactId?{uploadedArtifactId:s.uploadedArtifactId}:{},...s.clientArtifactPaths?{clientArtifactPaths:s.clientArtifactPaths}:{},...s.installSource?{installSource:s.installSource}:{}}};return u({level:"info",phase:"daemon_request_prepare",data:{requestId:r,command:t.command,session:t.session}}),await p("daemon_request",async()=>await ea(i,l,n.transportPreference,o),{requestId:r,command:t.command})}async function j(e,t){let r,o=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(ed(t)){let a=function(e,t){if("screenshot"===e.command){let r=B(e,"path",".png");return t[0]?{field:"path",localPath:r,positionalIndex:0,positionalPath:V("screenshot",".png")}:{field:"path",localPath:r,positionalIndex:0,flagPath:V("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=B(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:V("recording",n.extname(t)||".mp4")}}return null}(e,o);a&&(void 0!==a.positionalPath&&(o[a.positionalIndex]=a.positionalPath),void 0!==a.flagPath&&((i??={}).out=a.flagPath),l[a.field]=a.localPath);let c=await q(e,t);c&&(s=c.installSource,r=c.uploadedArtifactId??r)}if(!ed(t)||"install"!==e.command&&"reinstall"!==e.command||o.length<2)return{positionals:o,flags:i,installSource:s,uploadedArtifactId:r,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let c=o[1];if(c.startsWith("remote:"))return o[1]=c.slice(7),{positionals:o,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let d=n.isAbsolute(c)?c:n.resolve(e.meta?.cwd??process.cwd(),c);return a.existsSync(d)?{positionals:o,flags:i,installSource:s,uploadedArtifactId:r=await M({localPath:d,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:o,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function q(e,t){let r=e.meta?.installSource;if("install_source"!==e.command||!r||"path"!==r.kind)return null;let o=r.path.trim();if(!o)return{installSource:r};if(o.startsWith("remote:"))return{installSource:{...r,path:o.slice(7)}};let i=n.isAbsolute(o)?o:n.resolve(e.meta?.cwd??process.cwd(),o);if(!a.existsSync(i))return{installSource:{...r,path:i}};let s=await M({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...r,path:i},uploadedArtifactId:s}}function B(e,t,r,a=0){let o=e.positionals?.[a]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${r}`,s=o&&o.trim().length>0?o:i;return n.isAbsolute(s)?s:n.resolve(e.meta?.cwd??process.cwd(),s)}function V(e,t){let r=t.startsWith(".")?t:`.${t}`;return n.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${r}`)}async function G(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await ee(t,"http"))return t;throw new f("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 r=W(e.paths.infoPath),o=function(){try{let e=S();return JSON.parse(a.readFileSync(n.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=S()){try{let r=n.resolve(t),o=[n.resolve(e)],i=new Set,l=[];for(;o.length>0;){let e=o.pop();if(!e||i.has(e))continue;i.add(e);let t=a.statSync(e);if(!t.isFile())continue;let s=n.relative(r,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let c=a.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return x(e,P,t),x(e,N,t),[...t]}(c)){let r=function(e,t){let r=n.resolve(n.dirname(e),t),a=R(r);if(a)return a;for(let e of T){let t=R(`${r}${e}`);if(t)return t}for(let e of T){let t=R(n.join(r,`index${e}`));if(t)return t}return null}(e,t);r&&o.push(r)}}let c=l.sort().join("|"),d=s.createHash("sha1").update(c).digest("hex");return`graph:${l.length}:${d}`}catch{return"unknown"}}((t=er()).useSrc?t.srcPath:t.distPath,t.root),l=!!r&&await ee(r,e.transportPreference);if(r&&r.version===o&&r.codeSignature===i&&l)return r;r&&(r.version!==o||r.codeSignature!==i||!l)&&(await J(r),Z(e.paths.infoPath)),function(e){let t=X(e);if(!t.hasLock||t.hasInfo)return;let r=Q(e.lockPath);if(!r)return Z(e.lockPath);v(r.pid,r.processStartTime)||Z(e.lockPath)}(e.paths);let c=0;for(let t=1;t<=L;t+=1){await et(e);let r=await z(U,e);if(r)return r;if(await K(e.paths)){c+=1;continue}let a=X(e.paths);if(!(t<L))break;if(!a.hasInfo&&!a.hasLock){await H(150);continue}}let d=X(e.paths);throw new f("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:U,startupAttempts:L,lockRecoveryCount:c,metadataState:d,hint:function(e,t=D(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.`}(d,e.paths)})}async function z(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=W(t.paths.infoPath);if(e&&await ee(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function H(e){await new Promise(t=>setTimeout(t,e))}async function K(e){let t=X(e);if(!t.hasLock||t.hasInfo)return!1;let r=Q(e.lockPath);return r&&v(r.pid,r.processStartTime)&&await h(r.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:r.processStartTime}),Z(e.lockPath),!0}async function J(e){await h(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function W(e){let t=Y(e);if(!t||"object"!=typeof t)return null;let r="string"==typeof t.token&&t.token.length>0?t.token:null;if(!r)return null;let a=Number.isInteger(t.port)&&Number(t.port)>0,n=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!a&&!n)return null;let o=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,c=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:r,port:a?Number(t.port):void 0,httpPort:n?Number(t.httpPort):void 0,transport:"socket"===o||"http"===o||"dual"===o?o:void 0,pid:c?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function Q(e){let t=Y(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}F.addSubnet("127.0.0.0",8,"ipv4"),F.addAddress("::1","ipv6"),F.addSubnet("::ffff:127.0.0.0",104,"ipv6");function X(e){return{hasInfo:a.existsSync(e.infoPath),hasLock:a.existsSync(e.lockPath)}}function Y(e){if(!a.existsSync(e))return null;try{return JSON.parse(a.readFileSync(e,"utf8"))}catch{return null}}function Z(e){try{a.existsSync(e)&&a.unlinkSync(e)}catch{}}async function ee(a,n){var o;return"http"===en(a,n)?await function(e){let a=e.baseUrl?eu(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!a)return Promise.resolve(!1);let n=new URL(a),o="https:"===n.protocol?r:t,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=o.request({protocol:n.protocol,host:n.hostname,port:n.port,path:n.pathname+n.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()})}(a):await ((o=a.port)?new Promise(t=>{let r=e.createConnection({host:"127.0.0.1",port:o},()=>{r.destroy(),t(!0)});r.on("error",()=>{t(!1)})}):Promise.resolve(!1))}async function et(e){let t=er(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],a={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};I(process.execPath,r,{env:a})}function er(){let e=S(),t=n.join(e,"dist","src","daemon.js"),r=n.join(e,"src","daemon.ts"),o=a.existsSync(t),i=a.existsSync(r);if(!o&&!i)throw new f("COMMAND_FAILED","Daemon entry not found",{distPath:t,srcPath:r});return{root:e,distPath:t,srcPath:r,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!o&&i}}async function ea(e,t,r,a){return"http"===en(e,r)?await ec(e,t,a):await el(e,t,a)}function en(e,t){if(e.baseUrl){if("socket"===t)throw new f("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t||"socket"===t){var r=e,a=t;if(eo(r,a))return a;throw new f("COMMAND_FAILED","http"===a?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let n=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>eo(e,t));if(n)return n;throw new f("COMMAND_FAILED","Daemon metadata has no reachable transport")}function eo(e,t){return"http"===t?!!e.httpPort:!!e.port}function ei(e,t,r,a,n,o){let i=n?{terminated:0}:function(){let e=0;try{for(let t of O){let r=y("pkill",["-f",t],{allowFailure:!0});0===r.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}(),s=n?{forcedKill:!1}:function(e,t){let r=!1;try{v(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),r=!0)}catch{h(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{Z(t.infoPath),Z(t.lockPath)}return{forcedKill:r}}(e,t);return u({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:o,requestId:r,command:a,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:n?void 0:e.pid,daemonPidForceKilled:n?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new f("COMMAND_FAILED","Daemon request timed out",{timeoutMs:o,requestId:r,hint:n?"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 es(e,t,r){return u({level:"error",phase:"daemon_request_socket_error",data:{requestId:t,message:e instanceof Error?e.message:String(e)}}),new f("COMMAND_FAILED","Failed to communicate with daemon",{requestId:t,hint:r?"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 el(t,r,a){let n=t.port;if(!n)throw new f("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((o,i)=>{let s=e.createConnection({host:"127.0.0.1",port:n},()=>{s.write(`${JSON.stringify(r)}
|
|
2
|
-
`)}),l=D(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),c="number"==typeof a?setTimeout(()=>{s.destroy(),i(ei(t,l,r.meta?.requestId,r.command,!1,a))},a):void 0,d="";s.setEncoding("utf8"),s.on("data",e=>{let t=(d+=e).indexOf("\n");if(-1===t)return;let a=d.slice(0,t).trim();if(a)try{let e=JSON.parse(a);s.end(),c&&clearTimeout(c),o(e)}catch(e){c&&clearTimeout(c),i(new f("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:a},e instanceof Error?e:void 0))}}),s.on("error",e=>{c&&clearTimeout(c),i(es(e,r.meta?.requestId,!1))})})}async function ec(e,a,n){let o=e.baseUrl?new URL(eu(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!o)throw new f("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:a.meta?.requestId??d(),method:"agent_device.command",params:a}),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,c)=>{let d=D(a.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),u=("https:"===o.protocol?r:t).request({protocol:o.protocol,host:o.hostname,port:o.port,method:"POST",path:o.pathname+o.search,headers:s},t=>{let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{m&&clearTimeout(m);try{let t=JSON.parse(r);if(t.error){let e=t.error.data??{};c(new f(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:a.meta?.requestId}));return}if(!t.result||"object"!=typeof t.result)return void c(new f("COMMAND_FAILED","Invalid daemon RPC response",{requestId:a.meta?.requestId}));if(e.baseUrl&&t.result.ok)return void ep(e,a,t.result).then(l).catch(c);l(t.result)}catch(e){m&&clearTimeout(m),c(new f("COMMAND_FAILED","Invalid daemon response",{requestId:a.meta?.requestId,line:r},e instanceof Error?e:void 0))}})}),p=ed(e),m="number"==typeof n?setTimeout(()=>{u.destroy(),c(ei(e,d,a.meta?.requestId,a.command,p,n))},n):void 0;u.on("error",e=>{m&&clearTimeout(m),c(es(e,a.meta?.requestId,p))}),u.write(i),u.end()})}function ed(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function eu(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function ep(e,t,r){let a=Array.isArray(r.data?.artifacts)?r.data.artifacts:[];if(0===a.length||!e.baseUrl)return r;let o=r.data?{...r.data}:{},i=[];for(let r of a){if(!r||"object"!=typeof r||"string"!=typeof r.artifactId){i.push(r);continue}let a=function(e,t){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let r=e.fileName?.trim()||`${e.field}-${Date.now()}`;return n.resolve(t.meta?.cwd??process.cwd(),r)}(r,t);await em({baseUrl:e.baseUrl,token:e.token,artifactId:r.artifactId,destinationPath:a,requestId:t.meta?.requestId}),o[r.field]=a,i.push({...r,localPath:a})}return o.artifacts=i,{ok:!0,data:o}}async function em(e){var o,i;let s,l=new URL((o=e.baseUrl,i=e.artifactId,s=o.endsWith("/")?o:`${o}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),c="https:"===l.protocol?r:t;await a.promises.mkdir(n.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let n=!1,o=e.timeoutMs??C,i=o=>{if(!n){if(n=!0,clearTimeout(d),o)return void a.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(o));t()}},s=c.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 r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{i(new f("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=a.createWriteStream(e.destinationPath);r.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("aborted",()=>{i(new f("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),d=setTimeout(()=>{s.destroy(new f("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:o}))},o);s.on("error",t=>{t instanceof f?i(t):i(new f("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:o},t instanceof Error?t:void 0))}),s.end()})}function ef(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 eh="clipboard",ew="wait",ey=new Set(["id","role","text","label","value","appname","windowtitle"]),ev=new Set(["visible","hidden","editable","selected","enabled","hittable"]),eI=new Set([...ey,...ev]);function eg(e){let t=e.trim();if(!t)throw new f("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!ev.has(r))throw new f("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let a=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!eI.has(a))throw new f("INVALID_ARGS",`Unknown selector key: ${a}`);if(!n)throw new f("INVALID_ARGS",`Missing selector value for key: ${a}`);if(ev.has(a)){let e,t="true"===(e=eb(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new f("INVALID_ARGS",`Invalid boolean value for ${a}: ${n}`);return{key:a,value:t}}return{key:a,value:eb(n)}}function eA(e,t){return e?e===t?null:e:t}function eb(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function eS(e,t){let r=0;for(let a=t-1;a>=0&&"\\"===e[a];a-=1)r+=1;return r%2==1}let eD=g.map(e=>e.key);function e_(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function eM(e,t,r){return{deviceId:t,deviceName:r,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function ek(e,t,r,a){let n=r(e[t]);if(void 0===n)throw new f("COMMAND_FAILED",a,{response:e});return n}[...b];function eE(e,t){return ek(e,t,eC,`Daemon response is missing "${t}".`)}function eP(e,t){return eC(e[t])}function eN(e,t){var r;let a;return r=eC,null===(a=e[t])?null:r(a)}function eT(e,t){return ek(e,t,eL,`Daemon response has invalid "${t}".`)}function ex(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function eR(e,t){let r=e[t];if(!e$(r))return;let a="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0,o="number"==typeof r.width?r.width:void 0,i="number"==typeof r.height?r.height:void 0;if(void 0!==a&&void 0!==n&&void 0!==o&&void 0!==i)return{x:a,y:n,width:o,height:i}}function eC(e){return"string"==typeof e&&e.length>0?e:void 0}function eU(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function eL(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function eO(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function eF(e){if(!e$(e))throw new f("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function e$(e){return"object"==typeof e&&null!==e}function ej(e){let t={};for(let[r,a]of Object.entries(e))void 0!==a&&(t[r]=a);return t}function eq(e,t){let r=eP(e,"bundleId"),a=eP(e,"package");return{app:eE(e,"app"),appPath:eE(e,"appPath"),platform:eT(e,"platform"),appId:r??a,bundleId:r,package:a,identifiers:e_({session:t,bundleId:r,packageName:a})}}function eB(e){let t=eF(e),r=eT(t,"platform"),a=eE(t,"id"),n=eE(t,"name");return{platform:r,target:ex(t,"target"),kind:ek(t,"kind",eO,'Daemon response has invalid "kind".'),id:a,name:n,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:eM(r,a,n),ios:"ios"===r?{udid:a}:void 0,android:"android"===r?{serial:a}:void 0}}function eV(e){let t=eF(e),r=eT(t,"platform"),a=eE(t,"id"),n=eE(t,"name"),o=ex(t,"target"),i=eE(t,"device"),s={session:n,...eM(r,a,i)};return{name:n,createdAt:ek(t,"createdAt",eU,'Daemon response is missing numeric "createdAt".'),device:{platform:r,target:o,id:a,name:i,identifiers:s,ios:"ios"===r?{udid:a,simulatorSetPath:eN(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:a}:void 0},identifiers:s}}function eG(e){return e??"default"}function ez(e={},t={}){var r;let a,n=t.transport??$,o=eQ(e),i=async(t,r=[],a={})=>{let i=eW(e,o,a),s=await n({session:eG(i.session),command:t,positionals:r,flags:ej({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:ej({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 f(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(eV)},l=async(e,t=[],r={})=>await i(e,t,r),c=(t={})=>eG(eW(e,o,t).session);return{command:(r=async e=>await i(e.command,e.positionals,e.options),a=async e=>await r(e),{wait:async e=>await a(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 f("INVALID_ARGS","wait command requires exactly one of durationMs, text, ref, or selector.");if(void 0!==e.durationMs)return{command:ew,positionals:[String(e.durationMs)],options:e};let t=void 0!==e.timeoutMs?[String(e.timeoutMs)]:[];if(void 0!==e.text)return{command:ew,positionals:["text",e.text,...t],options:e};if(void 0!==e.ref)return{command:ew,positionals:[e.ref,...t],options:e};let r=e.selector;return function(e){if(!function(e){try{let t=e.trim();if(!t)throw new f("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",a=null;for(let n=0;n<e.length;n+=1){let o=e[n];if(('"'===o||"'"===o)&&!eS(e,n)){a=eA(a,o),r+=o;continue}if(!a&&"|"===o&&"|"===e[n+1]){let a=r.trim();if(!a)throw new f("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(a),r="",n+=1;continue}r+=o}let n=r.trim();if(!n)throw new f("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new f("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new f("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",a=null;for(let n=0;n<e.length;n+=1){let o=e[n];if(('"'===o||"'"===o)&&!eS(e,n)){a=eA(a,o),r+=o;continue}if(!a&&/\s/.test(o)){r.trim()&&t.push(r.trim()),r="";continue}r+=o}if(a)throw new f("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim()&&t.push(r.trim()),t}(t);if(0===r.length)throw new f("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(eg)}})(e))}}catch{return null}}(e))throw new f("INVALID_ARGS",`Invalid wait selector: ${e}`)}(r),{command:ew,positionals:[r,...t],options:e}}(e)),alert:async(e={})=>{var t;return await a({command:"alert",positionals:[(t=e).action??"get",...void 0!==t.timeoutMs?[String(t.timeoutMs)]:[]],options:t})},appState:async(e={})=>await a({command:"appstate",positionals:[],options:e}),back:async(e={})=>await a({command:"back",positionals:[],options:{...e,backMode:e.mode}}),home:async(e={})=>await a({command:"home",positionals:[],options:e}),rotate:async e=>await a({command:"rotate",positionals:[e.orientation],options:e}),appSwitcher:async(e={})=>await a({command:"app-switcher",positionals:[],options:e}),keyboard:async(e={})=>await a({command:"keyboard",positionals:e.action?[e.action]:[],options:e}),clipboard:async e=>{var t;return await a("read"===(t=e).action?{command:eh,positionals:["read"],options:t}:{command:eh,positionals:["write",t.text],options:t})}}),devices:{list:async(e={})=>{let t=await i("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(eB)},boot:async(e={})=>await l("boot",[],e)},sessions:{list:async(e={})=>await s(e),close:async(e={})=>{let t=c(e),r=(await i("close",[],e)).shutdown;return{session:t,shutdown:"object"==typeof r&&null!==r?r:void 0,identifiers:{session:t}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,a=await i("ensure-simulator",[],{...r,simulatorRuntimeId:t}),n=eE(a,"udid"),o=eE(a,"device");return{udid:n,device:o,runtime:eE(a,"runtime"),created:!0===a.created,booted:!0===a.booted,iosSimulatorDeviceSet:eN(a,"ios_simulator_device_set"),identifiers:{deviceId:n,deviceName:o,udid:n}}}},apps:{install:async e=>eq(await i("install",[e.app,e.appPath],e),c(e)),reinstall:async e=>eq(await i("reinstall",[e.app,e.appPath],e),c(e)),installFromSource:async e=>(function(e,t){let r=eP(e,"bundleId"),a=eP(e,"packageName"),n=r??a??eP(e,"appId"),o=eP(e,"launchTarget")??a??r??n;if(!o)throw new f("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:eP(e,"appName"),appId:n,bundleId:r,packageName:a,launchTarget:o,installablePath:eP(e,"installablePath"),archivePath:eP(e,"archivePath"),materializationId:eP(e,"materializationId"),materializationExpiresAt:eP(e,"materializationExpiresAt"),identifiers:e_({session:t,bundleId:r,packageName:a,appId:n})}})(await i("install_source",[],{...e,installSource:e.source,retainMaterializedPaths:e.retainPaths,materializedPathRetentionMs:e.retentionMs}),c(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=c(e),r=e.app?e.url?[e.app,e.url]:[e.app]:[],a=await i("open",r,e),n=function(e){let t=e.platform,r=eP(e,"id"),a=eP(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!r||!a)return;let n=ex(e,"target"),o=eM(t,r,a);return{platform:t,target:n,id:r,name:a,identifiers:o,ios:"ios"===t?{udid:eP(e,"device_udid")??r,simulatorSetPath:eN(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:eP(e,"serial")??r}:void 0}}(a),o=eP(a,"appBundleId");return{session:t,appName:eP(a,"appName"),appBundleId:o,appId:o,startup:function(e){if(e$(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")}}(a.startup),runtime:function(e){if(!e$(e))return;let t=e.platform,r=eP(e,"metroHost"),a="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:a,bundleUrl:eP(e,"bundleUrl"),launchUrl:eP(e,"launchUrl")}}(a.runtime),device:n,identifiers:{session:t,deviceId:n?.id,deviceName:n?.name,udid:n?.ios?.udid,serial:n?.android?.serial,appId:o,appBundleId:o}}},close:async(e={})=>{let t=c(e),r=(await i("close",e.app?[e.app]:[],e)).shutdown;return{session:t,closedApp:e.app,shutdown:"object"==typeof r&&null!==r?r: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:eE(t,"materializationId"),identifiers:{}}}},metro:{prepare:async t=>await w({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 r=c(e),a=await i("snapshot",[],e),n=eP(a,"appBundleId"),o="object"==typeof a.visibility&&null!==a.visibility?a.visibility:void 0;return{nodes:Array.isArray(t=a.nodes)?t:[],truncated:!0===a.truncated,appName:eP(a,"appName"),appBundleId:n,...o?{visibility:o}:{},warnings:Array.isArray(a.warnings)?a.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:r,appId:n,appBundleId:n}}},screenshot:async(e={})=>{let t=c(e),r=await i("screenshot",e.path?[e.path]:[],{...e,screenshotFullscreen:e.fullscreen});return{path:eE(r,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let r=[];for(let e of t){if(!e$(e))continue;let t=eP(e,"ref"),a=eR(e,"rect"),n=eR(e,"overlayRect"),o=function(e,t){let r=e[t];if(!e$(r))return;let a="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0;if(void 0!==a&&void 0!==n)return{x:a,y:n}}(e,"center");t&&a&&n&&o&&r.push({ref:t,label:eP(e,"label"),rect:a,overlayRect:n,center:o})}return r}(r),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",eH(e),{...e,clickButton:e.button}),press:async e=>await l("press",eH(e),e),longPress:async e=>await l("longpress",[String(e.x),String(e.y),...eJ(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),...eJ(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",[...eH(e),e.text],e),scroll:async e=>await l("scroll",[e.direction,...eJ(e.amount)],e),scrollIntoView:async e=>{var t;return await l("scrollintoview",void 0!==(t=e).ref?[t.ref,...eK(t.label)]:[t.text??""],e)},pinch:async e=>await l("pinch",[String(e.scale),...eJ(e.x),...eJ(e.y)],e),get:async e=>{var t;return await l("get",[e.format,...void 0!==(t=e).ref?[t.ref,...eK(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",...eJ(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",...eK(t.message)],e)},network:async(e={})=>{var t;return await l("network",[...(t=e).action?[t.action]:[],...eJ(t.limit)],{...e,networkInclude:e.include})}},recording:{record:async e=>await l("record",[e.action,...eK(e.path)],e),trace:async e=>await l("trace",[e.action,...eK(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 eH(e){return void 0!==e.ref?[e.ref,...eK(e.label)]:void 0!==e.selector?[e.selector]:[String(e.x),String(e.y)]}function eK(e){return void 0===e?[]:[e]}function eJ(e){return void 0===e?[]:[String(e)]}function eW(e,t,r){return r.remoteConfig&&r.remoteConfig!==e.remoteConfig?{...eQ({...e,...r}),...e,...r}:{...t,...e,...r}}function eQ(e){var t;if(!e.remoteConfig)return{};let{runtime:r,...a}=(t={remoteConfig:e.remoteConfig,cwd:e.cwd??process.cwd(),env:process.env}).remoteConfig?{...function(e){let t={};for(let r of eD){let a=e[r];void 0!==a&&(t[r]=a)}return t}(A({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}).profile),remoteConfig:t.remoteConfig}:{};return a}export{AppError}from"./957.js";export{ez as createAgentDeviceClient};
|
|
1
|
+
import e from"node:net";import t from"node:http";import r from"node:https";import a from"node:fs";import n from"node:path";import{fileURLToPath as o}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 c}from"node:child_process";import{redactDiagnosticData as d,AppError as u}from"./152.js";import{resolveUserPath as p,expandUserHomePath as m}from"./267.js";import{stopProcessForTakeover as f,prepareMetroRuntime as h,runCmdSync as w,isAgentDeviceDaemonProcess as y,runCmdDetached as v}from"./974.js";import{REMOTE_CONFIG_FIELD_SPECS as g,resolveRemoteConfigProfile as I,REMOTE_OPEN_PROFILE_KEYS as A}from"./924.js";function b(){let e=n.dirname(o(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(a.existsSync(e))return t;t=n.dirname(t)}return e}let S=new i;function _(){return s.randomBytes(8).toString("hex")}function D(e){let t=S.getStore();if(!t)return;let r={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?d(e.data):void 0};if(t.events.push(r),!t.debug)return;let n=`[agent-device][diag] ${JSON.stringify(r)}
|
|
2
|
+
`;try{t.logPath&&a.appendFile(t.logPath,n,()=>{}),t.traceLogPath&&a.appendFile(t.traceLogPath,n,()=>{}),t.logPath||t.traceLogPath||process.stderr.write(n)}catch{}}async function M(e,t,r){let a=Date.now();try{let n=await t();return D({level:"info",phase:e,durationMs:Date.now()-a,data:r}),n}catch(t){throw D({level:"error",phase:e,durationMs:Date.now()-a,data:{...r??{},error:t instanceof Error?t.message:String(t)}}),t}}function P(e){let t,r=(t=(e??"").trim())?p(t):n.join(m("~"),".agent-device");return{baseDir:r,infoPath:n.join(r,"daemon.json"),lockPath:n.join(r,"daemon.lock"),logPath:n.join(r,"daemon.log"),sessionsDir:n.join(r,"sessions")}}let E="sha256";async function k(e){let{localPath:o,baseUrl:i,token:s}=e,l=a.statSync(o),d=l.isDirectory(),p=n.basename(o),m=d?"app-bundle":"file",f=i.endsWith("/")?i:`${i}/`,h=d?void 0:await T(o);if(h){let e=await N({normalizedBase:f,token:s,hash:h,filename:p,sizeBytes:l.size,artifactType:m});if(e)return e}let w=new URL("upload",f),y="https:"===w.protocol?r: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"]=E),s&&(v.authorization=`Bearer ${s}`,v["x-agent-device-token"]=s),new Promise((e,t)=>{let r=y.request({protocol:w.protocol,host:w.hostname,port:w.port,method:"POST",path:w.pathname+w.search,headers:v},r=>{let a="";r.setEncoding("utf8"),r.on("data",e=>{a+=e}),r.on("end",()=>{clearTimeout(i);try{let r=JSON.parse(a);if(!r.ok||!r.uploadId)return void t(new u("COMMAND_FAILED",`Upload failed: ${a}`));e(r.uploadId)}catch{t(new u("COMMAND_FAILED",`Invalid upload response: ${a}`))}})}),i=setTimeout(()=>{r.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(r.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))}),d){let e=c("tar",["cf","-","-C",n.dirname(o),n.basename(o)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(r),e.on("error",e=>{r.destroy(),t(new u("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(r.destroy(),t(new u("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=a.createReadStream(o);e.pipe(r),e.on("error",e=>{r.destroy(),t(new u("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}async function N(e){var t;let r=new URL("upload/preflight",e.normalizedBase),a={"content-type":"application/json"};e.token&&(a.authorization=`Bearer ${e.token}`,a["x-agent-device-token"]=e.token);let n=await fetch(r,{method:"POST",headers:a,signal:AbortSignal.timeout(3e4),body:JSON.stringify({hash:e.hash,hashAlgorithm:E,fileName:e.filename,sizeBytes:e.sizeBytes,artifactType:e.artifactType})}).catch(()=>void 0);if(!n?.ok)return;let o=await n.json().catch(()=>void 0);return(t=o)&&"object"==typeof t&&!0===t.ok&&!0===t.cacheHit&&"string"==typeof t.uploadId?o.uploadId:void 0}async function T(e){let t=l(E);return await new Promise((r,n)=>{a.createReadStream(e).on("data",e=>t.update(e)).on("error",e=>{n(new u("COMMAND_FAILED","Failed to read local artifact",{},e))}).on("end",r)}),t.digest("hex")}let x=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,R=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,C=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function L(e,t,r){t.lastIndex=0;let a=null;for(;null!==(a=t.exec(e));){let e=a[1]?.trim();e?.startsWith(".")&&r.add(e)}}function U(e){try{return a.statSync(e).isFile()?e:null}catch{return null}}let O=ey(),F=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}(),$=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}(),j=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],q=new e.BlockList;async function B(t){let r=t.meta?.requestId??_(),a=!!(t.meta?.debug||t.flags?.verbose),n=function(t){let r,a,n,o=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,c=s;if(!(!l||"localhost"===(r=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(e.isIPv4(r)?q.check(r,"ipv4"):!!e.isIPv6(r)&&q.check(r,"ipv6")))&&("string"!=typeof c||!(c.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 d=t.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,p="auto"===(a=(d??"").trim().toLowerCase())?"auto":"socket"===a?"socket":"http"===a?"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"===(n=(t.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===d?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===n?"dual":"socket";return{paths:P(o),transportPreference:p,serverMode:m,remoteBaseUrl:i,remoteAuthToken:s}}(t),o=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return ey(t)}(t.command),i=await M("daemon_startup",async()=>await H(n),{requestId:r,session:t.session}),s=await G(t,i),l={...t,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...t.meta??{},requestId:r,debug:a,cwd:t.meta?.cwd,tenantId:t.meta?.tenantId??t.flags?.tenant,runId:t.meta?.runId??t.flags?.runId,leaseId:t.meta?.leaseId??t.flags?.leaseId,sessionIsolation:t.meta?.sessionIsolation??t.flags?.sessionIsolation,lockPolicy:t.meta?.lockPolicy,lockPlatform:t.meta?.lockPlatform,...s.uploadedArtifactId?{uploadedArtifactId:s.uploadedArtifactId}:{},...s.clientArtifactPaths?{clientArtifactPaths:s.clientArtifactPaths}:{},...s.installSource?{installSource:s.installSource}:{}}};return D({level:"info",phase:"daemon_request_prepare",data:{requestId:r,command:t.command,session:t.session}}),await M("daemon_request",async()=>await ei(i,l,n.transportPreference,o),{requestId:r,command:t.command})}async function G(e,t){let r,o=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(em(t)){let a=function(e,t){if("screenshot"===e.command){let r=z(e,"path",".png");return t[0]?{field:"path",localPath:r,positionalIndex:0,positionalPath:K("screenshot",".png")}:{field:"path",localPath:r,positionalIndex:0,flagPath:K("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=z(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:K("recording",n.extname(t)||".mp4")}}return null}(e,o);a&&(void 0!==a.positionalPath&&(o[a.positionalIndex]=a.positionalPath),void 0!==a.flagPath&&((i??={}).out=a.flagPath),l[a.field]=a.localPath);let c=await V(e,t);c&&(s=c.installSource,r=c.uploadedArtifactId??r)}if(!em(t)||"install"!==e.command&&"reinstall"!==e.command||o.length<2)return{positionals:o,flags:i,installSource:s,uploadedArtifactId:r,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let c=o[1];if(c.startsWith("remote:"))return o[1]=c.slice(7),{positionals:o,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let d=n.isAbsolute(c)?c:n.resolve(e.meta?.cwd??process.cwd(),c);return a.existsSync(d)?{positionals:o,flags:i,installSource:s,uploadedArtifactId:r=await k({localPath:d,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:o,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function V(e,t){let r=e.meta?.installSource;if("install_source"!==e.command||!r||"path"!==r.kind)return null;let o=r.path.trim();if(!o)return{installSource:r};if(o.startsWith("remote:"))return{installSource:{...r,path:o.slice(7)}};let i=n.isAbsolute(o)?o:n.resolve(e.meta?.cwd??process.cwd(),o);if(!a.existsSync(i))return{installSource:{...r,path:i}};let s=await k({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...r,path:i},uploadedArtifactId:s}}function z(e,t,r,a=0){let o=e.positionals?.[a]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${r}`,s=o&&o.trim().length>0?o:i;return n.isAbsolute(s)?s:n.resolve(e.meta?.cwd??process.cwd(),s)}function K(e,t){let r=t.startsWith(".")?t:`.${t}`;return n.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${r}`)}async function H(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await ea(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 r=Y(e.paths.infoPath),o=function(){try{let e=b();return JSON.parse(a.readFileSync(n.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=b()){try{let r=n.resolve(t),o=[n.resolve(e)],i=new Set,l=[];for(;o.length>0;){let e=o.pop();if(!e||i.has(e))continue;i.add(e);let t=a.statSync(e);if(!t.isFile())continue;let s=n.relative(r,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let c=a.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return L(e,x,t),L(e,R,t),[...t]}(c)){let r=function(e,t){let r=n.resolve(n.dirname(e),t),a=U(r);if(a)return a;for(let e of C){let t=U(`${r}${e}`);if(t)return t}for(let e of C){let t=U(n.join(r,`index${e}`));if(t)return t}return null}(e,t);r&&o.push(r)}}let c=l.sort().join("|"),d=s.createHash("sha1").update(c).digest("hex");return`graph:${l.length}:${d}`}catch{return"unknown"}}((t=eo()).useSrc?t.srcPath:t.distPath,t.root),l=!!r&&await ea(r,e.transportPreference);if(r&&r.version===o&&r.codeSignature===i&&l)return r;r&&(r.version!==o||r.codeSignature!==i||!l)&&(await X(r),er(e.paths.infoPath)),function(e){let t=ee(e);if(!t.hasLock||t.hasInfo)return;let r=Z(e.lockPath);if(!r)return er(e.lockPath);y(r.pid,r.processStartTime)||er(e.lockPath)}(e.paths);let c=0;for(let t=1;t<=$;t+=1){await en(e);let r=await J(F,e);if(r)return r;if(await Q(e.paths)){c+=1;continue}let a=ee(e.paths);if(!(t<$))break;if(!a.hasInfo&&!a.hasLock){await W(150);continue}}let d=ee(e.paths);throw new u("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:F,startupAttempts:$,lockRecoveryCount:c,metadataState:d,hint:function(e,t=P(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.`}(d,e.paths)})}async function J(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=Y(t.paths.infoPath);if(e&&await ea(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function W(e){await new Promise(t=>setTimeout(t,e))}async function Q(e){let t=ee(e);if(!t.hasLock||t.hasInfo)return!1;let r=Z(e.lockPath);return r&&y(r.pid,r.processStartTime)&&await f(r.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:r.processStartTime}),er(e.lockPath),!0}async function X(e){await f(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function Y(e){let t=et(e);if(!t||"object"!=typeof t)return null;let r="string"==typeof t.token&&t.token.length>0?t.token:null;if(!r)return null;let a=Number.isInteger(t.port)&&Number(t.port)>0,n=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!a&&!n)return null;let o=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,c=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:r,port:a?Number(t.port):void 0,httpPort:n?Number(t.httpPort):void 0,transport:"socket"===o||"http"===o||"dual"===o?o:void 0,pid:c?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function Z(e){let t=et(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}q.addSubnet("127.0.0.0",8,"ipv4"),q.addAddress("::1","ipv6"),q.addSubnet("::ffff:127.0.0.0",104,"ipv6");function ee(e){return{hasInfo:a.existsSync(e.infoPath),hasLock:a.existsSync(e.lockPath)}}function et(e){if(!a.existsSync(e))return null;try{return JSON.parse(a.readFileSync(e,"utf8"))}catch{return null}}function er(e){try{a.existsSync(e)&&a.unlinkSync(e)}catch{}}async function ea(a,n){var o;return"http"===es(a,n)?await function(e){let a=e.baseUrl?ef(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!a)return Promise.resolve(!1);let n=new URL(a),o="https:"===n.protocol?r:t,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=o.request({protocol:n.protocol,host:n.hostname,port:n.port,path:n.pathname+n.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()})}(a):await ((o=a.port)?new Promise(t=>{let r=e.createConnection({host:"127.0.0.1",port:o},()=>{r.destroy(),t(!0)});r.on("error",()=>{t(!1)})}):Promise.resolve(!1))}async function en(e){let t=eo(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],a={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};v(process.execPath,r,{env:a})}function eo(){let e=b(),t=n.join(e,"dist","src","daemon.js"),r=n.join(e,"src","daemon.ts"),o=a.existsSync(t),i=a.existsSync(r);if(!o&&!i)throw new u("COMMAND_FAILED","Daemon entry not found",{distPath:t,srcPath:r});return{root:e,distPath:t,srcPath:r,useSrc:process.execArgv.includes("--experimental-strip-types")?i:!o&&i}}async function ei(e,t,r,a){return"http"===es(e,r)?await ep(e,t,a):await eu(e,t,a)}function es(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 r=e,a=t;if(el(r,a))return a;throw new u("COMMAND_FAILED","http"===a?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let n=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>el(e,t));if(n)return n;throw new u("COMMAND_FAILED","Daemon metadata has no reachable transport")}function el(e,t){return"http"===t?!!e.httpPort:!!e.port}function ec(e,t,r,a,n,o){let i=n?{terminated:0}:function(){let e=0;try{for(let t of j){let r=w("pkill",["-f",t],{allowFailure:!0});0===r.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}(),s=n?{forcedKill:!1}:function(e,t){let r=!1;try{y(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),r=!0)}catch{f(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{er(t.infoPath),er(t.lockPath)}return{forcedKill:r}}(e,t);return D({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:o,requestId:r,command:a,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:n?void 0:e.pid,daemonPidForceKilled:n?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new u("COMMAND_FAILED","Daemon request timed out",{timeoutMs:o,requestId:r,hint:n?"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 ed(e,t,r){return D({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:r?"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 eu(t,r,a){let n=t.port;if(!n)throw new u("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((o,i)=>{let s=e.createConnection({host:"127.0.0.1",port:n},()=>{s.write(`${JSON.stringify(r)}
|
|
3
|
+
`)}),l=P(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),c="number"==typeof a?setTimeout(()=>{s.destroy(),i(ec(t,l,r.meta?.requestId,r.command,!1,a))},a):void 0,d="";s.setEncoding("utf8"),s.on("data",e=>{let t=(d+=e).indexOf("\n");if(-1===t)return;let a=d.slice(0,t).trim();if(a)try{let e=JSON.parse(a);s.end(),c&&clearTimeout(c),o(e)}catch(e){c&&clearTimeout(c),i(new u("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:a},e instanceof Error?e:void 0))}}),s.on("error",e=>{c&&clearTimeout(c),i(ed(e,r.meta?.requestId,!1))})})}async function ep(e,a,n){let o=e.baseUrl?new URL(ef(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!o)throw new u("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:a.meta?.requestId??_(),method:"agent_device.command",params:a}),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,c)=>{let d=P(a.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),p=("https:"===o.protocol?r:t).request({protocol:o.protocol,host:o.hostname,port:o.port,method:"POST",path:o.pathname+o.search,headers:s},t=>{let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{f&&clearTimeout(f);try{let t=JSON.parse(r);if(t.error){let e=t.error.data??{};c(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:a.meta?.requestId}));return}if(!t.result||"object"!=typeof t.result)return void c(new u("COMMAND_FAILED","Invalid daemon RPC response",{requestId:a.meta?.requestId}));if(e.baseUrl&&t.result.ok)return void eh(e,a,t.result).then(l).catch(c);l(t.result)}catch(e){f&&clearTimeout(f),c(new u("COMMAND_FAILED","Invalid daemon response",{requestId:a.meta?.requestId,line:r},e instanceof Error?e:void 0))}})}),m=em(e),f="number"==typeof n?setTimeout(()=>{p.destroy(),c(ec(e,d,a.meta?.requestId,a.command,m,n))},n):void 0;p.on("error",e=>{f&&clearTimeout(f),c(ed(e,a.meta?.requestId,m))}),p.write(i),p.end()})}function em(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function ef(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function eh(e,t,r){let a=Array.isArray(r.data?.artifacts)?r.data.artifacts:[];if(0===a.length||!e.baseUrl)return r;let o=r.data?{...r.data}:{},i=[];for(let r of a){if(!r||"object"!=typeof r||"string"!=typeof r.artifactId){i.push(r);continue}let a=function(e,t){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let r=e.fileName?.trim()||`${e.field}-${Date.now()}`;return n.resolve(t.meta?.cwd??process.cwd(),r)}(r,t);await ew({baseUrl:e.baseUrl,token:e.token,artifactId:r.artifactId,destinationPath:a,requestId:t.meta?.requestId}),o[r.field]=a,i.push({...r,localPath:a})}return o.artifacts=i,{ok:!0,data:o}}async function ew(e){var o,i;let s,l=new URL((o=e.baseUrl,i=e.artifactId,s=o.endsWith("/")?o:`${o}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),c="https:"===l.protocol?r:t;await a.promises.mkdir(n.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let n=!1,o=e.timeoutMs??O,i=o=>{if(!n){if(n=!0,clearTimeout(d),o)return void a.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(o));t()}},s=c.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 r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{i(new u("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=a.createWriteStream(e.destinationPath);r.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("aborted",()=>{i(new u("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),d=setTimeout(()=>{s.destroy(new u("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:o}))},o);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:o},t instanceof Error?t:void 0))}),s.end()})}function ey(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 ev="clipboard",eg="wait",eI=new Set(["id","role","text","label","value","appname","windowtitle"]),eA=new Set(["visible","hidden","editable","selected","enabled","hittable"]),eb=new Set([...eI,...eA]);function eS(e){let t=e.trim();if(!t)throw new u("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!eA.has(r))throw new u("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let a=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!eb.has(a))throw new u("INVALID_ARGS",`Unknown selector key: ${a}`);if(!n)throw new u("INVALID_ARGS",`Missing selector value for key: ${a}`);if(eA.has(a)){let e,t="true"===(e=eD(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new u("INVALID_ARGS",`Invalid boolean value for ${a}: ${n}`);return{key:a,value:t}}return{key:a,value:eD(n)}}function e_(e,t){return e?e===t?null:e:t}function eD(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function eM(e,t){let r=0;for(let a=t-1;a>=0&&"\\"===e[a];a-=1)r+=1;return r%2==1}let eP=g.map(e=>e.key);function eE(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function ek(e,t,r){return{deviceId:t,deviceName:r,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function eN(e,t,r,a){let n=r(e[t]);if(void 0===n)throw new u("COMMAND_FAILED",a,{response:e});return n}[...A];function eT(e,t){return eN(e,t,eO,`Daemon response is missing "${t}".`)}function ex(e,t){return eO(e[t])}function eR(e,t){var r;let a;return r=eO,null===(a=e[t])?null:r(a)}function eC(e,t){return eN(e,t,e$,`Daemon response has invalid "${t}".`)}function eL(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function eU(e,t){let r=e[t];if(!eB(r))return;let a="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0,o="number"==typeof r.width?r.width:void 0,i="number"==typeof r.height?r.height:void 0;if(void 0!==a&&void 0!==n&&void 0!==o&&void 0!==i)return{x:a,y:n,width:o,height:i}}function eO(e){return"string"==typeof e&&e.length>0?e:void 0}function eF(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function e$(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function ej(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function eq(e){if(!eB(e))throw new u("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eB(e){return"object"==typeof e&&null!==e}function eG(e){let t={};for(let[r,a]of Object.entries(e))void 0!==a&&(t[r]=a);return t}function eV(e,t){let r=ex(e,"bundleId"),a=ex(e,"package");return{app:eT(e,"app"),appPath:eT(e,"appPath"),platform:eC(e,"platform"),appId:r??a,bundleId:r,package:a,identifiers:eE({session:t,bundleId:r,packageName:a})}}function ez(e){let t=eq(e),r=eC(t,"platform"),a=eT(t,"id"),n=eT(t,"name");return{platform:r,target:eL(t,"target"),kind:eN(t,"kind",ej,'Daemon response has invalid "kind".'),id:a,name:n,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:ek(r,a,n),ios:"ios"===r?{udid:a}:void 0,android:"android"===r?{serial:a}:void 0}}function eK(e){let t=eq(e),r=eC(t,"platform"),a=eT(t,"id"),n=eT(t,"name"),o=eL(t,"target"),i=eT(t,"device"),s={session:n,...ek(r,a,i)};return{name:n,createdAt:eN(t,"createdAt",eF,'Daemon response is missing numeric "createdAt".'),device:{platform:r,target:o,id:a,name:i,identifiers:s,ios:"ios"===r?{udid:a,simulatorSetPath:eR(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:a}:void 0},identifiers:s}}function eH(e){return e??"default"}function eJ(e={},t={}){var r;let a,n=t.transport??B,o=eZ(e),i=async(t,r=[],a={})=>{let i=eY(e,o,a),s=await n({session:eH(i.session),command:t,positionals:r,flags:eG({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:eG({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(eK)},l=async(e,t=[],r={})=>await i(e,t,r),c=(t={})=>eH(eY(e,o,t).session);return{command:(r=async e=>await i(e.command,e.positionals,e.options),a=async e=>await r(e),{wait:async e=>await a(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:eg,positionals:[String(e.durationMs)],options:e};let t=void 0!==e.timeoutMs?[String(e.timeoutMs)]:[];if(void 0!==e.text)return{command:eg,positionals:["text",e.text,...t],options:e};if(void 0!==e.ref)return{command:eg,positionals:[e.ref,...t],options:e};let r=e.selector;return function(e){if(!function(e){try{let t=e.trim();if(!t)throw new u("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",a=null;for(let n=0;n<e.length;n+=1){let o=e[n];if(('"'===o||"'"===o)&&!eM(e,n)){a=e_(a,o),r+=o;continue}if(!a&&"|"===o&&"|"===e[n+1]){let a=r.trim();if(!a)throw new u("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(a),r="",n+=1;continue}r+=o}let n=r.trim();if(!n)throw new u("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new u("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new u("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",a=null;for(let n=0;n<e.length;n+=1){let o=e[n];if(('"'===o||"'"===o)&&!eM(e,n)){a=e_(a,o),r+=o;continue}if(!a&&/\s/.test(o)){r.trim()&&t.push(r.trim()),r="";continue}r+=o}if(a)throw new u("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim()&&t.push(r.trim()),t}(t);if(0===r.length)throw new u("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(eS)}})(e))}}catch{return null}}(e))throw new u("INVALID_ARGS",`Invalid wait selector: ${e}`)}(r),{command:eg,positionals:[r,...t],options:e}}(e)),alert:async(e={})=>{var t;return await a({command:"alert",positionals:[(t=e).action??"get",...void 0!==t.timeoutMs?[String(t.timeoutMs)]:[]],options:t})},appState:async(e={})=>await a({command:"appstate",positionals:[],options:e}),back:async(e={})=>await a({command:"back",positionals:[],options:{...e,backMode:e.mode}}),home:async(e={})=>await a({command:"home",positionals:[],options:e}),rotate:async e=>await a({command:"rotate",positionals:[e.orientation],options:e}),appSwitcher:async(e={})=>await a({command:"app-switcher",positionals:[],options:e}),keyboard:async(e={})=>await a({command:"keyboard",positionals:e.action?[e.action]:[],options:e}),clipboard:async e=>{var t;return await a("read"===(t=e).action?{command:ev,positionals:["read"],options:t}:{command:ev,positionals:["write",t.text],options:t})}}),devices:{list:async(e={})=>{let t=await i("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(ez)},boot:async(e={})=>await l("boot",[],e)},sessions:{list:async(e={})=>await s(e),close:async(e={})=>{let t=c(e),r=(await i("close",[],e)).shutdown;return{session:t,shutdown:"object"==typeof r&&null!==r?r:void 0,identifiers:{session:t}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,a=await i("ensure-simulator",[],{...r,simulatorRuntimeId:t}),n=eT(a,"udid"),o=eT(a,"device");return{udid:n,device:o,runtime:eT(a,"runtime"),created:!0===a.created,booted:!0===a.booted,iosSimulatorDeviceSet:eR(a,"ios_simulator_device_set"),identifiers:{deviceId:n,deviceName:o,udid:n}}}},apps:{install:async e=>eV(await i("install",[e.app,e.appPath],e),c(e)),reinstall:async e=>eV(await i("reinstall",[e.app,e.appPath],e),c(e)),installFromSource:async e=>(function(e,t){let r=ex(e,"bundleId"),a=ex(e,"packageName"),n=r??a??ex(e,"appId"),o=ex(e,"launchTarget")??a??r??n;if(!o)throw new u("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:ex(e,"appName"),appId:n,bundleId:r,packageName:a,launchTarget:o,installablePath:ex(e,"installablePath"),archivePath:ex(e,"archivePath"),materializationId:ex(e,"materializationId"),materializationExpiresAt:ex(e,"materializationExpiresAt"),identifiers:eE({session:t,bundleId:r,packageName:a,appId:n})}})(await i("install_source",[],{...e,installSource:e.source,retainMaterializedPaths:e.retainPaths,materializedPathRetentionMs:e.retentionMs}),c(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=c(e),r=e.app?e.url?[e.app,e.url]:[e.app]:[],a=await i("open",r,e),n=function(e){let t=e.platform,r=ex(e,"id"),a=ex(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!r||!a)return;let n=eL(e,"target"),o=ek(t,r,a);return{platform:t,target:n,id:r,name:a,identifiers:o,ios:"ios"===t?{udid:ex(e,"device_udid")??r,simulatorSetPath:eR(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:ex(e,"serial")??r}:void 0}}(a),o=ex(a,"appBundleId");return{session:t,appName:ex(a,"appName"),appBundleId:o,appId:o,startup:function(e){if(eB(e)&&"number"==typeof e.durationMs&&"string"==typeof e.measuredAt&&"string"==typeof e.method)return{durationMs:e.durationMs,measuredAt:e.measuredAt,method:e.method,appTarget:ex(e,"appTarget"),appBundleId:ex(e,"appBundleId")}}(a.startup),runtime:function(e){if(!eB(e))return;let t=e.platform,r=ex(e,"metroHost"),a="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:a,bundleUrl:ex(e,"bundleUrl"),launchUrl:ex(e,"launchUrl")}}(a.runtime),device:n,identifiers:{session:t,deviceId:n?.id,deviceName:n?.name,udid:n?.ios?.udid,serial:n?.android?.serial,appId:o,appBundleId:o}}},close:async(e={})=>{let t=c(e),r=(await i("close",e.app?[e.app]:[],e)).shutdown;return{session:t,closedApp:e.app,shutdown:"object"==typeof r&&null!==r?r: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:eT(t,"materializationId"),identifiers:{}}}},metro:{prepare:async t=>await h({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 r=c(e),a=await i("snapshot",[],e),n=ex(a,"appBundleId"),o="object"==typeof a.visibility&&null!==a.visibility?a.visibility:void 0;return{nodes:Array.isArray(t=a.nodes)?t:[],truncated:!0===a.truncated,appName:ex(a,"appName"),appBundleId:n,...o?{visibility:o}:{},warnings:Array.isArray(a.warnings)?a.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:r,appId:n,appBundleId:n}}},screenshot:async(e={})=>{let t=c(e),r=await i("screenshot",e.path?[e.path]:[],{...e,screenshotFullscreen:e.fullscreen});return{path:eT(r,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let r=[];for(let e of t){if(!eB(e))continue;let t=ex(e,"ref"),a=eU(e,"rect"),n=eU(e,"overlayRect"),o=function(e,t){let r=e[t];if(!eB(r))return;let a="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0;if(void 0!==a&&void 0!==n)return{x:a,y:n}}(e,"center");t&&a&&n&&o&&r.push({ref:t,label:ex(e,"label"),rect:a,overlayRect:n,center:o})}return r}(r),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",eW(e),{...e,clickButton:e.button}),press:async e=>await l("press",eW(e),e),longPress:async e=>await l("longpress",[String(e.x),String(e.y),...eX(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),...eX(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",[...eW(e),e.text],e),scroll:async e=>await l("scroll",[e.direction,...eX(e.amount)],e),pinch:async e=>await l("pinch",[String(e.scale),...eX(e.x),...eX(e.y)],e),get:async e=>{var t;return await l("get",[e.format,...void 0!==(t=e).ref?[t.ref,...eQ(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",...eX(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",...eQ(t.message)],e)},network:async(e={})=>{var t;return await l("network",[...(t=e).action?[t.action]:[],...eX(t.limit)],{...e,networkInclude:e.include})}},recording:{record:async e=>await l("record",[e.action,...eQ(e.path)],e),trace:async e=>await l("trace",[e.action,...eQ(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 eW(e){return void 0!==e.ref?[e.ref,...eQ(e.label)]:void 0!==e.selector?[e.selector]:[String(e.x),String(e.y)]}function eQ(e){return void 0===e?[]:[e]}function eX(e){return void 0===e?[]:[String(e)]}function eY(e,t,r){return r.remoteConfig&&r.remoteConfig!==e.remoteConfig?{...eZ({...e,...r}),...e,...r}:{...t,...e,...r}}function eZ(e){var t;if(!e.remoteConfig)return{};let{runtime:r,...a}=(t={remoteConfig:e.remoteConfig,cwd:e.cwd??process.cwd(),env:process.env}).remoteConfig?{...function(e){let t={};for(let r of eP){let a=e[r];void 0!==a&&(t[r]=a)}return t}(I({configPath:t.remoteConfig,cwd:t.cwd,env:t.env}).profile),remoteConfig:t.remoteConfig}:{};return a}export{AppError}from"./152.js";export{centerOfRect}from"./57.js";export{eJ as createAgentDeviceClient};
|
package/dist/src/metro.d.ts
CHANGED
|
@@ -179,6 +179,12 @@ export declare type PrepareRemoteMetroResult = {
|
|
|
179
179
|
logPath: string;
|
|
180
180
|
};
|
|
181
181
|
|
|
182
|
+
export declare function resolveRuntimeTransport(runtime: SessionRuntimeHints | undefined): {
|
|
183
|
+
host: string;
|
|
184
|
+
port: number;
|
|
185
|
+
scheme: 'http' | 'https';
|
|
186
|
+
} | undefined;
|
|
187
|
+
|
|
182
188
|
declare type SessionRuntimeHints = {
|
|
183
189
|
platform?: 'ios' | 'android';
|
|
184
190
|
metroHost?: string;
|
package/dist/src/metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildMetroRuntimeHints as
|
|
1
|
+
import{URL as t}from"node:url";import"node:fs";import"node:os";import e from"node:path";import{buildMetroRuntimeHints as o,ensureMetroCompanion as r,stopMetroCompanion as n,prepareMetroRuntime as i}from"./974.js";import{AppError as s}from"./152.js";function l(t){let e=t?.trim();return e&&e.length>0?e:void 0}function u(t){if(Number.isInteger(t)&&!(t<=0)&&!(t>65535))return t}function a(e){return function(e){if(!e)return;let o=l(e.metroHost),r=u(e.metroPort),n="http",i=l(e.bundleUrl);if(i){var a;let e;try{e=new t(i)}catch(t){throw new s("INVALID_ARGS",`Invalid runtime bundle URL: ${i}`,{},t)}("http:"===e.protocol||"https:"===e.protocol)&&(o??=l(e.hostname),r??=u(e.port.length>0?Number(e.port):"https:"===(a=e.protocol)?443:"http:"===a?80:void 0),n="https:"===e.protocol?"https":"http")}if(o&&r)return{host:o,port:r,scheme:n}}(e)}async function p(t){let e=await i({projectRoot:t.projectRoot,kind:t.kind,publicBaseUrl:t.publicBaseUrl,proxyBaseUrl:t.proxyBaseUrl,proxyBearerToken:t.proxyBearerToken,launchUrl:t.launchUrl,companionProfileKey:t.profileKey,companionConsumerKey:t.consumerKey,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,env:t.env});return{iosRuntime:e.iosRuntime,androidRuntime:e.androidRuntime,bridge:e.bridge,started:e.started,reused:e.reused,logPath:e.logPath}}async function d(t){let e=await r(t);return{pid:e.pid,started:e.spawned,logPath:e.logPath}}async function m(t){await n(t)}function c(t){return o(t,"ios")}function h(t){return o(t,"android")}e.join("cmdline-tools","latest","bin"),e.join("cmdline-tools","tools","bin");export{buildBundleUrl,normalizeBaseUrl}from"./974.js";export{h as buildAndroidRuntimeHints,c as buildIosRuntimeHints,d as ensureMetroTunnel,p as prepareRemoteMetro,a as resolveRuntimeTransport,m as stopMetroTunnel};
|
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
- `
|
|
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
|
-
-
|
|
119
|
-
-
|
|
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
|
|
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,
|
|
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.
|