agent-device 0.11.10 → 0.11.12
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/dist/src/113.js +3 -0
- package/dist/src/320.js +1 -0
- package/dist/src/818.js +3 -0
- package/dist/src/957.js +2 -0
- package/dist/src/974.js +2 -0
- package/dist/src/995.js +1 -3
- package/dist/src/bin.js +59 -61
- package/dist/src/contracts.d.ts +135 -0
- package/dist/src/contracts.js +1 -0
- package/dist/src/daemon.js +43 -43
- package/dist/src/index.d.ts +65 -39
- package/dist/src/index.js +2 -4
- package/dist/src/metro-companion.js +1 -0
- package/dist/src/metro.d.ts +197 -0
- package/dist/src/metro.js +1 -0
- package/dist/src/remote-config.d.ts +49 -0
- package/dist/src/remote-config.js +1 -0
- package/dist/src/update-check-entry.js +1 -0
- package/package.json +13 -1
package/dist/src/index.d.ts
CHANGED
|
@@ -350,51 +350,79 @@ declare type DaemonArtifact = {
|
|
|
350
350
|
path?: string;
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
+
declare type DaemonError = {
|
|
354
|
+
code: string;
|
|
355
|
+
message: string;
|
|
356
|
+
hint?: string;
|
|
357
|
+
diagnosticId?: string;
|
|
358
|
+
logPath?: string;
|
|
359
|
+
details?: Record<string, unknown>;
|
|
360
|
+
};
|
|
361
|
+
|
|
353
362
|
declare type DaemonInstallSource = MaterializeInstallSource;
|
|
354
363
|
|
|
364
|
+
declare type DaemonInstallSource_2 = {
|
|
365
|
+
kind: 'url';
|
|
366
|
+
url: string;
|
|
367
|
+
headers?: Record<string, string>;
|
|
368
|
+
} | {
|
|
369
|
+
kind: 'path';
|
|
370
|
+
path: string;
|
|
371
|
+
};
|
|
372
|
+
|
|
355
373
|
declare type DaemonLockPolicy = 'reject' | 'strip';
|
|
356
374
|
|
|
357
|
-
declare type DaemonRequest = {
|
|
375
|
+
declare type DaemonRequest = Omit<DaemonRequest_2, 'token' | 'session' | 'flags' | 'meta'> & {
|
|
358
376
|
token: string;
|
|
359
377
|
session: string;
|
|
378
|
+
flags?: CommandFlags;
|
|
379
|
+
meta?: DaemonRequestMeta_2;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
declare type DaemonRequest_2 = {
|
|
383
|
+
token?: string;
|
|
384
|
+
session?: string;
|
|
360
385
|
command: string;
|
|
361
386
|
positionals: string[];
|
|
362
|
-
flags?:
|
|
363
|
-
runtime?:
|
|
364
|
-
meta?:
|
|
365
|
-
requestId?: string;
|
|
366
|
-
debug?: boolean;
|
|
367
|
-
cwd?: string;
|
|
368
|
-
tenantId?: string;
|
|
369
|
-
runId?: string;
|
|
370
|
-
leaseId?: string;
|
|
371
|
-
leaseTtlMs?: number;
|
|
372
|
-
leaseBackend?: 'ios-simulator';
|
|
373
|
-
sessionIsolation?: 'none' | 'tenant';
|
|
374
|
-
uploadedArtifactId?: string;
|
|
375
|
-
clientArtifactPaths?: Record<string, string>;
|
|
376
|
-
installSource?: DaemonInstallSource;
|
|
377
|
-
retainMaterializedPaths?: boolean;
|
|
378
|
-
materializedPathRetentionMs?: number;
|
|
379
|
-
materializationId?: string;
|
|
380
|
-
lockPolicy?: DaemonLockPolicy;
|
|
381
|
-
lockPlatform?: PlatformSelector;
|
|
382
|
-
};
|
|
387
|
+
flags?: Record<string, unknown>;
|
|
388
|
+
runtime?: SessionRuntimeHints_2;
|
|
389
|
+
meta?: DaemonRequestMeta;
|
|
383
390
|
};
|
|
384
391
|
|
|
385
|
-
declare type
|
|
392
|
+
declare type DaemonRequestMeta = {
|
|
393
|
+
requestId?: string;
|
|
394
|
+
debug?: boolean;
|
|
395
|
+
cwd?: string;
|
|
396
|
+
tenantId?: string;
|
|
397
|
+
runId?: string;
|
|
398
|
+
leaseId?: string;
|
|
399
|
+
leaseTtlMs?: number;
|
|
400
|
+
leaseBackend?: LeaseBackend;
|
|
401
|
+
sessionIsolation?: 'none' | 'tenant';
|
|
402
|
+
uploadedArtifactId?: string;
|
|
403
|
+
clientArtifactPaths?: Record<string, string>;
|
|
404
|
+
installSource?: DaemonInstallSource_2;
|
|
405
|
+
retainMaterializedPaths?: boolean;
|
|
406
|
+
materializedPathRetentionMs?: number;
|
|
407
|
+
materializationId?: string;
|
|
408
|
+
lockPolicy?: DaemonLockPolicy;
|
|
409
|
+
lockPlatform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
declare type DaemonRequestMeta_2 = Omit<DaemonRequestMeta, 'installSource' | 'lockPlatform'> & {
|
|
413
|
+
installSource?: DaemonInstallSource;
|
|
414
|
+
lockPlatform?: PlatformSelector;
|
|
415
|
+
leaseBackend?: 'ios-simulator';
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
declare type DaemonResponse = DaemonResponse_2;
|
|
419
|
+
|
|
420
|
+
declare type DaemonResponse_2 = {
|
|
386
421
|
ok: true;
|
|
387
422
|
data?: DaemonResponseData;
|
|
388
423
|
} | {
|
|
389
424
|
ok: false;
|
|
390
|
-
error:
|
|
391
|
-
code: string;
|
|
392
|
-
message: string;
|
|
393
|
-
hint?: string;
|
|
394
|
-
diagnosticId?: string;
|
|
395
|
-
logPath?: string;
|
|
396
|
-
details?: Record<string, unknown>;
|
|
397
|
-
};
|
|
425
|
+
error: DaemonError;
|
|
398
426
|
};
|
|
399
427
|
|
|
400
428
|
declare type DaemonResponseData = Record<string, unknown> & {
|
|
@@ -429,6 +457,8 @@ declare type EnsureSimulatorResult = {
|
|
|
429
457
|
|
|
430
458
|
declare type ErrorCode = 'INVALID_ARGS' | 'DEVICE_NOT_FOUND' | 'TOOL_MISSING' | 'APP_NOT_INSTALLED' | 'UNSUPPORTED_PLATFORM' | 'UNSUPPORTED_OPERATION' | 'COMMAND_FAILED' | 'SESSION_NOT_FOUND' | 'UNAUTHORIZED' | 'UNKNOWN';
|
|
431
459
|
|
|
460
|
+
declare type LeaseBackend = 'ios-simulator' | 'ios-instance' | 'android-instance';
|
|
461
|
+
|
|
432
462
|
declare type MaterializationReleaseOptions = AgentDeviceRequestOverrides & {
|
|
433
463
|
materializationId: string;
|
|
434
464
|
};
|
|
@@ -493,13 +523,7 @@ declare type MetroPrepareOptions = {
|
|
|
493
523
|
|
|
494
524
|
declare type MetroPrepareResult = PrepareMetroRuntimeResult;
|
|
495
525
|
|
|
496
|
-
declare type MetroRuntimeHints =
|
|
497
|
-
platform?: 'ios' | 'android';
|
|
498
|
-
metroHost?: string;
|
|
499
|
-
metroPort?: number;
|
|
500
|
-
bundleUrl?: string;
|
|
501
|
-
launchUrl?: string;
|
|
502
|
-
};
|
|
526
|
+
declare type MetroRuntimeHints = SessionRuntimeHints_2;
|
|
503
527
|
|
|
504
528
|
declare type Platform = ApplePlatform | 'android' | 'linux';
|
|
505
529
|
|
|
@@ -574,7 +598,9 @@ declare type SessionCloseResult = {
|
|
|
574
598
|
|
|
575
599
|
declare type SessionIsolationMode = 'none' | 'tenant';
|
|
576
600
|
|
|
577
|
-
declare type SessionRuntimeHints =
|
|
601
|
+
declare type SessionRuntimeHints = SessionRuntimeHints_2;
|
|
602
|
+
|
|
603
|
+
declare type SessionRuntimeHints_2 = {
|
|
578
604
|
platform?: 'ios' | 'android';
|
|
579
605
|
metroHost?: string;
|
|
580
606
|
metroPort?: number;
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
let e;import t from"node:net";import r from"node:http";import n from"node:https";import o from"node:fs";import a from"node:path";import{AsyncLocalStorage as i}from"node:async_hooks";import s,{createHash as l}from"node:crypto";import u from"node:os";import"node:fs/promises";import{spawn as c,spawnSync as d}from"node:child_process";import{fileURLToPath as m,pathToFileURL as p}from"node:url";import{setTimeout as f}from"node:timers/promises";let h=new i,y=/(token|secret|password|authorization|cookie|api[_-]?key|access[_-]?key|private[_-]?key)/i,g=/(bearer\s+[a-z0-9._-]+|(?:api[_-]?key|token|secret|password)\s*[=:]\s*\S+)/i;function w(){return s.randomBytes(8).toString("hex")}function v(e){let t=h.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?function e(t,r,n){if(null==t)return t;if("string"==typeof t){var o=t,a=n;let e=o.trim();if(!e)return o;if(a&&y.test(a)||g.test(e))return"[REDACTED]";let r=function(e){try{let t=new URL(e);return t.search&&(t.search="?REDACTED"),(t.username||t.password)&&(t.username="REDACTED",t.password="REDACTED"),t.toString()}catch{return null}}(e);return r||(e.length>400?`${e.slice(0,200)}...<truncated>`:e)}if("object"!=typeof t)return t;if(r.has(t))return"[Circular]";if(r.add(t),Array.isArray(t))return t.map(t=>e(t,r));let i={};for(let[n,o]of Object.entries(t)){if(y.test(n)){i[n]="[REDACTED]";continue}i[n]=e(o,r,n)}return i}(e.data,new WeakSet):void 0};if(t.events.push(r),!t.debug)return;let n=`[agent-device][diag] ${JSON.stringify(r)}
|
|
2
|
-
`;try{t.logPath&&o.appendFile(t.logPath,n,()=>{}),t.traceLogPath&&o.appendFile(t.traceLogPath,n,()=>{}),t.logPath||t.traceLogPath||process.stderr.write(n)}catch{}}async function b(e,t,r){let n=Date.now();try{let o=await t();return v({level:"info",phase:e,durationMs:Date.now()-n,data:r}),o}catch(t){throw v({level:"error",phase:e,durationMs:Date.now()-n,data:{...r??{},error:t instanceof Error?t.message:String(t)}}),t}}class I extends Error{code;details;cause;constructor(e,t,r,n){super(t),this.code=e,this.details=r,this.cause=n}}let E=/^[A-Za-z0-9][A-Za-z0-9._+-]*$/;function S(e,t,r={}){let n=_(e),o=d(n,t,{cwd:r.cwd,env:r.env,stdio:["pipe","pipe","pipe"],encoding:r.binaryStdout?void 0:"utf8",input:r.stdin,timeout:P(r.timeoutMs),shell:!1});if(o.error){let a=o.error.code;if("ETIMEDOUT"===a)throw new I("COMMAND_FAILED",`${n} timed out after ${P(r.timeoutMs)}ms`,{cmd:e,args:t,timeoutMs:P(r.timeoutMs)},o.error);if("ENOENT"===a)throw new I("TOOL_MISSING",`${n} not found in PATH`,{cmd:e},o.error);throw new I("COMMAND_FAILED",`Failed to run ${n}`,{cmd:e,args:t},o.error)}let a=r.binaryStdout?Buffer.isBuffer(o.stdout)?o.stdout:Buffer.from(o.stdout??""):void 0,i=r.binaryStdout?"":"string"==typeof o.stdout?o.stdout:(o.stdout??"").toString(),s="string"==typeof o.stderr?o.stderr:(o.stderr??"").toString(),l=o.status??1;if(0!==l&&!r.allowFailure)throw new I("COMMAND_FAILED",`${n} exited with code ${l}`,{cmd:e,args:t,stdout:i,stderr:s,exitCode:l,processExitError:!0});return{stdout:i,stderr:s,exitCode:l,stdoutBuffer:a}}function A(e,t,r={}){let n=c(_(e),t,{cwd:r.cwd,env:r.env,stdio:r.stdio??"ignore",detached:!0,shell:!1});return n.unref(),n.pid??0}function _(e){var t;let r,n=(t={allowRelativePath:!0},!(r=e.trim())||r.includes("\0")?null:a.isAbsolute(r)?r:r.includes("/")||r.includes("\\")?t.allowRelativePath?r:null:E.test(r)?r:null);if(!n)throw new I("INVALID_ARGS",`Invalid executable command: ${JSON.stringify(e)}`,{cmd:e});return n}function P(e){if(!Number.isFinite(e))return;let t=Math.floor(e);if(!(t<=0))return t}function D(){let e=a.dirname(m(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=a.join(t,"package.json");if(o.existsSync(e))return t;t=a.dirname(t)}return e}let k=[/(^|[/\s"'=])dist\/src\/daemon\.js($|[\s"'])/,/(^|[/\s"'=])src\/daemon\.ts($|[\s"'])/];function M(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(e){return"EPERM"===e.code}}function T(e){if(!Number.isInteger(e)||e<=0)return null;try{let t=S("ps",["-p",String(e),"-o","lstart="],{allowFailure:!0,timeoutMs:1e3});if(0!==t.exitCode)return null;let r=t.stdout.trim();return r.length>0?r:null}catch{return null}}function N(e){if(!Number.isInteger(e)||e<=0)return null;try{let t=S("ps",["-p",String(e),"-o","command="],{allowFailure:!0,timeoutMs:1e3});if(0!==t.exitCode)return null;let r=t.stdout.trim();return r.length>0?r:null}catch{return null}}function U(e,t){let r;if(!M(e))return!1;if(t){let r=T(e);if(!r||r!==t)return!1}let n=N(e);return!!n&&!!(r=n.toLowerCase().replaceAll("\\","/")).includes("agent-device")&&k.some(e=>e.test(r))}function R(e,t){try{return process.kill(e,t),!0}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return!1;throw t}}async function O(e,t){if(!M(e))return!0;let r=Date.now();for(;Date.now()-r<t;)if(await new Promise(e=>setTimeout(e,50)),!M(e))return!0;return!M(e)}async function L(e,t){!U(e,t.expectedStartTime)||!R(e,"SIGTERM")||await O(e,t.termTimeoutMs)||R(e,"SIGKILL")&&await O(e,t.killTimeoutMs)}function C(e){return e?.HOME?.trim()||u.homedir()}function x(e,t={}){return"~"===e?C(t.env):e.startsWith("~/")?a.join(C(t.env),e.slice(2)):e}function $(e,t={}){let r=x(e,t);return a.isAbsolute(r)?r:a.resolve(t.cwd??process.cwd(),r)}function B(e){let t,r=(t=(e??"").trim())?$(t):a.join(x("~"),".agent-device");return{baseDir:r,infoPath:a.join(r,"daemon.json"),lockPath:a.join(r,"daemon.lock"),logPath:a.join(r,"daemon.log"),sessionsDir:a.join(r,"sessions")}}async function F(e){let{localPath:t,baseUrl:i,token:s}=e,l=o.statSync(t).isDirectory(),u=a.basename(t),d=new URL("upload",i.endsWith("/")?i:`${i}/`),m="https:"===d.protocol?n:r,p={"x-artifact-type":l?"app-bundle":"file","x-artifact-filename":u,"transfer-encoding":"chunked"};return s&&(p.authorization=`Bearer ${s}`,p["x-agent-device-token"]=s),new Promise((e,r)=>{let n=m.request({protocol:d.protocol,host:d.hostname,port:d.port,method:"POST",path:d.pathname+d.search,headers:p},t=>{let n="";t.setEncoding("utf8"),t.on("data",e=>{n+=e}),t.on("end",()=>{clearTimeout(i);try{let t=JSON.parse(n);if(!t.ok||!t.uploadId)return void r(new I("COMMAND_FAILED",`Upload failed: ${n}`));e(t.uploadId)}catch{r(new I("COMMAND_FAILED",`Invalid upload response: ${n}`))}})}),i=setTimeout(()=>{n.destroy(),r(new I("COMMAND_FAILED","Artifact upload timed out",{timeoutMs:3e5,hint:"The upload to the remote daemon exceeded the 5-minute timeout."}))},3e5);if(n.on("error",e=>{clearTimeout(i),r(new I("COMMAND_FAILED","Failed to upload artifact to remote daemon",{hint:"Verify the remote daemon is reachable and supports artifact uploads."},e))}),l){let e=c("tar",["cf","-","-C",a.dirname(t),a.basename(t)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(n),e.on("error",e=>{n.destroy(),r(new I("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(n.destroy(),r(new I("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=o.createReadStream(t);e.pipe(n),e.on("error",e=>{n.destroy(),r(new I("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}let j=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,q=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,G=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function V(e,t,r){t.lastIndex=0;let n=null;for(;null!==(n=t.exec(e));){let e=n[1]?.trim();e?.startsWith(".")&&r.add(e)}}function H(e){try{return o.statSync(e).isFile()?e:null}catch{return null}}let z=eP(),K=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS){if(!e)return 15e3;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):15e3}(),J=function(e=process.env.AGENT_DEVICE_DAEMON_STARTUP_ATTEMPTS){if(!e)return 2;let t=Number(e);return Number.isFinite(t)?Math.min(5,Math.max(1,Math.floor(t))):2}(),W=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],Z=new t.BlockList;async function X(e){let r=e.meta?.requestId??w(),n=!!(e.meta?.debug||e.flags?.verbose),o=function(e){let r,n,o,a=e.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR,i=function(e){let t;if(e){try{t=new URL(e)}catch(t){throw new I("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new I("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(e.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),s=e.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN;var l=i,u=s;if(!(!l||"localhost"===(r=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(t.isIPv4(r)?Z.check(r,"ipv4"):!!t.isIPv6(r)&&Z.check(r,"ipv6")))&&("string"!=typeof u||!(u.trim().length>0)))throw new I("INVALID_ARGS","Remote daemon base URL for non-loopback hosts requires daemon authentication",{daemonBaseUrl:l,hint:"Provide --daemon-auth-token or AGENT_DEVICE_DAEMON_AUTH_TOKEN when using a non-loopback remote daemon URL."});let c=e.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,d="auto"===(n=(c??"").trim().toLowerCase())?"auto":"socket"===n?"socket":"http"===n?"http":"auto";if(i&&"socket"===d)throw new I("INVALID_ARGS","Remote daemon base URL only supports HTTP transport. Remove --daemon-transport socket.",{daemonBaseUrl:i});let m="http"===(o=(e.flags?.daemonServerMode??process.env.AGENT_DEVICE_DAEMON_SERVER_MODE??("dual"===c?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===o?"dual":"socket";return{paths:B(a),transportPreference:d,serverMode:m,remoteBaseUrl:i,remoteAuthToken:s}}(e),a=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return eP(t)}(e.command),i=await b("daemon_startup",async()=>await er(o),{requestId:r,session:e.session}),s=await Y(e,i),l={...e,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...e.meta??{},requestId:r,debug:n,cwd:e.meta?.cwd,tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,sessionIsolation:e.meta?.sessionIsolation??e.flags?.sessionIsolation,lockPolicy:e.meta?.lockPolicy,lockPlatform:e.meta?.lockPlatform,...s.uploadedArtifactId?{uploadedArtifactId:s.uploadedArtifactId}:{},...s.clientArtifactPaths?{clientArtifactPaths:s.clientArtifactPaths}:{},...s.installSource?{installSource:s.installSource}:{}}};return v({level:"info",phase:"daemon_request_prepare",data:{requestId:r,command:e.command,session:e.session}}),await b("daemon_request",async()=>await eh(i,l,o.transportPreference,a),{requestId:r,command:e.command})}async function Y(e,t){let r,n=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(eE(t)){let o=function(e,t){if("screenshot"===e.command){let r=ee(e,"path",".png");return t[0]?{field:"path",localPath:r,positionalIndex:0,positionalPath:et("screenshot",".png")}:{field:"path",localPath:r,positionalIndex:0,flagPath:et("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=ee(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:et("recording",a.extname(t)||".mp4")}}return null}(e,n);o&&(void 0!==o.positionalPath&&(n[o.positionalIndex]=o.positionalPath),void 0!==o.flagPath&&((i??={}).out=o.flagPath),l[o.field]=o.localPath);let u=await Q(e,t);u&&(s=u.installSource,r=u.uploadedArtifactId??r)}if(!eE(t)||"install"!==e.command&&"reinstall"!==e.command||n.length<2)return{positionals:n,flags:i,installSource:s,uploadedArtifactId:r,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let u=n[1];if(u.startsWith("remote:"))return n[1]=u.slice(7),{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let c=a.isAbsolute(u)?u:a.resolve(e.meta?.cwd??process.cwd(),u);return o.existsSync(c)?{positionals:n,flags:i,installSource:s,uploadedArtifactId:r=await F({localPath:c,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:n,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function Q(e,t){let r=e.meta?.installSource;if("install_source"!==e.command||!r||"path"!==r.kind)return null;let n=r.path.trim();if(!n)return{installSource:r};if(n.startsWith("remote:"))return{installSource:{...r,path:n.slice(7)}};let i=a.isAbsolute(n)?n:a.resolve(e.meta?.cwd??process.cwd(),n);if(!o.existsSync(i))return{installSource:{...r,path:i}};let s=await F({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...r,path:i},uploadedArtifactId:s}}function ee(e,t,r,n=0){let o=e.positionals?.[n]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${r}`,s=o&&o.trim().length>0?o:i;return a.isAbsolute(s)?s:a.resolve(e.meta?.cwd??process.cwd(),s)}function et(e,t){let r=t.startsWith(".")?t:`.${t}`;return a.posix.join("/tmp",`agent-device-${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${r}`)}async function er(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await em(t,"http"))return t;throw new I("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=es(e.paths.infoPath),n=function(){try{let e=D();return JSON.parse(o.readFileSync(a.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=D()){try{let r=a.resolve(t),n=[a.resolve(e)],i=new Set,l=[];for(;n.length>0;){let e=n.pop();if(!e||i.has(e))continue;i.add(e);let t=o.statSync(e);if(!t.isFile())continue;let s=a.relative(r,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let u=o.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return V(e,j,t),V(e,q,t),[...t]}(u)){let r=function(e,t){let r=a.resolve(a.dirname(e),t),n=H(r);if(n)return n;for(let e of G){let t=H(`${r}${e}`);if(t)return t}for(let e of G){let t=H(a.join(r,`index${e}`));if(t)return t}return null}(e,t);r&&n.push(r)}}let u=l.sort().join("|"),c=s.createHash("sha1").update(u).digest("hex");return`graph:${l.length}:${c}`}catch{return"unknown"}}((t=ef()).useSrc?t.srcPath:t.distPath,t.root),l=!!r&&await em(r,e.transportPreference);if(r&&r.version===n&&r.codeSignature===i&&l)return r;r&&(r.version!==n||r.codeSignature!==i||!l)&&(await ei(r),ed(e.paths.infoPath)),function(e){let t=eu(e);if(!t.hasLock||t.hasInfo)return;let r=el(e.lockPath);if(!r)return ed(e.lockPath);U(r.pid,r.processStartTime)||ed(e.lockPath)}(e.paths);let u=0;for(let t=1;t<=J;t+=1){await ep(e);let r=await en(K,e);if(r)return r;if(await ea(e.paths)){u+=1;continue}let n=eu(e.paths);if(!(t<J))break;if(!n.hasInfo&&!n.hasLock){await eo(150);continue}}let c=eu(e.paths);throw new I("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:K,startupAttempts:J,lockRecoveryCount:u,metadataState:c,hint:function(e,t=B(process.env.AGENT_DEVICE_STATE_DIR)){return e.hasLock&&!e.hasInfo?`Detected ${t.lockPath} without ${t.infoPath}. If no agent-device daemon process is running, delete ${t.lockPath} and retry.`:e.hasLock&&e.hasInfo?`Daemon metadata may be stale. If no agent-device daemon process is running, delete ${t.infoPath} and ${t.lockPath}, then retry.`:`Daemon metadata is missing or stale. Delete ${t.infoPath} if present and retry.`}(c,e.paths)})}async function en(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=es(t.paths.infoPath);if(e&&await em(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function eo(e){await new Promise(t=>setTimeout(t,e))}async function ea(e){let t=eu(e);if(!t.hasLock||t.hasInfo)return!1;let r=el(e.lockPath);return r&&U(r.pid,r.processStartTime)&&await L(r.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:r.processStartTime}),ed(e.lockPath),!0}async function ei(e){await L(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function es(e){let t=ec(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 n=Number.isInteger(t.port)&&Number(t.port)>0,o=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!n&&!o)return null;let a=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,u=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:r,port:n?Number(t.port):void 0,httpPort:o?Number(t.httpPort):void 0,transport:"socket"===a||"http"===a||"dual"===a?a:void 0,pid:u?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function el(e){let t=ec(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}Z.addSubnet("127.0.0.0",8,"ipv4"),Z.addAddress("::1","ipv6"),Z.addSubnet("::ffff:127.0.0.0",104,"ipv6");function eu(e){return{hasInfo:o.existsSync(e.infoPath),hasLock:o.existsSync(e.lockPath)}}function ec(e){if(!o.existsSync(e))return null;try{return JSON.parse(o.readFileSync(e,"utf8"))}catch{return null}}function ed(e){try{o.existsSync(e)&&o.unlinkSync(e)}catch{}}async function em(e,o){var a;return"http"===ey(e,o)?await function(e){let t=e.baseUrl?eS(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!t)return Promise.resolve(!1);let o=new URL(t),a="https:"===o.protocol?n:r,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=a.request({protocol:o.protocol,host:o.hostname,port:o.port,path:o.pathname+o.search,method:"GET",timeout:i},t=>{t.resume(),e((t.statusCode??500)<500)});t.on("timeout",()=>{t.destroy(),e(!1)}),t.on("error",()=>{e(!1)}),t.end()})}(e):await ((a=e.port)?new Promise(e=>{let r=t.createConnection({host:"127.0.0.1",port:a},()=>{r.destroy(),e(!0)});r.on("error",()=>{e(!1)})}):Promise.resolve(!1))}async function ep(e){let t=ef(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],n={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};A(process.execPath,r,{env:n})}function ef(){let e=D(),t=a.join(e,"dist","src","daemon.js"),r=a.join(e,"src","daemon.ts"),n=o.existsSync(t),i=o.existsSync(r);if(!n&&!i)throw new I("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:!n&&i}}async function eh(e,t,r,n){return"http"===ey(e,r)?await eI(e,t,n):await eb(e,t,n)}function ey(e,t){if(e.baseUrl){if("socket"===t)throw new I("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t||"socket"===t){var r=e,n=t;if(eg(r,n))return n;throw new I("COMMAND_FAILED","http"===n?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let o=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>eg(e,t));if(o)return o;throw new I("COMMAND_FAILED","Daemon metadata has no reachable transport")}function eg(e,t){return"http"===t?!!e.httpPort:!!e.port}function ew(e,t,r,n,o,a){let i=o?{terminated:0}:function(){let e=0;try{for(let t of W){let r=S("pkill",["-f",t],{allowFailure:!0});0===r.exitCode&&(e+=1)}return{terminated:e}}catch(t){return{terminated:e,error:t instanceof Error?t.message:String(t)}}}(),s=o?{forcedKill:!1}:function(e,t){let r=!1;try{U(e.pid,e.processStartTime)&&(process.kill(e.pid,"SIGKILL"),r=!0)}catch{L(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{ed(t.infoPath),ed(t.lockPath)}return{forcedKill:r}}(e,t);return v({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:a,requestId:r,command:n,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:o?void 0:e.pid,daemonPidForceKilled:o?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new I("COMMAND_FAILED","Daemon request timed out",{timeoutMs:a,requestId:r,hint:o?"Retry with --debug and verify the remote daemon URL, auth token, and remote host logs.":"Retry with --debug and check daemon diagnostics logs. Timed-out iOS runner xcodebuild processes were terminated when detected."})}function ev(e,t,r){return v({level:"error",phase:"daemon_request_socket_error",data:{requestId:t,message:e instanceof Error?e.message:String(e)}}),new I("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 eb(e,r,n){let o=e.port;if(!o)throw new I("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((a,i)=>{let s=t.createConnection({host:"127.0.0.1",port:o},()=>{s.write(`${JSON.stringify(r)}
|
|
3
|
-
`)}),l=B(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),u="number"==typeof n?setTimeout(()=>{s.destroy(),i(ew(e,l,r.meta?.requestId,r.command,!1,n))},n):void 0,c="";s.setEncoding("utf8"),s.on("data",e=>{let t=(c+=e).indexOf("\n");if(-1===t)return;let n=c.slice(0,t).trim();if(n)try{let e=JSON.parse(n);s.end(),u&&clearTimeout(u),a(e)}catch(e){u&&clearTimeout(u),i(new I("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:n},e instanceof Error?e:void 0))}}),s.on("error",e=>{u&&clearTimeout(u),i(ev(e,r.meta?.requestId,!1))})})}async function eI(e,t,o){let a=e.baseUrl?new URL(eS(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!a)throw new I("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:t.meta?.requestId??w(),method:"agent_device.command",params:t}),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,u)=>{let c=B(t.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),d=("https:"===a.protocol?n:r).request({protocol:a.protocol,host:a.hostname,port:a.port,method:"POST",path:a.pathname+a.search,headers:s},r=>{let n="";r.setEncoding("utf8"),r.on("data",e=>{n+=e}),r.on("end",()=>{p&&clearTimeout(p);try{let r=JSON.parse(n);if(r.error){let e=r.error.data??{};u(new I(String(e.code??"COMMAND_FAILED"),String(e.message??r.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:t.meta?.requestId}));return}if(!r.result||"object"!=typeof r.result)return void u(new I("COMMAND_FAILED","Invalid daemon RPC response",{requestId:t.meta?.requestId}));if(e.baseUrl&&r.result.ok)return void eA(e,t,r.result).then(l).catch(u);l(r.result)}catch(e){p&&clearTimeout(p),u(new I("COMMAND_FAILED","Invalid daemon response",{requestId:t.meta?.requestId,line:n},e instanceof Error?e:void 0))}})}),m=eE(e),p="number"==typeof o?setTimeout(()=>{d.destroy(),u(ew(e,c,t.meta?.requestId,t.command,m,o))},o):void 0;d.on("error",e=>{p&&clearTimeout(p),u(ev(e,t.meta?.requestId,m))}),d.write(i),d.end()})}function eE(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function eS(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function eA(e,t,r){let n=Array.isArray(r.data?.artifacts)?r.data.artifacts:[];if(0===n.length||!e.baseUrl)return r;let o=r.data?{...r.data}:{},i=[];for(let r of n){if(!r||"object"!=typeof r||"string"!=typeof r.artifactId){i.push(r);continue}let n=function(e,t){if(e.localPath&&e.localPath.trim().length>0)return e.localPath;let r=e.fileName?.trim()||`${e.field}-${Date.now()}`;return a.resolve(t.meta?.cwd??process.cwd(),r)}(r,t);await e_({baseUrl:e.baseUrl,token:e.token,artifactId:r.artifactId,destinationPath:n,requestId:t.meta?.requestId}),o[r.field]=n,i.push({...r,localPath:n})}return o.artifacts=i,{ok:!0,data:o}}async function e_(e){var t,i;let s,l=new URL((t=e.baseUrl,i=e.artifactId,s=t.endsWith("/")?t:`${t}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),u="https:"===l.protocol?n:r;await o.promises.mkdir(a.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let n=!1,a=e.timeoutMs??z,i=a=>{if(!n){if(n=!0,clearTimeout(c),a)return void o.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(a));t()}},s=u.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 I("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=o.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 I("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),c=setTimeout(()=>{s.destroy(new I("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:a}))},a);s.on("error",t=>{t instanceof I?i(t):i(new I("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:a},t instanceof Error?t:void 0))}),s.end()})}function eP(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 eD="--agent-device-run-metro-companion",ek="AGENT_DEVICE_METRO_COMPANION_SERVER_BASE_URL",eM="AGENT_DEVICE_METRO_COMPANION_BEARER_TOKEN",eT="AGENT_DEVICE_METRO_COMPANION_LOCAL_BASE_URL",eN="AGENT_DEVICE_METRO_COMPANION_LAUNCH_URL";function eU(e){return e.replace(/\/+$/,"")}async function eR(e){var t,r;let n=await fetch(`${eU(e.serverBaseUrl)}/api/metro/companion/register`,{method:"POST",headers:(t=e.serverBaseUrl,r=e.bearerToken,{authorization:`Bearer ${r}`,"content-type":"application/json",...t.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}),body:JSON.stringify({local_base_url:eU(e.localBaseUrl),...e.launchUrl?{launch_url:e.launchUrl}:{}})}),o=await n.json();if(!n.ok||!0!==o.ok||"string"!=typeof o.data?.ws_url)throw Error(`Failed to register Metro companion: ${JSON.stringify(o)}`);return{wsUrl:o.data.ws_url}}async function eO(e){return"string"==typeof e?Buffer.from(e,"utf8"):e instanceof ArrayBuffer?Buffer.from(e):ArrayBuffer.isView(e)?Buffer.from(e.buffer,e.byteOffset,e.byteLength):"u">typeof Blob&&e instanceof Blob?Buffer.from(await e.arrayBuffer()):Buffer.from(String(e),"utf8")}async function eL(e){return JSON.parse((await eO(e.data)).toString("utf8"))}function eC(e,t){1===e.readyState&&e.send(JSON.stringify(t))}async function ex(e,t){1!==e.readyState&&await new Promise((r,n)=>{let o=()=>{s(),r()},a=()=>{s(),n(Error(`${t} WebSocket failed before opening.`))},i=()=>{s(),n(Error(`${t} WebSocket closed before opening.`))},s=()=>{e.removeEventListener("open",o),e.removeEventListener("error",a),e.removeEventListener("close",i)};e.addEventListener("open",o,{once:!0}),e.addEventListener("error",a,{once:!0}),e.addEventListener("close",i,{once:!0})})}async function e$(e){e.readyState>=WebSocket.CLOSING||await new Promise(t=>{let r=()=>{n(),t()},n=()=>{e.removeEventListener("close",r),e.removeEventListener("error",r)};e.addEventListener("close",r,{once:!0}),e.addEventListener("error",r,{once:!0}),e.readyState>=WebSocket.CLOSING&&r()})}function eB(e,t,r){try{e.close(t,r)}catch{}}async function eF(e,t,r,n){var o,a;switch(t.type){case"ping":return void eC(e,{type:"pong",timestamp:t.timestamp});case"http-request":try{let n=await fetch(new URL(t.path,`${eU(r.localBaseUrl)}/`),{method:t.method,headers:t.headers,...t.bodyBase64?{body:Buffer.from(t.bodyBase64,"base64")}:{}}),o=Buffer.from(await n.arrayBuffer());eC(e,{type:"http-response",requestId:t.requestId,status:n.status,headers:Object.fromEntries(n.headers.entries()),...o.length>0?{bodyBase64:o.toString("base64")}:{}})}catch(r){eC(e,{type:"http-error",requestId:t.requestId,message:r instanceof Error?r.message:String(r)})}return;case"ws-open":{let a,i=new WebSocket((o=r.localBaseUrl,(a=new URL(t.path,`${eU(o)}/`)).protocol="https:"===a.protocol?"wss:":"ws:",a.toString()));i.binaryType="arraybuffer";let s=!1;i.addEventListener("message",r=>{(async()=>{if(!s)return;let n=await eO(r.data);eC(e,{type:"ws-frame",streamId:t.streamId,dataBase64:n.toString("base64"),binary:"string"!=typeof r.data})})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),i.addEventListener("close",r=>{n.delete(t.streamId),s&&eC(e,{type:"ws-close",streamId:t.streamId,code:r.code,reason:r.reason})}),i.addEventListener("error",()=>{s&&eC(e,{type:"ws-close",streamId:t.streamId,code:1011,reason:"Upstream WebSocket error."})}),n.set(t.streamId,i);try{await ex(i,"Upstream"),s=!0,eC(e,{type:"ws-open-result",streamId:t.streamId,success:!0,headers:{}})}catch(r){n.delete(t.streamId),eB(i,1011,"open failed"),eC(e,{type:"ws-open-result",streamId:t.streamId,success:!1,error:r instanceof Error?r.message:String(r)})}return}case"ws-frame":{let e=n.get(t.streamId);if(!e||1!==e.readyState)return;let r=Buffer.from(t.dataBase64,"base64");e.send(t.binary?r:r.toString("utf8"));return}case"ws-close":{let e=n.get(t.streamId);if(!e)return;n.delete(t.streamId),eB(e,"number"==typeof(a=t.code)&&Number.isInteger(a)&&(1e3===a||a>=3e3&&a<=4999||a>=1001&&a<=1015&&1004!==a&&1005!==a&&1006!==a)?a:1011,t.reason??"bridge requested close");return}}}async function ej(e){let t=new Map;for(;;){try{let r=await eR(e),n=new WebSocket(r.wsUrl);n.binaryType="arraybuffer",await ex(n,"Bridge"),n.addEventListener("message",r=>{(async()=>{let o=await eL(r);await eF(n,o,e,t)})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),await e$(n),t.forEach(e=>eB(e,1012,"bridge disconnected")),t.clear()}catch(e){console.error(e instanceof Error?e.message:String(e))}await f(1e3)}}async function eq(e,t){let r=function(e,t){if(e[0]!==eD)return null;let r=t[ek]?.trim(),n=t[eM]?.trim(),o=t[eT]?.trim();if(!r||!n||!o)throw Error("Metro companion worker is missing required environment configuration.");return{serverBaseUrl:r,bearerToken:n,localBaseUrl:o,launchUrl:t[eN]?.trim()||void 0}}(e,t);return!!r&&(await ej(r),!0)}function eG(e){return l("sha256").update(e).digest("hex")}function eV(e){return e?.trim()?e.trim():void 0}function eH(e,t){o.mkdirSync(a.dirname(e),{recursive:!0}),o.writeFileSync(e,`${JSON.stringify(t,null,2)}
|
|
4
|
-
`,"utf8")}function ez(e){return e.includes(eD)}function eK(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}async function eJ(e){if(!M(e.pid))return;let t=N(e.pid);if(t&&ez(t)){try{process.kill(e.pid,"SIGTERM")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}if(!await O(e.pid,1e3)){try{process.kill(e.pid,"SIGKILL")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}await O(e.pid,1e3)}}}async function eW(e){let t=eV(e.consumerKey)??eV(e.profileKey)??null,r=function(e,t){let r=a.join(e,".agent-device");if(!t)return{statePath:a.join(r,"metro-companion.json"),logPath:a.join(r,"metro-companion.log")};let n=eG(t).slice(0,12),o=a.join(r,"metro-companion");return{statePath:a.join(o,`metro-companion-${n}.json`),logPath:a.join(o,`metro-companion-${n}.log`)}}(e.projectRoot,e.profileKey),n=function(e){try{let t=JSON.parse(o.readFileSync(e,"utf8"));if(!Number.isInteger(t.pid)||0>=Number(t.pid)||"string"!=typeof t.serverBaseUrl||"string"!=typeof t.localBaseUrl||"string"!=typeof t.tokenHash||0===t.tokenHash.length)return null;let r=Array.isArray(t.consumers)?t.consumers.filter(e=>"string"==typeof e&&e.length>0):[];return{pid:Number(t.pid),startTime:"string"==typeof t.startTime?t.startTime:void 0,command:"string"==typeof t.command?t.command:void 0,serverBaseUrl:t.serverBaseUrl,localBaseUrl:t.localBaseUrl,launchUrl:eV("string"==typeof t.launchUrl?t.launchUrl:void 0),tokenHash:t.tokenHash,consumers:r}}catch{return null}}(r.statePath);if(n&&function(e,t){if(!M(e.pid))return!1;if(e.startTime){let t=T(e.pid);if(!t||t!==e.startTime)return!1}let r=N(e.pid);return!!r&&!!ez(r)&&e.serverBaseUrl===eU(t.serverBaseUrl)&&e.localBaseUrl===eU(t.localBaseUrl)&&e.launchUrl===eV(t.launchUrl)&&e.tokenHash===eG(t.bearerToken)}(n,e)){let e=eK(n,t);return e!==n&&eH(r.statePath,e),{pid:n.pid,spawned:!1,statePath:r.statePath,logPath:r.logPath}}if(n){await eJ(n);var i=r.statePath;try{o.unlinkSync(i)}catch{}}let s=function(e,t){let r=m(import.meta.url),n=r.endsWith(".ts")?["--experimental-strip-types"]:[];o.mkdirSync(a.dirname(t),{recursive:!0});let i=o.openSync(t,"a"),s=0;try{let t;s=A(process.execPath,[...n,r,eD],{env:(t={...e.env??process.env,[ek]:eU(e.serverBaseUrl),[eM]:e.bearerToken,[eT]:eU(e.localBaseUrl)},e.launchUrl?.trim()?t[eN]=e.launchUrl.trim():delete t[eN],t),stdio:["ignore",i,i]})}finally{o.closeSync(i)}if(!Number.isInteger(s)||s<=0)throw Error("Failed to start Metro companion process.");return{pid:s,startTime:T(s)??void 0,command:N(s)??void 0,serverBaseUrl:eU(e.serverBaseUrl),localBaseUrl:eU(e.localBaseUrl),launchUrl:eV(e.launchUrl),tokenHash:eG(e.bearerToken),consumers:[]}}(e,r.logPath);return eH(r.statePath,eK(s,t)),{pid:s.pid,spawned:!0,statePath:r.statePath,logPath:r.logPath}}function eZ(e){return"string"==typeof e&&e.trim()?eU(e.trim()):""}function eX(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function eY(e,t,r){return $(e,{env:t,cwd:r})}function eQ(e){try{return o.accessSync(e,o.constants.F_OK),!0}catch{return!1}}function e0(e,t,r){if(null==e||""===e)return t;let n=Number.parseInt(String(e),10);return Number.isInteger(n)?Math.max(n,r):t}function e1(e,t){let r;return{platform:t,bundleUrl:((r=new URL(`${eU(e)}/index.bundle`)).searchParams.set("platform",t),r.searchParams.set("dev","true"),r.searchParams.set("minify","false"),r.toString())}}function e3(e,t){return{platform:t,metroHost:eX(e?.metro_host),metroPort:e?.metro_port,bundleUrl:eX(e?.metro_bundle_url),launchUrl:eX(e?.launch_url)}}async function e4(e){await new Promise(t=>setTimeout(t,e))}async function e5(e,t,r={}){try{let n=await fetch(e,{headers:r,signal:AbortSignal.timeout(t)});return{ok:n.ok,status:n.status,body:await n.text()}}catch(r){if(r instanceof Error&&"TimeoutError"===r.name)throw Error(`Timed out fetching ${e} after ${t}ms`);throw r}}async function e8(e,t){try{let r=await e5(e,t);return r.ok&&r.body.includes("packager-status:running")}catch{return!1}}function e2(e,t){let r=Error(e);return r.retryable=t,r}async function e6(e){var t,r,n,o;let a;try{a=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:"POST",headers:(t=e.baseUrl,r=e.bearerToken,{Authorization:`Bearer ${r}`,"Content-Type":"application/json",...t.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}),body:JSON.stringify({ios_runtime:e.runtime,timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){if(t instanceof Error&&"TimeoutError"===t.name)throw e2(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0);throw e2(t instanceof Error?t.message:String(t),!0)}let i=await a.text(),s=i?JSON.parse(i):{};if(!a.ok)throw e2(`/api/metro/bridge failed (${a.status}): ${JSON.stringify(s)}`,(n=a.status,!!(n>=500||408===n||425===n||429===n||JSON.stringify(s).includes("Metro companion is not connected"))));return{enabled:(o=s.data??s).enabled,baseUrl:o.base_url,statusUrl:o.status_url,bundleUrl:o.bundle_url,iosRuntime:e3(o.ios_runtime,"ios"),androidRuntime:e3(o.android_runtime,"android"),upstream:{bundleUrl:o.upstream.bundle_url,host:o.upstream.host,port:o.upstream.port,statusUrl:o.upstream.status_url},probe:{reachable:o.probe.reachable,statusCode:o.probe.status_code,latencyMs:o.probe.latency_ms,detail:o.probe.detail}}}function e7(e,t,r,n,o){let a=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&a.push(`bridgeError=${t}`),r?.probe.reachable===!1&&a.push(`bridgeProbe=${r.probe.detail||`unreachable (status ${r.probe.statusCode||0})`}`),n&&n!==t&&a.push(`initialBridgeError=${n}`),o&&a.push(`metroCompanionLog=${o}`),a.join(" ")}async function e9(e,t,r){let n=Date.now()+t;for(;Date.now()<n;){let t=Math.min(r,Math.max(n-Date.now(),1));if(await e8(e,t))return!0;let o=Math.min(500,Math.max(n-Date.now(),0));o>0&&await e4(o)}return!1}async function te(e){let t=Date.now()+e.startupTimeoutMs,r=null,n=null;for(;Date.now()<t;){try{let t=await e6({baseUrl:e.baseUrl,bearerToken:e.bearerToken,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(!1!==t.probe.reachable)return t;r=t,n=null}catch(e){if(n=e instanceof Error?e.message:String(e),!(e&&"object"==typeof e&&"retryable"in e&&!0===e.retryable))break}let o=Math.min(1e3,Math.max(t-Date.now(),0));o>0&&await e4(o)}throw Error(e7(e.baseUrl,n,r,e.initialBridgeError,e.companionLogPath))}async function tt(e={}){let t=e.env??process.env,r=process.cwd(),n=eY(e.projectRoot??r,t,r),i=function(e,t){if("auto"!==t)return t;let r=function(e){let t=a.join(e,"package.json");if(!eQ(t))throw new I("INVALID_ARGS",`package.json not found at ${t}`);return JSON.parse(o.readFileSync(t,"utf8"))}(e);return"string"==typeof({...r.dependencies??{},...r.devDependencies??{}}).expo?"expo":"react-native"}(n,e.kind??"auto"),s=function(e){if(null==e||""===e)return 8081;let t=Number.parseInt(String(e),10);if(!Number.isInteger(t)||t<1||t>65535)throw new I("INVALID_ARGS",`Invalid Metro port: ${String(e)}. Use 1-65535.`);return t}(e.metroPort??8081),l=eX(e.listenHost)??"0.0.0.0",u=eX(e.statusHost)??"127.0.0.1",c=eZ(e.publicBaseUrl),d=e0(e.startupTimeoutMs,18e4,3e4),m=e0(e.probeTimeoutMs,1e4,1e3),p=e.reuseExisting??!0,f=e.installDependenciesIfNeeded??!0,h=e.runtimeFilePath?eY(e.runtimeFilePath,t,r):null,y=eY(e.logPath??a.join(n,".agent-device","metro.log"),t,r);if(!c)throw new I("INVALID_ARGS","metro prepare requires --public-base-url <url>.");let{proxyEnabled:g,proxyBaseUrl:w,proxyBearerToken:v}=function(e,t){if(e&&!t)throw new I("INVALID_ARGS","metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_PROXY_TOKEN.");if(!e&&t)throw new I("INVALID_ARGS","metro prepare requires --proxy-base-url when proxy auth is provided.");return{proxyEnabled:!!(e&&t),proxyBaseUrl:e,proxyBearerToken:t}}(eZ(e.proxyBaseUrl),eX(e.proxyBearerToken)??""),b=f?function(e,t){if(function(e){try{return o.statSync(e).isDirectory()}catch{return!1}}(a.join(e,"node_modules")))return{installed:!1};let r=eQ(a.join(e,"pnpm-lock.yaml"))?{command:"pnpm",installArgs:["install"]}:eQ(a.join(e,"yarn.lock"))?{command:"yarn",installArgs:["install"]}:{command:"npm",installArgs:["install"]};return S(r.command,r.installArgs,{cwd:e,env:t}),{installed:!0,packageManager:r.command}}(n,t):{installed:!1},E=`http://${u}:${s}/status`,_=!1,P=!1,D=0;if(p&&await e8(E,m))P=!0;else if(_=!0,D=function(e,t,r,n,i,s){let l="expo"===t?{command:"npx",installArgs:["expo","start","--host","lan","--port",String(r)]}:{command:"npx",installArgs:["react-native","start","--host",n,"--port",String(r)]};o.mkdirSync(a.dirname(i),{recursive:!0});let u=o.openSync(i,"a"),c=0;try{c=A(l.command,l.installArgs,{cwd:e,env:s,stdio:["ignore",u,u]})}finally{o.closeSync(u)}if(!Number.isInteger(c)||c<=0)throw Error("Failed to start Metro. Expected a detached child PID.");return{pid:c}}(n,i,s,l,y,t).pid,!await e9(E,d,m))throw Error(`Metro did not become ready at ${E} within ${d}ms. Check ${y}.`);let k=e1(c,"ios"),M=e1(c,"android"),T=null,N=null;if(g)try{T=await e6({baseUrl:w,bearerToken:v,runtime:{metro_bundle_url:k.bundleUrl},timeoutMs:m})}catch(e){N=e instanceof Error?e.message:String(e)}if(g&&(!T||!1===T.probe.reachable)){let r;try{r=(await eW({projectRoot:n,serverBaseUrl:w,bearerToken:v,localBaseUrl:`http://${u}:${s}`,launchUrl:eX(e.launchUrl),profileKey:eX(e.companionProfileKey),consumerKey:eX(e.companionConsumerKey),env:t})).logPath}catch(e){throw Error(e7(w,e instanceof Error?e.message:String(e),T,N))}try{T=await te({baseUrl:w,bearerToken:v,runtime:{metro_bundle_url:k.bundleUrl},probeTimeoutMs:m,startupTimeoutMs:d,initialBridgeError:N,companionLogPath:r})}catch(e){throw e instanceof Error?e:Error(String(e))}}let U=T?.iosRuntime??k,R=T?.androidRuntime??M,O={projectRoot:n,kind:i,dependenciesInstalled:b.installed,packageManager:b.packageManager??null,started:_,reused:P,pid:D,logPath:y,statusUrl:E,runtimeFilePath:h,iosRuntime:U,androidRuntime:R,bridge:T};return h&&(o.mkdirSync(a.dirname(h),{recursive:!0}),o.writeFileSync(h,JSON.stringify(O,null,2))),O}function tr(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function tn(e,t,r){return{deviceId:t,deviceName:r,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function to(e,t,r,n){let o=r(e[t]);if(void 0===o)throw new I("COMMAND_FAILED",n,{response:e});return o}(e=process.argv[1])&&p(a.resolve(e)).href===import.meta.url&&eq(process.argv.slice(2),process.env).catch(e=>{if(e instanceof Error&&e.message.includes("missing required environment")){console.error(e.message),process.exitCode=1;return}console.error(e instanceof Error?e.stack??e.message:String(e)),process.exitCode=1});function ta(e,t){return to(e,t,td,`Daemon response is missing "${t}".`)}function ti(e,t){return td(e[t])}function ts(e,t){var r;let n;return r=td,null===(n=e[t])?null:r(n)}function tl(e,t){return to(e,t,tp,`Daemon response has invalid "${t}".`)}function tu(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function tc(e,t){let r=e[t];if(!ty(r))return;let n="number"==typeof r.x?r.x:void 0,o="number"==typeof r.y?r.y:void 0,a="number"==typeof r.width?r.width:void 0,i="number"==typeof r.height?r.height:void 0;if(void 0!==n&&void 0!==o&&void 0!==a&&void 0!==i)return{x:n,y:o,width:a,height:i}}function td(e){return"string"==typeof e&&e.length>0?e:void 0}function tm(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function tp(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function tf(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function th(e){if(!ty(e))throw new I("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function ty(e){return"object"==typeof e&&null!==e}function tg(e){let t={};for(let[r,n]of Object.entries(e))void 0!==n&&(t[r]=n);return t}function tw(e,t){let r=ti(e,"bundleId"),n=ti(e,"package");return{app:ta(e,"app"),appPath:ta(e,"appPath"),platform:tl(e,"platform"),appId:r??n,bundleId:r,package:n,identifiers:tr({session:t,bundleId:r,packageName:n})}}function tv(e){let t=th(e),r=tl(t,"platform"),n=ta(t,"id"),o=ta(t,"name");return{platform:r,target:tu(t,"target"),kind:to(t,"kind",tf,'Daemon response has invalid "kind".'),id:n,name:o,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:tn(r,n,o),ios:"ios"===r?{udid:n}:void 0,android:"android"===r?{serial:n}:void 0}}function tb(e){let t=th(e),r=tl(t,"platform"),n=ta(t,"id"),o=ta(t,"name"),a=tu(t,"target"),i=ta(t,"device"),s={session:o,...tn(r,n,i)};return{name:o,createdAt:to(t,"createdAt",tm,'Daemon response is missing numeric "createdAt".'),device:{platform:r,target:a,id:n,name:i,identifiers:s,ios:"ios"===r?{udid:n,simulatorSetPath:ts(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:n}:void 0},identifiers:s}}function tI(e,t){return t??e??"default"}function tE(e={},t={}){let r=t.transport??X,n=async(t,n=[],o={})=>{let a={...e,...o},i=await r({session:tI(e.session,o.session),command:t,positionals:n,flags:tg({stateDir:a.stateDir,daemonBaseUrl:a.daemonBaseUrl,daemonAuthToken:a.daemonAuthToken,daemonTransport:a.daemonTransport,daemonServerMode:a.daemonServerMode,tenant:a.tenant,sessionIsolation:a.sessionIsolation,runId:a.runId,leaseId:a.leaseId,platform:a.platform,target:a.target,device:a.device,udid:a.udid,serial:a.serial,iosSimulatorDeviceSet:a.iosSimulatorDeviceSet,androidDeviceAllowlist:a.androidDeviceAllowlist,runtime:a.simulatorRuntimeId,boot:a.boot,reuseExisting:a.reuseExisting,surface:a.surface,activity:a.activity,relaunch:a.relaunch,shutdown:a.shutdown,saveScript:a.saveScript,noRecord:a.noRecord,metroHost:a.metroHost,metroPort:a.metroPort,bundleUrl:a.bundleUrl,launchUrl:a.launchUrl,snapshotInteractiveOnly:a.interactiveOnly,snapshotCompact:a.compact,snapshotDepth:a.depth,snapshotScope:a.scope,snapshotRaw:a.raw,overlayRefs:a.overlayRefs,verbose:a.debug}),runtime:a.runtime,meta:tg({requestId:a.requestId,cwd:a.cwd,debug:a.debug,lockPolicy:a.lockPolicy,lockPlatform:a.lockPlatform,tenantId:a.tenant,runId:a.runId,leaseId:a.leaseId,sessionIsolation:a.sessionIsolation,installSource:a.installSource,retainMaterializedPaths:a.retainMaterializedPaths,materializedPathRetentionMs:a.materializedPathRetentionMs,materializationId:a.materializationId})});if(!i.ok)throw new I(i.error.code,i.error.message,{...i.error.details??{},hint:i.error.hint,diagnosticId:i.error.diagnosticId,logPath:i.error.logPath});return i.data??{}},o=async(e={})=>{let t=await n("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(tb)};return{devices:{list:async(e={})=>{let t=await n("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(tv)}},sessions:{list:async(e={})=>await o(e),close:async(t={})=>{let r=tI(e.session,t.session),o=(await n("close",[],t)).shutdown;return{session:r,shutdown:"object"==typeof o&&null!==o?o:void 0,identifiers:{session:r}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,o=await n("ensure-simulator",[],{...r,simulatorRuntimeId:t}),a=ta(o,"udid"),i=ta(o,"device");return{udid:a,device:i,runtime:ta(o,"runtime"),created:!0===o.created,booted:!0===o.booted,iosSimulatorDeviceSet:ts(o,"ios_simulator_device_set"),identifiers:{deviceId:a,deviceName:i,udid:a}}}},apps:{install:async t=>tw(await n("install",[t.app,t.appPath],t),tI(e.session,t.session)),reinstall:async t=>tw(await n("reinstall",[t.app,t.appPath],t),tI(e.session,t.session)),installFromSource:async t=>(function(e,t){let r=ti(e,"bundleId"),n=ti(e,"packageName"),o=r??n??ti(e,"appId"),a=ti(e,"launchTarget")??n??r??o;if(!a)throw new I("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:ti(e,"appName"),appId:o,bundleId:r,packageName:n,launchTarget:a,installablePath:ti(e,"installablePath"),archivePath:ti(e,"archivePath"),materializationId:ti(e,"materializationId"),materializationExpiresAt:ti(e,"materializationExpiresAt"),identifiers:tr({session:t,bundleId:r,packageName:n,appId:o})}})(await n("install_source",[],{...t,installSource:t.source,retainMaterializedPaths:t.retainPaths,materializedPathRetentionMs:t.retentionMs}),tI(e.session,t.session)),open:async t=>{let r=tI(e.session,t.session),o=t.url?[t.app,t.url]:[t.app],a=await n("open",o,t),i=function(e){let t=e.platform,r=ti(e,"id"),n=ti(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!r||!n)return;let o=tu(e,"target"),a=tn(t,r,n);return{platform:t,target:o,id:r,name:n,identifiers:a,ios:"ios"===t?{udid:ti(e,"device_udid")??r,simulatorSetPath:ts(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:ti(e,"serial")??r}:void 0}}(a),s=ti(a,"appBundleId");return{session:r,appName:ti(a,"appName"),appBundleId:s,appId:s,startup:function(e){if(ty(e)&&"number"==typeof e.durationMs&&"string"==typeof e.measuredAt&&"string"==typeof e.method)return{durationMs:e.durationMs,measuredAt:e.measuredAt,method:e.method,appTarget:ti(e,"appTarget"),appBundleId:ti(e,"appBundleId")}}(a.startup),runtime:function(e){if(!ty(e))return;let t=e.platform,r=ti(e,"metroHost"),n="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:n,bundleUrl:ti(e,"bundleUrl"),launchUrl:ti(e,"launchUrl")}}(a.runtime),device:i,identifiers:{session:r,deviceId:i?.id,deviceName:i?.name,udid:i?.ios?.udid,serial:i?.android?.serial,appId:s,appBundleId:s}}},close:async(t={})=>{let r=tI(e.session,t.session),o=(await n("close",t.app?[t.app]:[],t)).shutdown;return{session:r,closedApp:t.app,shutdown:"object"==typeof o&&null!==o?o:void 0,identifiers:{session:r}}}},materializations:{release:async e=>{var t;return{released:!0===(t=await n("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:ta(t,"materializationId"),identifiers:{}}}},metro:{prepare:async t=>await tt({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(t={})=>{var r;let o=tI(e.session,t.session),a=await n("snapshot",[],t),i=ti(a,"appBundleId"),s="object"==typeof a.visibility&&null!==a.visibility?a.visibility:void 0;return{nodes:Array.isArray(r=a.nodes)?r:[],truncated:!0===a.truncated,appName:ti(a,"appName"),appBundleId:i,...s?{visibility:s}:{},warnings:Array.isArray(a.warnings)?a.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:o,appId:i,appBundleId:i}}},screenshot:async(t={})=>{let r=tI(e.session,t.session),o=await n("screenshot",t.path?[t.path]:[],t);return{path:ta(o,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let r=[];for(let e of t){if(!ty(e))continue;let t=ti(e,"ref"),n=tc(e,"rect"),o=tc(e,"overlayRect"),a=function(e,t){let r=e[t];if(!ty(r))return;let n="number"==typeof r.x?r.x:void 0,o="number"==typeof r.y?r.y:void 0;if(void 0!==n&&void 0!==o)return{x:n,y:o}}(e,"center");t&&n&&o&&a&&r.push({ref:t,label:ti(e,"label"),rect:n,overlayRect:o,center:a})}return r}(o),identifiers:{session:r}}}}}}export{tE as createAgentDeviceClient,I as AppError};
|
|
1
|
+
import e from"node:net";import t from"node:http";import r from"node:https";import o from"node:fs";import n from"node:path";import{fileURLToPath as a}from"node:url";import{spawn as i}from"node:child_process";import s from"node:crypto";import{resolveUserPath as l,createRequestId as d,emitDiagnostic as u,withDiagnosticTimer as c,expandUserHomePath as p,AppError as m}from"./957.js";import{stopProcessForTakeover as f,prepareMetroRuntime as h,runCmdSync as I,isAgentDeviceDaemonProcess as v,runCmdDetached as y}from"./974.js";function w(){let e=n.dirname(a(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(o.existsSync(e))return t;t=n.dirname(t)}return e}function g(e){let t,r=(t=(e??"").trim())?l(t):n.join(p("~"),".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")}}async function A(e){let{localPath:a,baseUrl:s,token:l}=e,d=o.statSync(a).isDirectory(),u=n.basename(a),c=new URL("upload",s.endsWith("/")?s:`${s}/`),p="https:"===c.protocol?r:t,f={"x-artifact-type":d?"app-bundle":"file","x-artifact-filename":u,"transfer-encoding":"chunked"};return l&&(f.authorization=`Bearer ${l}`,f["x-agent-device-token"]=l),new Promise((e,t)=>{let r=p.request({protocol:c.protocol,host:c.hostname,port:c.port,method:"POST",path:c.pathname+c.search,headers:f},r=>{let o="";r.setEncoding("utf8"),r.on("data",e=>{o+=e}),r.on("end",()=>{clearTimeout(s);try{let r=JSON.parse(o);if(!r.ok||!r.uploadId)return void t(new m("COMMAND_FAILED",`Upload failed: ${o}`));e(r.uploadId)}catch{t(new m("COMMAND_FAILED",`Invalid upload response: ${o}`))}})}),s=setTimeout(()=>{r.destroy(),t(new m("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 m("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(a),n.basename(a)],{stdio:["ignore","pipe","pipe"]});e.stdout.pipe(r),e.on("error",e=>{r.destroy(),t(new m("COMMAND_FAILED","Failed to create tar archive for app bundle",{},e))}),e.on("close",e=>{0!==e&&(r.destroy(),t(new m("COMMAND_FAILED",`tar failed with exit code ${e}`)))})}else{let e=o.createReadStream(a);e.pipe(r),e.on("error",e=>{r.destroy(),t(new m("COMMAND_FAILED","Failed to read local artifact",{},e))})}})}let D=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,b=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,E=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function P(e,t,r){t.lastIndex=0;let o=null;for(;null!==(o=t.exec(e));){let e=o[1]?.trim();e?.startsWith(".")&&r.add(e)}}function _(e){try{return o.statSync(e).isFile()?e:null}catch{return null}}let S=es(),T=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}(),M=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}(),k=["xcodebuild .*AgentDeviceRunnerUITests/RunnerTests/testCommand","xcodebuild .*AgentDeviceRunner\\.env\\.session-","xcodebuild build-for-testing .*ios-runner/AgentDeviceRunner/AgentDeviceRunner\\.xcodeproj"],N=new e.BlockList;async function U(t){let r=t.meta?.requestId??d(),o=!!(t.meta?.debug||t.flags?.verbose),n=function(t){let r,o,n,a=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 m("INVALID_ARGS","Invalid daemon base URL",{daemonBaseUrl:e},t instanceof Error?t:void 0)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new m("INVALID_ARGS","Daemon base URL must use http or https",{daemonBaseUrl:e});return t.toString().replace(/\/+$/,"")}}(t.flags?.daemonBaseUrl??process.env.AGENT_DEVICE_DAEMON_BASE_URL),s=t.flags?.daemonAuthToken??process.env.AGENT_DEVICE_DAEMON_AUTH_TOKEN;var l=i,d=s;if(!(!l||"localhost"===(r=new URL(l).hostname.trim().toLowerCase().replace(/^\[(.*)\]$/,"$1"))||(e.isIPv4(r)?N.check(r,"ipv4"):!!e.isIPv6(r)&&N.check(r,"ipv6")))&&("string"!=typeof d||!(d.trim().length>0)))throw new m("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 u=t.flags?.daemonTransport??process.env.AGENT_DEVICE_DAEMON_TRANSPORT,c="auto"===(o=(u??"").trim().toLowerCase())?"auto":"socket"===o?"socket":"http"===o?"http":"auto";if(i&&"socket"===c)throw new m("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"===u?"dual":void 0)??"").trim().toLowerCase())?"http":"dual"===n?"dual":"socket";return{paths:g(a),transportPreference:c,serverMode:p,remoteBaseUrl:i,remoteAuthToken:s}}(t),a=function(e,t=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS){if("test"!==e)return es(t)}(t.command),i=await c("daemon_startup",async()=>await x(n),{requestId:r,session:t.session}),s=await R(t,i),l={...t,positionals:s.positionals,flags:s.flags,token:i.token,meta:{...t.meta??{},requestId:r,debug:o,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 c("daemon_request",async()=>await Q(i,l,n.transportPreference,a),{requestId:r,command:t.command})}async function R(e,t){let r,a=[...e.positionals??[]],i=e.flags?{...e.flags}:void 0,s=e.meta?.installSource,l={};if(eo(t)){let o=function(e,t){if("screenshot"===e.command){let r=O(e,"path",".png");return t[0]?{field:"path",localPath:r,positionalIndex:0,positionalPath:L("screenshot",".png")}:{field:"path",localPath:r,positionalIndex:0,flagPath:L("screenshot",".png")}}if("record"===e.command&&"start"===(t[0]??"").toLowerCase()){let t=O(e,"outPath",".mp4",1);return{field:"outPath",localPath:t,positionalIndex:1,positionalPath:L("recording",n.extname(t)||".mp4")}}return null}(e,a);o&&(void 0!==o.positionalPath&&(a[o.positionalIndex]=o.positionalPath),void 0!==o.flagPath&&((i??={}).out=o.flagPath),l[o.field]=o.localPath);let d=await C(e,t);d&&(s=d.installSource,r=d.uploadedArtifactId??r)}if(!eo(t)||"install"!==e.command&&"reinstall"!==e.command||a.length<2)return{positionals:a,flags:i,installSource:s,uploadedArtifactId:r,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let d=a[1];if(d.startsWith("remote:"))return a[1]=d.slice(7),{positionals:a,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}};let u=n.isAbsolute(d)?d:n.resolve(e.meta?.cwd??process.cwd(),d);return o.existsSync(u)?{positionals:a,flags:i,installSource:s,uploadedArtifactId:r=await A({localPath:u,baseUrl:t.baseUrl,token:t.token}),...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}:{positionals:a,flags:i,...Object.keys(l).length>0?{clientArtifactPaths:l}:{}}}async function C(e,t){let r=e.meta?.installSource;if("install_source"!==e.command||!r||"path"!==r.kind)return null;let a=r.path.trim();if(!a)return{installSource:r};if(a.startsWith("remote:"))return{installSource:{...r,path:a.slice(7)}};let i=n.isAbsolute(a)?a:n.resolve(e.meta?.cwd??process.cwd(),a);if(!o.existsSync(i))return{installSource:{...r,path:i}};let s=await A({localPath:i,baseUrl:t.baseUrl,token:t.token});return{installSource:{...r,path:i},uploadedArtifactId:s}}function O(e,t,r,o=0){let a=e.positionals?.[o]??e.flags?.out,i=`${"path"===t?"screenshot":"recording"}-${Date.now()}${r}`,s=a&&a.trim().length>0?a:i;return n.isAbsolute(s)?s:n.resolve(e.meta?.cwd??process.cwd(),s)}function L(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 x(e){let t;if(e.remoteBaseUrl){let t={transport:"http",token:e.remoteAuthToken??"",pid:0,baseUrl:e.remoteBaseUrl};if(await K(t,"http"))return t;throw new m("COMMAND_FAILED","Remote daemon is unavailable",{daemonBaseUrl:e.remoteBaseUrl,hint:"Verify AGENT_DEVICE_DAEMON_BASE_URL points to a reachable daemon with GET /health and POST /rpc."})}let r=B(e.paths.infoPath),a=function(){try{let e=w();return JSON.parse(o.readFileSync(n.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),i=function(e,t=w()){try{let r=n.resolve(t),a=[n.resolve(e)],i=new Set,l=[];for(;a.length>0;){let e=a.pop();if(!e||i.has(e))continue;i.add(e);let t=o.statSync(e);if(!t.isFile())continue;let s=n.relative(r,e)||e;l.push(`${s}:${t.size}:${Math.trunc(t.mtimeMs)}`);let d=o.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return P(e,D,t),P(e,b,t),[...t]}(d)){let r=function(e,t){let r=n.resolve(n.dirname(e),t),o=_(r);if(o)return o;for(let e of E){let t=_(`${r}${e}`);if(t)return t}for(let e of E){let t=_(n.join(r,`index${e}`));if(t)return t}return null}(e,t);r&&a.push(r)}}let d=l.sort().join("|"),u=s.createHash("sha1").update(d).digest("hex");return`graph:${l.length}:${u}`}catch{return"unknown"}}((t=J()).useSrc?t.srcPath:t.distPath,t.root),l=!!r&&await K(r,e.transportPreference);if(r&&r.version===a&&r.codeSignature===i&&l)return r;r&&(r.version!==a||r.codeSignature!==i||!l)&&(await q(r),H(e.paths.infoPath)),function(e){let t=V(e);if(!t.hasLock||t.hasInfo)return;let r=G(e.lockPath);if(!r)return H(e.lockPath);v(r.pid,r.processStartTime)||H(e.lockPath)}(e.paths);let d=0;for(let t=1;t<=M;t+=1){await W(e);let r=await F(T,e);if(r)return r;if(await j(e.paths)){d+=1;continue}let o=V(e.paths);if(!(t<M))break;if(!o.hasInfo&&!o.hasLock){await $(150);continue}}let u=V(e.paths);throw new m("COMMAND_FAILED","Failed to start daemon",{kind:"daemon_startup_failed",infoPath:e.paths.infoPath,lockPath:e.paths.lockPath,startupTimeoutMs:T,startupAttempts:M,lockRecoveryCount:d,metadataState:u,hint:function(e,t=g(process.env.AGENT_DEVICE_STATE_DIR)){return e.hasLock&&!e.hasInfo?`Detected ${t.lockPath} without ${t.infoPath}. If no agent-device daemon process is running, delete ${t.lockPath} and retry.`:e.hasLock&&e.hasInfo?`Daemon metadata may be stale. If no agent-device daemon process is running, delete ${t.infoPath} and ${t.lockPath}, then retry.`:`Daemon metadata is missing or stale. Delete ${t.infoPath} if present and retry.`}(u,e.paths)})}async function F(e,t){let r=Date.now();for(;Date.now()-r<e;){let e=B(t.paths.infoPath);if(e&&await K(e,t.transportPreference))return e;await new Promise(e=>setTimeout(e,100))}return null}async function $(e){await new Promise(t=>setTimeout(t,e))}async function j(e){let t=V(e);if(!t.hasLock||t.hasInfo)return!1;let r=G(e.lockPath);return r&&v(r.pid,r.processStartTime)&&await f(r.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:r.processStartTime}),H(e.lockPath),!0}async function q(e){await f(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}function B(e){let t=z(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 o=Number.isInteger(t.port)&&Number(t.port)>0,n=Number.isInteger(t.httpPort)&&Number(t.httpPort)>0;if(!o&&!n)return null;let a=t.transport,i="string"==typeof t.version?t.version:void 0,s="string"==typeof t.codeSignature?t.codeSignature:void 0,l="string"==typeof t.processStartTime?t.processStartTime:void 0,d=Number.isInteger(t.pid)&&Number(t.pid)>0;return{token:r,port:o?Number(t.port):void 0,httpPort:n?Number(t.httpPort):void 0,transport:"socket"===a||"http"===a||"dual"===a?a:void 0,pid:d?Number(t.pid):0,version:i,codeSignature:s,processStartTime:l}}function G(e){let t=z(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}N.addSubnet("127.0.0.0",8,"ipv4"),N.addAddress("::1","ipv6"),N.addSubnet("::ffff:127.0.0.0",104,"ipv6");function V(e){return{hasInfo:o.existsSync(e.infoPath),hasLock:o.existsSync(e.lockPath)}}function z(e){if(!o.existsSync(e))return null;try{return JSON.parse(o.readFileSync(e,"utf8"))}catch{return null}}function H(e){try{o.existsSync(e)&&o.unlinkSync(e)}catch{}}async function K(o,n){var a;return"http"===X(o,n)?await function(e){let o=e.baseUrl?en(e.baseUrl,"health"):e.httpPort?`http://127.0.0.1:${e.httpPort}/health`:null;if(!o)return Promise.resolve(!1);let n=new URL(o),a="https:"===n.protocol?r:t,i=e.baseUrl?3e3:500;return new Promise(e=>{let t=a.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()})}(o):await ((a=o.port)?new Promise(t=>{let r=e.createConnection({host:"127.0.0.1",port:a},()=>{r.destroy(),t(!0)});r.on("error",()=>{t(!1)})}):Promise.resolve(!1))}async function W(e){let t=J(),r=t.useSrc?["--experimental-strip-types",t.srcPath]:[t.distPath],o={...process.env,AGENT_DEVICE_STATE_DIR:e.paths.baseDir,AGENT_DEVICE_DAEMON_SERVER_MODE:e.serverMode};y(process.execPath,r,{env:o})}function J(){let e=w(),t=n.join(e,"dist","src","daemon.js"),r=n.join(e,"src","daemon.ts"),a=o.existsSync(t),i=o.existsSync(r);if(!a&&!i)throw new m("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:!a&&i}}async function Q(e,t,r,o){return"http"===X(e,r)?await er(e,t,o):await et(e,t,o)}function X(e,t){if(e.baseUrl){if("socket"===t)throw new m("COMMAND_FAILED","Remote daemon endpoint only supports HTTP transport",{daemonBaseUrl:e.baseUrl});return"http"}if("http"===t||"socket"===t){var r=e,o=t;if(Y(r,o))return o;throw new m("COMMAND_FAILED","http"===o?"Daemon HTTP endpoint is unavailable":"Daemon socket endpoint is unavailable")}let n=("socket"===e.transport||"dual"===e.transport?["socket","http"]:["http","socket"]).find(t=>Y(e,t));if(n)return n;throw new m("COMMAND_FAILED","Daemon metadata has no reachable transport")}function Y(e,t){return"http"===t?!!e.httpPort:!!e.port}function Z(e,t,r,o,n,a){let i=n?{terminated:0}:function(){let e=0;try{for(let t of k){let r=I("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{f(e.pid,{termTimeoutMs:3e3,killTimeoutMs:1e3,expectedStartTime:e.processStartTime})}finally{H(t.infoPath),H(t.lockPath)}return{forcedKill:r}}(e,t);return u({level:"error",phase:"daemon_request_timeout",data:{timeoutMs:a,requestId:r,command:o,timedOutRunnerPidsTerminated:i.terminated,timedOutRunnerCleanupError:i.error,daemonPidReset:n?void 0:e.pid,daemonPidForceKilled:n?void 0:s.forcedKill,daemonBaseUrl:e.baseUrl}}),new m("COMMAND_FAILED","Daemon request timed out",{timeoutMs:a,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 ee(e,t,r){return u({level:"error",phase:"daemon_request_socket_error",data:{requestId:t,message:e instanceof Error?e.message:String(e)}}),new m("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 et(t,r,o){let n=t.port;if(!n)throw new m("COMMAND_FAILED","Daemon socket endpoint is unavailable");return new Promise((a,i)=>{let s=e.createConnection({host:"127.0.0.1",port:n},()=>{s.write(`${JSON.stringify(r)}
|
|
2
|
+
`)}),l=g(r.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),d="number"==typeof o?setTimeout(()=>{s.destroy(),i(Z(t,l,r.meta?.requestId,r.command,!1,o))},o):void 0,u="";s.setEncoding("utf8"),s.on("data",e=>{let t=(u+=e).indexOf("\n");if(-1===t)return;let o=u.slice(0,t).trim();if(o)try{let e=JSON.parse(o);s.end(),d&&clearTimeout(d),a(e)}catch(e){d&&clearTimeout(d),i(new m("COMMAND_FAILED","Invalid daemon response",{requestId:r.meta?.requestId,line:o},e instanceof Error?e:void 0))}}),s.on("error",e=>{d&&clearTimeout(d),i(ee(e,r.meta?.requestId,!1))})})}async function er(e,o,n){let a=e.baseUrl?new URL(en(e.baseUrl,"rpc")):e.httpPort?new URL(`http://127.0.0.1:${e.httpPort}/rpc`):null;if(!a)throw new m("COMMAND_FAILED","Daemon HTTP endpoint is unavailable");let i=JSON.stringify({jsonrpc:"2.0",id:o.meta?.requestId??d(),method:"agent_device.command",params:o}),s={"content-type":"application/json","content-length":Buffer.byteLength(i)};return e.baseUrl&&e.token&&(s.authorization=`Bearer ${e.token}`,s["x-agent-device-token"]=e.token),await new Promise((l,d)=>{let u=g(o.flags?.stateDir??process.env.AGENT_DEVICE_STATE_DIR),c=("https:"===a.protocol?r:t).request({protocol:a.protocol,host:a.hostname,port:a.port,method:"POST",path:a.pathname+a.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??{};d(new m(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:o.meta?.requestId}));return}if(!t.result||"object"!=typeof t.result)return void d(new m("COMMAND_FAILED","Invalid daemon RPC response",{requestId:o.meta?.requestId}));if(e.baseUrl&&t.result.ok)return void ea(e,o,t.result).then(l).catch(d);l(t.result)}catch(e){f&&clearTimeout(f),d(new m("COMMAND_FAILED","Invalid daemon response",{requestId:o.meta?.requestId,line:r},e instanceof Error?e:void 0))}})}),p=eo(e),f="number"==typeof n?setTimeout(()=>{c.destroy(),d(Z(e,u,o.meta?.requestId,o.command,p,n))},n):void 0;c.on("error",e=>{f&&clearTimeout(f),d(ee(e,o.meta?.requestId,p))}),c.write(i),c.end()})}function eo(e){return"string"==typeof e.baseUrl&&e.baseUrl.length>0}function en(e,t){return new URL(t,e.endsWith("/")?e:`${e}/`).toString()}async function ea(e,t,r){let o=Array.isArray(r.data?.artifacts)?r.data.artifacts:[];if(0===o.length||!e.baseUrl)return r;let a=r.data?{...r.data}:{},i=[];for(let r of o){if(!r||"object"!=typeof r||"string"!=typeof r.artifactId){i.push(r);continue}let o=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 ei({baseUrl:e.baseUrl,token:e.token,artifactId:r.artifactId,destinationPath:o,requestId:t.meta?.requestId}),a[r.field]=o,i.push({...r,localPath:o})}return a.artifacts=i,{ok:!0,data:a}}async function ei(e){var a,i;let s,l=new URL((a=e.baseUrl,i=e.artifactId,s=a.endsWith("/")?a:`${a}/`,new URL(`upload/${encodeURIComponent(i)}`,s).toString())),d="https:"===l.protocol?r:t;await o.promises.mkdir(n.dirname(e.destinationPath),{recursive:!0}),await new Promise((t,r)=>{let n=!1,a=e.timeoutMs??S,i=a=>{if(!n){if(n=!0,clearTimeout(u),a)return void o.promises.rm(e.destinationPath,{force:!0}).finally(()=>r(a));t()}},s=d.request({protocol:l.protocol,host:l.hostname,port:l.port,method:"GET",path:l.pathname+l.search,headers:e.token?{authorization:`Bearer ${e.token}`,"x-agent-device-token":e.token}:void 0},t=>{if((t.statusCode??500)>=400){let r="";t.setEncoding("utf8"),t.on("data",e=>{r+=e}),t.on("end",()=>{i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,statusCode:t.statusCode,requestId:e.requestId,body:r}))});return}let r=o.createWriteStream(e.destinationPath);r.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("error",e=>{i(e instanceof Error?e:Error(String(e)))}),t.on("aborted",()=>{i(new m("COMMAND_FAILED","Remote artifact download was interrupted",{artifactId:e.artifactId,requestId:e.requestId}))}),r.on("finish",()=>{r.close(()=>i())}),t.pipe(r)}),u=setTimeout(()=>{s.destroy(new m("COMMAND_FAILED","Remote artifact download timed out",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:a}))},a);s.on("error",t=>{t instanceof m?i(t):i(new m("COMMAND_FAILED","Failed to download remote artifact",{artifactId:e.artifactId,requestId:e.requestId,timeoutMs:a},t instanceof Error?t:void 0))}),s.end()})}function es(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}function el(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function ed(e,t,r){return{deviceId:t,deviceName:r,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function eu(e,t,r,o){let n=r(e[t]);if(void 0===n)throw new m("COMMAND_FAILED",o,{response:e});return n}function ec(e,t){return eu(e,t,ev,`Daemon response is missing "${t}".`)}function ep(e,t){return ev(e[t])}function em(e,t){var r;let o;return r=ev,null===(o=e[t])?null:r(o)}function ef(e,t){return eu(e,t,ew,`Daemon response has invalid "${t}".`)}function eh(e,t){return function(e){return"tv"===e||"mobile"===e||"desktop"===e?e:void 0}(e[t])??"mobile"}function eI(e,t){let r=e[t];if(!eD(r))return;let o="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0,a="number"==typeof r.width?r.width:void 0,i="number"==typeof r.height?r.height:void 0;if(void 0!==o&&void 0!==n&&void 0!==a&&void 0!==i)return{x:o,y:n,width:a,height:i}}function ev(e){return"string"==typeof e&&e.length>0?e:void 0}function ey(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function ew(e){return"ios"===e||"macos"===e||"android"===e?e:void 0}function eg(e){return"simulator"===e||"emulator"===e||"device"===e?e:void 0}function eA(e){if(!eD(e))throw new m("COMMAND_FAILED","Daemon returned an unexpected response shape.",{value:e});return e}function eD(e){return"object"==typeof e&&null!==e}function eb(e){let t={};for(let[r,o]of Object.entries(e))void 0!==o&&(t[r]=o);return t}function eE(e,t){let r=ep(e,"bundleId"),o=ep(e,"package");return{app:ec(e,"app"),appPath:ec(e,"appPath"),platform:ef(e,"platform"),appId:r??o,bundleId:r,package:o,identifiers:el({session:t,bundleId:r,packageName:o})}}function eP(e){let t=eA(e),r=ef(t,"platform"),o=ec(t,"id"),n=ec(t,"name");return{platform:r,target:eh(t,"target"),kind:eu(t,"kind",eg,'Daemon response has invalid "kind".'),id:o,name:n,booted:"boolean"==typeof t.booted?t.booted:void 0,identifiers:ed(r,o,n),ios:"ios"===r?{udid:o}:void 0,android:"android"===r?{serial:o}:void 0}}function e_(e){let t=eA(e),r=ef(t,"platform"),o=ec(t,"id"),n=ec(t,"name"),a=eh(t,"target"),i=ec(t,"device"),s={session:n,...ed(r,o,i)};return{name:n,createdAt:eu(t,"createdAt",ey,'Daemon response is missing numeric "createdAt".'),device:{platform:r,target:a,id:o,name:i,identifiers:s,ios:"ios"===r?{udid:o,simulatorSetPath:em(t,"ios_simulator_device_set")}:void 0,android:"android"===r?{serial:o}:void 0},identifiers:s}}function eS(e,t){return t??e??"default"}function eT(e={},t={}){let r=t.transport??U,o=async(t,o=[],n={})=>{let a={...e,...n},i=await r({session:eS(e.session,n.session),command:t,positionals:o,flags:eb({stateDir:a.stateDir,daemonBaseUrl:a.daemonBaseUrl,daemonAuthToken:a.daemonAuthToken,daemonTransport:a.daemonTransport,daemonServerMode:a.daemonServerMode,tenant:a.tenant,sessionIsolation:a.sessionIsolation,runId:a.runId,leaseId:a.leaseId,platform:a.platform,target:a.target,device:a.device,udid:a.udid,serial:a.serial,iosSimulatorDeviceSet:a.iosSimulatorDeviceSet,androidDeviceAllowlist:a.androidDeviceAllowlist,runtime:a.simulatorRuntimeId,boot:a.boot,reuseExisting:a.reuseExisting,surface:a.surface,activity:a.activity,relaunch:a.relaunch,shutdown:a.shutdown,saveScript:a.saveScript,noRecord:a.noRecord,metroHost:a.metroHost,metroPort:a.metroPort,bundleUrl:a.bundleUrl,launchUrl:a.launchUrl,snapshotInteractiveOnly:a.interactiveOnly,snapshotCompact:a.compact,snapshotDepth:a.depth,snapshotScope:a.scope,snapshotRaw:a.raw,overlayRefs:a.overlayRefs,verbose:a.debug}),runtime:a.runtime,meta:eb({requestId:a.requestId,cwd:a.cwd,debug:a.debug,lockPolicy:a.lockPolicy,lockPlatform:a.lockPlatform,tenantId:a.tenant,runId:a.runId,leaseId:a.leaseId,sessionIsolation:a.sessionIsolation,installSource:a.installSource,retainMaterializedPaths:a.retainMaterializedPaths,materializedPathRetentionMs:a.materializedPathRetentionMs,materializationId:a.materializationId})});if(!i.ok)throw new m(i.error.code,i.error.message,{...i.error.details??{},hint:i.error.hint,diagnosticId:i.error.diagnosticId,logPath:i.error.logPath});return i.data??{}},n=async(e={})=>{let t=await o("session_list",[],e);return(Array.isArray(t.sessions)?t.sessions:[]).map(e_)};return{devices:{list:async(e={})=>{let t=await o("devices",[],e);return(Array.isArray(t.devices)?t.devices:[]).map(eP)}},sessions:{list:async(e={})=>await n(e),close:async(t={})=>{let r=eS(e.session,t.session),n=(await o("close",[],t)).shutdown;return{session:r,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},simulators:{ensure:async e=>{let{runtime:t,...r}=e,n=await o("ensure-simulator",[],{...r,simulatorRuntimeId:t}),a=ec(n,"udid"),i=ec(n,"device");return{udid:a,device:i,runtime:ec(n,"runtime"),created:!0===n.created,booted:!0===n.booted,iosSimulatorDeviceSet:em(n,"ios_simulator_device_set"),identifiers:{deviceId:a,deviceName:i,udid:a}}}},apps:{install:async t=>eE(await o("install",[t.app,t.appPath],t),eS(e.session,t.session)),reinstall:async t=>eE(await o("reinstall",[t.app,t.appPath],t),eS(e.session,t.session)),installFromSource:async t=>(function(e,t){let r=ep(e,"bundleId"),o=ep(e,"packageName"),n=r??o??ep(e,"appId"),a=ep(e,"launchTarget")??o??r??n;if(!a)throw new m("COMMAND_FAILED",'Daemon response is missing "launchTarget".',{response:e});return{appName:ep(e,"appName"),appId:n,bundleId:r,packageName:o,launchTarget:a,installablePath:ep(e,"installablePath"),archivePath:ep(e,"archivePath"),materializationId:ep(e,"materializationId"),materializationExpiresAt:ep(e,"materializationExpiresAt"),identifiers:el({session:t,bundleId:r,packageName:o,appId:n})}})(await o("install_source",[],{...t,installSource:t.source,retainMaterializedPaths:t.retainPaths,materializedPathRetentionMs:t.retentionMs}),eS(e.session,t.session)),open:async t=>{let r=eS(e.session,t.session),n=t.url?[t.app,t.url]:[t.app],a=await o("open",n,t),i=function(e){let t=e.platform,r=ep(e,"id"),o=ep(e,"device");if("ios"!==t&&"macos"!==t&&"android"!==t||!r||!o)return;let n=eh(e,"target"),a=ed(t,r,o);return{platform:t,target:n,id:r,name:o,identifiers:a,ios:"ios"===t?{udid:ep(e,"device_udid")??r,simulatorSetPath:em(e,"ios_simulator_device_set")}:void 0,android:"android"===t?{serial:ep(e,"serial")??r}:void 0}}(a),s=ep(a,"appBundleId");return{session:r,appName:ep(a,"appName"),appBundleId:s,appId:s,startup:function(e){if(eD(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(!eD(e))return;let t=e.platform,r=ep(e,"metroHost"),o="number"==typeof e.metroPort?e.metroPort:void 0;return{platform:"ios"===t||"android"===t?t:void 0,metroHost:r,metroPort:o,bundleUrl:ep(e,"bundleUrl"),launchUrl:ep(e,"launchUrl")}}(a.runtime),device:i,identifiers:{session:r,deviceId:i?.id,deviceName:i?.name,udid:i?.ios?.udid,serial:i?.android?.serial,appId:s,appBundleId:s}}},close:async(t={})=>{let r=eS(e.session,t.session),n=(await o("close",t.app?[t.app]:[],t)).shutdown;return{session:r,closedApp:t.app,shutdown:"object"==typeof n&&null!==n?n:void 0,identifiers:{session:r}}}},materializations:{release:async e=>{var t;return{released:!0===(t=await o("release_materialized_paths",[],{...e,materializationId:e.materializationId})).released,materializationId:ec(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(t={})=>{var r;let n=eS(e.session,t.session),a=await o("snapshot",[],t),i=ep(a,"appBundleId"),s="object"==typeof a.visibility&&null!==a.visibility?a.visibility:void 0;return{nodes:Array.isArray(r=a.nodes)?r:[],truncated:!0===a.truncated,appName:ep(a,"appName"),appBundleId:i,...s?{visibility:s}:{},warnings:Array.isArray(a.warnings)?a.warnings.filter(e=>"string"==typeof e):void 0,identifiers:{session:n,appId:i,appBundleId:i}}},screenshot:async(t={})=>{let r=eS(e.session,t.session),n=await o("screenshot",t.path?[t.path]:[],t);return{path:ec(n,"path"),overlayRefs:function(e){let t=e.overlayRefs;if(!Array.isArray(t))return;let r=[];for(let e of t){if(!eD(e))continue;let t=ep(e,"ref"),o=eI(e,"rect"),n=eI(e,"overlayRect"),a=function(e,t){let r=e[t];if(!eD(r))return;let o="number"==typeof r.x?r.x:void 0,n="number"==typeof r.y?r.y:void 0;if(void 0!==o&&void 0!==n)return{x:o,y:n}}(e,"center");t&&o&&n&&a&&r.push({ref:t,label:ep(e,"label"),rect:o,overlayRect:n,center:a})}return r}(n),identifiers:{session:r}}}}}}export{AppError}from"./957.js";export{eT as createAgentDeviceClient};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setTimeout as e}from"node:timers/promises";import{normalizeBaseUrl as r,METRO_COMPANION_RUN_ARG as t,ENV_LAUNCH_URL as a,ENV_BEARER_TOKEN as s,ENV_SERVER_BASE_URL as n,ENV_LOCAL_BASE_URL as o}from"./320.js";async function i(e){var t,a;let s=await fetch(`${r(e.serverBaseUrl)}/api/metro/companion/register`,{method:"POST",headers:(t=e.serverBaseUrl,a=e.bearerToken,{authorization:`Bearer ${a}`,"content-type":"application/json",...t.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}),body:JSON.stringify({local_base_url:r(e.localBaseUrl),...e.launchUrl?{launch_url:e.launchUrl}:{}})}),n=await s.json();if(!s.ok||!0!==n.ok||"string"!=typeof n.data?.ws_url)throw Error(`Failed to register Metro companion: ${JSON.stringify(n)}`);return{wsUrl:n.data.ws_url}}async function c(e){return"string"==typeof e?Buffer.from(e,"utf8"):e instanceof ArrayBuffer?Buffer.from(e):ArrayBuffer.isView(e)?Buffer.from(e.buffer,e.byteOffset,e.byteLength):"u">typeof Blob&&e instanceof Blob?Buffer.from(await e.arrayBuffer()):Buffer.from(String(e),"utf8")}async function f(e){return JSON.parse((await c(e.data)).toString("utf8"))}function d(e,r){1===e.readyState&&e.send(JSON.stringify(r))}async function l(e,r){1!==e.readyState&&await new Promise((t,a)=>{let s=()=>{i(),t()},n=()=>{i(),a(Error(`${r} WebSocket failed before opening.`))},o=()=>{i(),a(Error(`${r} WebSocket closed before opening.`))},i=()=>{e.removeEventListener("open",s),e.removeEventListener("error",n),e.removeEventListener("close",o)};e.addEventListener("open",s,{once:!0}),e.addEventListener("error",n,{once:!0}),e.addEventListener("close",o,{once:!0})})}async function u(e){e.readyState>=WebSocket.CLOSING||await new Promise(r=>{let t=()=>{a(),r()},a=()=>{e.removeEventListener("close",t),e.removeEventListener("error",t)};e.addEventListener("close",t,{once:!0}),e.addEventListener("error",t,{once:!0}),e.readyState>=WebSocket.CLOSING&&t()})}function m(e,r,t){try{e.close(r,t)}catch{}}async function p(e,t,a,s){var n,o;switch(t.type){case"ping":return void d(e,{type:"pong",timestamp:t.timestamp});case"http-request":try{let s=await fetch(new URL(t.path,`${r(a.localBaseUrl)}/`),{method:t.method,headers:t.headers,...t.bodyBase64?{body:Buffer.from(t.bodyBase64,"base64")}:{}}),n=Buffer.from(await s.arrayBuffer());d(e,{type:"http-response",requestId:t.requestId,status:s.status,headers:Object.fromEntries(s.headers.entries()),...n.length>0?{bodyBase64:n.toString("base64")}:{}})}catch(r){d(e,{type:"http-error",requestId:t.requestId,message:r instanceof Error?r.message:String(r)})}return;case"ws-open":{let o,i=new WebSocket((n=a.localBaseUrl,(o=new URL(t.path,`${r(n)}/`)).protocol="https:"===o.protocol?"wss:":"ws:",o.toString()));i.binaryType="arraybuffer";let f=!1;i.addEventListener("message",r=>{(async()=>{if(!f)return;let a=await c(r.data);d(e,{type:"ws-frame",streamId:t.streamId,dataBase64:a.toString("base64"),binary:"string"!=typeof r.data})})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),i.addEventListener("close",r=>{s.delete(t.streamId),f&&d(e,{type:"ws-close",streamId:t.streamId,code:r.code,reason:r.reason})}),i.addEventListener("error",()=>{f&&d(e,{type:"ws-close",streamId:t.streamId,code:1011,reason:"Upstream WebSocket error."})}),s.set(t.streamId,i);try{await l(i,"Upstream"),f=!0,d(e,{type:"ws-open-result",streamId:t.streamId,success:!0,headers:{}})}catch(r){s.delete(t.streamId),m(i,1011,"open failed"),d(e,{type:"ws-open-result",streamId:t.streamId,success:!1,error:r instanceof Error?r.message:String(r)})}return}case"ws-frame":{let e=s.get(t.streamId);if(!e||1!==e.readyState)return;let r=Buffer.from(t.dataBase64,"base64");e.send(t.binary?r:r.toString("utf8"));return}case"ws-close":{let e=s.get(t.streamId);if(!e)return;s.delete(t.streamId),m(e,"number"==typeof(o=t.code)&&Number.isInteger(o)&&(1e3===o||o>=3e3&&o<=4999||o>=1001&&o<=1015&&1004!==o&&1005!==o&&1006!==o)?o:1011,t.reason??"bridge requested close");return}}}async function y(r){let t=new Map;for(;;){try{let e=await i(r),a=new WebSocket(e.wsUrl);a.binaryType="arraybuffer",await l(a,"Bridge"),a.addEventListener("message",e=>{(async()=>{let s=await f(e);await p(a,s,r,t)})().catch(e=>{console.error(e instanceof Error?e.message:String(e))})}),await u(a),t.forEach(e=>m(e,1012,"bridge disconnected")),t.clear()}catch(e){console.error(e instanceof Error?e.message:String(e))}await e(1e3)}}(async function(e,r){let i=function(e,r){if(e[0]!==t)return null;let i=r[n]?.trim(),c=r[s]?.trim(),f=r[o]?.trim();if(!i||!c||!f)throw Error("Metro companion worker is missing required environment configuration.");return{serverBaseUrl:i,bearerToken:c,localBaseUrl:f,launchUrl:r[a]?.trim()||void 0}}(e,r);return!!i&&(await y(i),!0)})(process.argv.slice(2),process.env).catch(e=>{if(e instanceof Error&&e.message.includes("missing required environment")){console.error(e.message),process.exitCode=1;return}console.error(e instanceof Error?e.stack??e.message:String(e)),process.exitCode=1});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
export declare function buildAndroidRuntimeHints(baseUrl: string): MetroRuntimeHints;
|
|
2
|
+
|
|
3
|
+
export declare function buildBundleUrl(baseUrl: string, platform: 'ios' | 'android'): string;
|
|
4
|
+
|
|
5
|
+
export declare function buildIosRuntimeHints(baseUrl: string): MetroRuntimeHints;
|
|
6
|
+
|
|
7
|
+
export declare function ensureMetroTunnel(options: EnsureMetroTunnelOptions): Promise<EnsureMetroTunnelResult>;
|
|
8
|
+
|
|
9
|
+
export declare type EnsureMetroTunnelOptions = {
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
serverBaseUrl: string;
|
|
12
|
+
bearerToken: string;
|
|
13
|
+
localBaseUrl: string;
|
|
14
|
+
launchUrl?: string;
|
|
15
|
+
profileKey?: string;
|
|
16
|
+
consumerKey?: string;
|
|
17
|
+
env?: EnvSource;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export declare type EnsureMetroTunnelResult = {
|
|
21
|
+
pid: number;
|
|
22
|
+
started: boolean;
|
|
23
|
+
logPath: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
declare type EnvSource = NodeJS.ProcessEnv | Record<string, string | undefined>;
|
|
27
|
+
|
|
28
|
+
export declare type MetroBridgeDescriptor = {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
base_url: string;
|
|
31
|
+
status_url?: string;
|
|
32
|
+
bundle_url?: string;
|
|
33
|
+
ios_runtime: MetroBridgeRuntimePayload;
|
|
34
|
+
android_runtime: MetroBridgeRuntimePayload;
|
|
35
|
+
upstream: {
|
|
36
|
+
bundle_url?: string;
|
|
37
|
+
host?: string;
|
|
38
|
+
port?: number;
|
|
39
|
+
status_url?: string;
|
|
40
|
+
};
|
|
41
|
+
probe: {
|
|
42
|
+
reachable: boolean;
|
|
43
|
+
status_code: number;
|
|
44
|
+
latency_ms: number;
|
|
45
|
+
detail: string;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export declare type MetroBridgeResult = {
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
baseUrl: string;
|
|
52
|
+
statusUrl: string;
|
|
53
|
+
bundleUrl: string;
|
|
54
|
+
iosRuntime: MetroRuntimeHints;
|
|
55
|
+
androidRuntime: MetroRuntimeHints;
|
|
56
|
+
upstream: {
|
|
57
|
+
bundleUrl: string;
|
|
58
|
+
host: string;
|
|
59
|
+
port: number;
|
|
60
|
+
statusUrl: string;
|
|
61
|
+
};
|
|
62
|
+
probe: {
|
|
63
|
+
reachable: boolean;
|
|
64
|
+
statusCode: number;
|
|
65
|
+
latencyMs: number;
|
|
66
|
+
detail: string;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export declare type MetroBridgeRuntimePayload = {
|
|
71
|
+
metro_host?: string;
|
|
72
|
+
metro_port?: number;
|
|
73
|
+
metro_bundle_url?: string;
|
|
74
|
+
launch_url?: string;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export declare type MetroRuntimeHints = SessionRuntimeHints;
|
|
78
|
+
|
|
79
|
+
export declare type MetroTunnelHttpErrorMessage = {
|
|
80
|
+
type: 'http-error';
|
|
81
|
+
requestId: string;
|
|
82
|
+
message: string;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export declare type MetroTunnelHttpRequestMessage = {
|
|
86
|
+
type: 'http-request';
|
|
87
|
+
requestId: string;
|
|
88
|
+
method: string;
|
|
89
|
+
path: string;
|
|
90
|
+
headers?: Record<string, string>;
|
|
91
|
+
bodyBase64?: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export declare type MetroTunnelHttpResponseMessage = {
|
|
95
|
+
type: 'http-response';
|
|
96
|
+
requestId: string;
|
|
97
|
+
status: number;
|
|
98
|
+
headers: Record<string, string>;
|
|
99
|
+
bodyBase64?: string;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export declare type MetroTunnelMessage = MetroTunnelRequestMessage | MetroTunnelResponseMessage;
|
|
103
|
+
|
|
104
|
+
export declare type MetroTunnelPingMessage = {
|
|
105
|
+
type: 'ping';
|
|
106
|
+
timestamp: number;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export declare type MetroTunnelPongMessage = {
|
|
110
|
+
type: 'pong';
|
|
111
|
+
timestamp: number;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export declare type MetroTunnelRequestMessage = MetroTunnelPingMessage | MetroTunnelHttpRequestMessage | MetroTunnelWebSocketOpenMessage | MetroTunnelWebSocketFrameMessage | MetroTunnelWebSocketCloseMessage;
|
|
115
|
+
|
|
116
|
+
export declare type MetroTunnelResponseMessage = MetroTunnelPongMessage | MetroTunnelHttpResponseMessage | MetroTunnelHttpErrorMessage | MetroTunnelWebSocketOpenResultMessage | MetroTunnelWebSocketFrameMessage | MetroTunnelWebSocketCloseMessage;
|
|
117
|
+
|
|
118
|
+
export declare type MetroTunnelWebSocketCloseMessage = {
|
|
119
|
+
type: 'ws-close';
|
|
120
|
+
streamId: string;
|
|
121
|
+
code?: number;
|
|
122
|
+
reason?: string;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export declare type MetroTunnelWebSocketFrameMessage = {
|
|
126
|
+
type: 'ws-frame';
|
|
127
|
+
streamId: string;
|
|
128
|
+
dataBase64: string;
|
|
129
|
+
binary: boolean;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export declare type MetroTunnelWebSocketOpenMessage = {
|
|
133
|
+
type: 'ws-open';
|
|
134
|
+
streamId: string;
|
|
135
|
+
path: string;
|
|
136
|
+
headers?: Record<string, string>;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export declare type MetroTunnelWebSocketOpenResultMessage = {
|
|
140
|
+
type: 'ws-open-result';
|
|
141
|
+
streamId: string;
|
|
142
|
+
success: boolean;
|
|
143
|
+
headers?: Record<string, string>;
|
|
144
|
+
error?: string;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export declare function normalizeBaseUrl(input: string): string;
|
|
148
|
+
|
|
149
|
+
export declare function prepareRemoteMetro(options: PrepareRemoteMetroOptions): Promise<PrepareRemoteMetroResult>;
|
|
150
|
+
|
|
151
|
+
export declare type PrepareRemoteMetroOptions = {
|
|
152
|
+
projectRoot: string;
|
|
153
|
+
kind: 'auto' | 'react-native' | 'expo';
|
|
154
|
+
publicBaseUrl: string;
|
|
155
|
+
proxyBaseUrl?: string;
|
|
156
|
+
proxyBearerToken?: string;
|
|
157
|
+
launchUrl?: string;
|
|
158
|
+
profileKey?: string;
|
|
159
|
+
consumerKey?: string;
|
|
160
|
+
port?: number;
|
|
161
|
+
listenHost?: string;
|
|
162
|
+
statusHost?: string;
|
|
163
|
+
startupTimeoutMs?: number;
|
|
164
|
+
probeTimeoutMs?: number;
|
|
165
|
+
reuseExisting?: boolean;
|
|
166
|
+
installDependenciesIfNeeded?: boolean;
|
|
167
|
+
runtimeFilePath?: string;
|
|
168
|
+
logPath?: string;
|
|
169
|
+
env?: EnvSource;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export declare type PrepareRemoteMetroResult = {
|
|
173
|
+
iosRuntime: MetroRuntimeHints;
|
|
174
|
+
androidRuntime: MetroRuntimeHints;
|
|
175
|
+
bridge: MetroBridgeResult | null;
|
|
176
|
+
started: boolean;
|
|
177
|
+
reused: boolean;
|
|
178
|
+
logPath: string;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
declare type SessionRuntimeHints = {
|
|
182
|
+
platform?: 'ios' | 'android';
|
|
183
|
+
metroHost?: string;
|
|
184
|
+
metroPort?: number;
|
|
185
|
+
bundleUrl?: string;
|
|
186
|
+
launchUrl?: string;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export declare function stopMetroTunnel(options: StopMetroTunnelOptions): Promise<void>;
|
|
190
|
+
|
|
191
|
+
export declare type StopMetroTunnelOptions = {
|
|
192
|
+
projectRoot: string;
|
|
193
|
+
profileKey?: string;
|
|
194
|
+
consumerKey?: string;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{buildMetroRuntimeHints as e,ensureMetroCompanion as t,stopMetroCompanion as r,prepareMetroRuntime as n}from"./974.js";async function o(e){let t=await n({projectRoot:e.projectRoot,kind:e.kind,publicBaseUrl:e.publicBaseUrl,proxyBaseUrl:e.proxyBaseUrl,proxyBearerToken:e.proxyBearerToken,launchUrl:e.launchUrl,companionProfileKey:e.profileKey,companionConsumerKey:e.consumerKey,metroPort:e.port,listenHost:e.listenHost,statusHost:e.statusHost,startupTimeoutMs:e.startupTimeoutMs,probeTimeoutMs:e.probeTimeoutMs,reuseExisting:e.reuseExisting,installDependenciesIfNeeded:e.installDependenciesIfNeeded,runtimeFilePath:e.runtimeFilePath,logPath:e.logPath,env:e.env});return{iosRuntime:t.iosRuntime,androidRuntime:t.androidRuntime,bridge:t.bridge,started:t.started,reused:t.reused,logPath:t.logPath}}async function i(e){let r=await t(e);return{pid:r.pid,started:r.spawned,logPath:r.logPath}}async function s(e){await r(e)}function a(t){return e(t,"ios")}function u(t){return e(t,"android")}export{buildBundleUrl,normalizeBaseUrl}from"./974.js";export{u as buildAndroidRuntimeHints,a as buildIosRuntimeHints,i as ensureMetroTunnel,o as prepareRemoteMetro,s as stopMetroTunnel};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export declare type RemoteConfigProfile = {
|
|
2
|
+
stateDir?: string;
|
|
3
|
+
daemonBaseUrl?: string;
|
|
4
|
+
daemonAuthToken?: string;
|
|
5
|
+
daemonTransport?: 'auto' | 'socket' | 'http';
|
|
6
|
+
daemonServerMode?: 'socket' | 'http' | 'dual';
|
|
7
|
+
tenant?: string;
|
|
8
|
+
sessionIsolation?: 'none' | 'tenant';
|
|
9
|
+
runId?: string;
|
|
10
|
+
leaseId?: string;
|
|
11
|
+
platform?: 'ios' | 'macos' | 'android' | 'linux' | 'apple';
|
|
12
|
+
target?: 'mobile' | 'tv' | 'desktop';
|
|
13
|
+
device?: string;
|
|
14
|
+
udid?: string;
|
|
15
|
+
serial?: string;
|
|
16
|
+
iosSimulatorDeviceSet?: string;
|
|
17
|
+
androidDeviceAllowlist?: string;
|
|
18
|
+
session?: string;
|
|
19
|
+
metroProjectRoot?: string;
|
|
20
|
+
metroKind?: 'auto' | 'react-native' | 'expo';
|
|
21
|
+
metroPublicBaseUrl?: string;
|
|
22
|
+
metroProxyBaseUrl?: string;
|
|
23
|
+
metroBearerToken?: string;
|
|
24
|
+
metroPreparePort?: number;
|
|
25
|
+
metroListenHost?: string;
|
|
26
|
+
metroStatusHost?: string;
|
|
27
|
+
metroStartupTimeoutMs?: number;
|
|
28
|
+
metroProbeTimeoutMs?: number;
|
|
29
|
+
metroRuntimeFile?: string;
|
|
30
|
+
metroNoReuseExisting?: boolean;
|
|
31
|
+
metroNoInstallDeps?: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export declare type RemoteConfigProfileOptions = {
|
|
35
|
+
configPath: string;
|
|
36
|
+
cwd: string;
|
|
37
|
+
env?: Record<string, string | undefined>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export declare type ResolvedRemoteConfigProfile = {
|
|
41
|
+
resolvedPath: string;
|
|
42
|
+
profile: RemoteConfigProfile;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export declare function resolveRemoteConfigPath(options: RemoteConfigProfileOptions): string;
|
|
46
|
+
|
|
47
|
+
export declare function resolveRemoteConfigProfile(options: RemoteConfigProfileOptions): ResolvedRemoteConfigProfile;
|
|
48
|
+
|
|
49
|
+
export { }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{resolveUserPath as n,AppError as r}from"./957.js";let o=new Set(["1","true","yes","on"]),i=new Set(["0","false","no","off"]);function a(e,t,n,o){if(e.multiple)return(Array.isArray(t)?t:[t]).map(t=>a({...e,multiple:!1},t,n,o));if("boolean"===e.type){var i=t,s=n,f=o;if("boolean"==typeof i)return i;if("string"==typeof i){let e=l(i);if(void 0!==e)return e}throw new r("INVALID_ARGS",`Invalid value for "${f}" in ${s}. Expected boolean.`)}if("booleanOrString"===e.type){if("boolean"==typeof t)return t;if("string"==typeof t&&void 0!==l(t))return l(t);if("string"==typeof t&&t.trim().length>0)return t;throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Expected boolean or non-empty string.`)}if("string"===e.type){if("string"==typeof t&&t.trim().length>0)return t;throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Expected non-empty string.`)}if("enum"===e.type){if(void 0!==e.setValue){var u=e,y=t,p=n,m=o;let i=u.setValue;if(y===i)return i;if("string"==typeof y){let e=y.trim();if(""===e||"true"===e||"1"===e)return i;if("false"===e||"0"===e)return}if(!0===y)return i;if(!1!==y)throw new r("INVALID_ARGS",`Invalid value for "${m}" in ${p}. Expected boolean-like value for enum flag.`);return}if("string"!=typeof t||!e.enumValues?.includes(t))throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Expected one of: ${e.enumValues?.join(", ")}.`);return t}let g="number"==typeof t?t:"string"==typeof t?Number(t):NaN;if(!Number.isFinite(g)||!Number.isInteger(g))throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Expected integer.`);if("number"==typeof e.min&&g<e.min)throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Must be >= ${e.min}.`);if("number"==typeof e.max&&g>e.max)throw new r("INVALID_ARGS",`Invalid value for "${o}" in ${n}. Must be <= ${e.max}.`);return g}function l(e){let t=e.trim().toLowerCase();return!!o.has(t)||!i.has(t)&&void 0}let s=[{key:"stateDir",type:"string",path:!0},{key:"daemonBaseUrl",type:"string"},{key:"daemonAuthToken",type:"string"},{key:"daemonTransport",type:"enum",enumValues:["auto","socket","http"]},{key:"daemonServerMode",type:"enum",enumValues:["socket","http","dual"]},{key:"tenant",type:"string"},{key:"sessionIsolation",type:"enum",enumValues:["none","tenant"]},{key:"runId",type:"string"},{key:"leaseId",type:"string"},{key:"platform",type:"enum",enumValues:["ios","macos","android","linux","apple"]},{key:"target",type:"enum",enumValues:["mobile","tv","desktop"]},{key:"device",type:"string"},{key:"udid",type:"string"},{key:"serial",type:"string"},{key:"iosSimulatorDeviceSet",type:"string",path:!0,legacyEnvNames:["IOS_SIMULATOR_DEVICE_SET"]},{key:"androidDeviceAllowlist",type:"string",legacyEnvNames:["ANDROID_DEVICE_ALLOWLIST"]},{key:"session",type:"string"},{key:"metroProjectRoot",type:"string",path:!0},{key:"metroKind",type:"enum",enumValues:["auto","react-native","expo"]},{key:"metroPublicBaseUrl",type:"string"},{key:"metroProxyBaseUrl",type:"string"},{key:"metroBearerToken",type:"string",legacyEnvNames:["AGENT_DEVICE_PROXY_TOKEN"]},{key:"metroPreparePort",type:"int",min:1,max:65535},{key:"metroListenHost",type:"string"},{key:"metroStatusHost",type:"string"},{key:"metroStartupTimeoutMs",type:"int",min:1},{key:"metroProbeTimeoutMs",type:"int",min:1},{key:"metroRuntimeFile",type:"string",path:!0},{key:"metroNoReuseExisting",type:"boolean"},{key:"metroNoInstallDeps",type:"boolean"}],f=new Map(s.map(e=>[e.key,e]));function u(e){let t=e.env??process.env;return n(e.configPath,{cwd:e.cwd,env:t})}function y(o){let i=function(o){let i,l,s=o.env??process.env,y=u(o);if(!e.existsSync(y))throw new r("INVALID_ARGS",`Remote config file not found: ${y}`);try{i=e.readFileSync(y,"utf8")}catch(e){throw new r("INVALID_ARGS",`Failed to read remote config file: ${y}`,{cause:e instanceof Error?e.message:String(e)})}try{l=JSON.parse(i)}catch(e){throw new r("INVALID_ARGS",`Invalid JSON in remote config file: ${y}`,{cause:e instanceof Error?e.message:String(e)})}if(!l||"object"!=typeof l||Array.isArray(l))throw new r("INVALID_ARGS",`Remote config file must contain a JSON object: ${y}`);let p={},m=l,g=t.dirname(y);for(let[e,t]of Object.entries(m)){let o=f.get(e);if(!o)throw new r("INVALID_ARGS",`Unsupported remote config key "${e}" in remote config file ${y}.`);let i=a(o,t,`remote config file ${y}`,e);p[o.key]="string"==typeof i&&"path"in o&&o.path?n(i,{cwd:g,env:s}):i}return{resolvedPath:y,profile:p}}(o);return{resolvedPath:i.resolvedPath,profile:function(...e){let t={};for(let n of e)if(n)for(let e of s){let r=n[e.key];void 0!==r&&(t[e.key]=r)}return t}(function(e=process.env){let t={};for(let n of s){let r=(function(e){let t=f.get(e);return[`AGENT_DEVICE_${e.replace(/([A-Z])/g,"_$1").replace(/[^A-Za-z0-9_]/g,"_").toUpperCase()}`,...t?.legacyEnvNames??[]]})(n.key).map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);r&&(t[n.key]=a(n,r.value,`environment variable ${r.name}`,r.name))}return t}(o.env),i.profile)}}export{u as resolveRemoteConfigPath,y as resolveRemoteConfigProfile};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readUpdateCheckWorkerArgs as e,runUpdateCheckWorker as c}from"./113.js";let o=e(process.argv.slice(2));o&&c(o).catch(()=>{process.exitCode=0});
|