agent-device 0.7.19 → 0.7.21
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/daemon.js +25 -25
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +40 -0
package/dist/src/daemon.js
CHANGED
|
@@ -8,34 +8,34 @@ ${e}`.toLowerCase()).includes("failed registering bundle identifier")||r.include
|
|
|
8
8
|
`)}function tI(e){if(e&&$.existsSync(e))try{$.unlinkSync(e)}catch{}}async function tv(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function tA(e){await new Promise(t=>setTimeout(t,e))}function ty(e,t){let r=t.includeTokens?.filter(e=>e.length>0)??[],i="",n=i=>{(!(r.length>0)||r.some(e=>i.includes(e)))&&e.write(function(e,t){if(0===t.length)return e;let r=e;for(let e of t)r=r.replace(e,"[REDACTED]");return r}(i,t.redactionPatterns))};return{onChunk:e=>{let t=`${i}${e}`.split("\n");for(let e of(i=t.pop()??"",t))n(`${e}
|
|
9
9
|
`)},flush:()=>{i&&(n(i),i="")}}}function tb(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function tN(e,t){let r=(await p("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function tS(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await tN(e,t);if(!d){await tA(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=ty(r,{redactionPatterns:i});o=tb(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&tg(n,u.pid);let p=await o;if(tI(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await tA(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),tI(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await tv(o),a&&!a.killed&&a.kill("SIGKILL"),await tv(d),tI(n)}}}async function t_(e,t,r,i){let n="active",a=h("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=ty(t,{redactionPatterns:r});"number"==typeof a.pid&&tg(i,a.pid);let s=tb(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),tI(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await tv(s),a.killed||a.kill("SIGKILL"),await tv(s),tI(i)}}}async function tD(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=ty(t,{redactionPatterns:r});"number"==typeof a.pid&&tg(i,a.pid);let s=tb(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),tI(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await tv(s),a.killed||a.kill("SIGKILL"),await tv(s),tI(i)}}}function tE(e,t){let r=process.env[e];if(!r)return t;let i=Number.parseInt(r,10);return Number.isInteger(i)&&i>0?i:t}function tk(e){let t=n.dirname(e);$.existsSync(t)||$.mkdirSync(t,{recursive:!0}),function(e,t){if($.existsSync(e)&&!($.statSync(e).size<t.maxBytes))for(let r=t.maxRotatedFiles;r>=1;r-=1){let t=1===r?e:`${e}.${r-1}`,i=`${e}.${r}`;$.existsSync(t)&&($.existsSync(i)&&$.unlinkSync(i),$.renameSync(t,i))}}(e,{maxBytes:tE("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:tE("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function tO(e,t,r,i){tk(r);let n=$.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await tD(e.id,n,a,i):await t_(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new I("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await tS(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function tL(e){await e.stop(),await tv(e.wait)}async function tM(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await p("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await p("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await p("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await p("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function tx(e){let t=n.dirname(e),r=n.basename(e);$.existsSync(t)||$.mkdirSync(t,{recursive:!0}),$.existsSync(e)?$.truncateSync(e,0):$.writeFileSync(e,"","utf8");let i=0;for(let e of $.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{$.unlinkSync(n.join(t,e)),i+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:i}}let tC=new Map;function tR(e){let t=tC.get(e);if(t&&(clearTimeout(t.timer),tC.delete(e),t.deleteAfterDownload))try{$.rmSync(t.artifactPath,{force:!0})}catch{}}let tT=new Map;function tP(e){let t=tT.get(e);t&&(clearTimeout(t.timer),tT.delete(e),$.rmSync(t.tempDir,{recursive:!0,force:!0}))}async function t$(e){let t=e.headers["x-artifact-type"],r=e.headers["x-artifact-filename"];if(!t||!r)throw new I("INVALID_ARGS","Missing required headers: x-artifact-type and x-artifact-filename");if("file"!==t&&"app-bundle"!==t)throw new I("INVALID_ARGS",`Invalid x-artifact-type: ${t}. Must be "file" or "app-bundle".`);!function(e){let t=e.headers["content-length"];if("string"!=typeof t)return;let r=Number(t);if(Number.isFinite(r)&&r>0x80000000)throw new I("INVALID_ARGS","Upload exceeds maximum size of 2147483648 bytes")}(e);let i=function(e){let t=n.basename(e);if(!t||"."===t||".."===t)throw new I("INVALID_ARGS",`Invalid artifact filename: ${e}`);return t}(r),a=$.mkdtempSync(n.join(V.tmpdir(),"agent-device-upload-"));try{if("file"===t){let t=n.join(a,i);return await tF(e,t),{artifactPath:t,tempDir:a}}let r=n.join(a,"artifact.tar");await tF(e,r),await tV(r,i),await p("tar",["xf",r,"-C",a]),$.rmSync(r,{force:!0});let o=n.join(a,i);if(!$.existsSync(o))throw new I("INVALID_ARGS",`Expected extracted bundle "${i}" not found in archive`);return{artifactPath:o,tempDir:a}}catch(e){throw $.rmSync(a,{recursive:!0,force:!0}),e}}function tF(e,t){return new Promise((r,i)=>{let n=$.createWriteStream(t),a=!1,o=0,s=e=>{a||(a=!0,i(e))};e.on("data",t=>{if((o+=t.length)>0x80000000){let t=new I("INVALID_ARGS","Upload exceeds maximum size of 2147483648 bytes");e.destroy(t),n.destroy(t)}}),e.pipe(n),n.on("finish",()=>{a||(a=!0,r())}),n.on("error",s),e.on("error",s)})}async function tV(e,t){let r=(await p("tar",["-tf",e])).stdout.split(/\r?\n/).map(e=>e.trim()).filter(Boolean);if(0===r.length)throw new I("INVALID_ARGS","Uploaded app bundle archive is empty");if(!r.some(e=>e===t||e.startsWith(`${t}/`)))throw new I("INVALID_ARGS",`Uploaded archive must contain a top-level "${t}" bundle`);for(let e of r)!function(e,t){if(e.includes("\0"))throw new I("INVALID_ARGS",`Invalid archive entry: ${e}`);if(n.posix.isAbsolute(e))throw new I("INVALID_ARGS",`Archive entry must be relative: ${e}`);let r=n.posix.normalize(e).replace(/^\.\/+/,"");if(!r||"."===r||r.startsWith("../"))throw new I("INVALID_ARGS",`Archive entry escapes bundle root: ${e}`);if(r!==t&&!r.startsWith(`${t}/`))throw new I("INVALID_ARGS",`Archive entry must stay inside top-level "${t}" bundle: ${e}`)}(e,t);for(let t of(await p("tar",["-tvf",e])).stdout.split(/\r?\n/).filter(Boolean)){let e=t[0];if("l"===e||"h"===e)throw new I("INVALID_ARGS","Uploaded app bundle archive cannot contain symlinks or hard links")}}let tU=new Set(["agent_device.command","agent-device.command"]),tG={"agent_device.lease.allocate":"lease_allocate","agent-device.lease.allocate":"lease_allocate","agent_device.lease.heartbeat":"lease_heartbeat","agent-device.lease.heartbeat":"lease_heartbeat","agent_device.lease.release":"lease_release","agent-device.lease.release":"lease_release"},tB=new Set([...tU,...Object.keys(tG)]);function tj(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function tq(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function tH(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function tW(e,t){let r="string"==typeof t.authorization?t.authorization:"",i=r.toLowerCase().startsWith("bearer ")?r.slice(7):void 0,n="string"==typeof t["x-agent-device-token"]?t["x-agent-device-token"]:void 0;return("string"==typeof e.token?e.token:void 0)??n??i??""}function tJ(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function tz(e,t){if(!e)return{ok:!0};let r=await e(t);if(void 0===r||!0===r)return{ok:!0};if(!1===r){let e=_(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:tj(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=_(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:tj(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=o(r.tenantId);if(!e){let e=_(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:tj(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function tK(){let e,t=process.env.AGENT_DEVICE_HTTP_AUTH_HOOK;if(!t)return null;let r=process.env.AGENT_DEVICE_HTTP_AUTH_EXPORT||"default",i=n.isAbsolute(t)?t:n.resolve(t);try{e=await import(g(i).href)}catch(e){throw new I("COMMAND_FAILED","Failed to load AGENT_DEVICE_HTTP_AUTH_HOOK module",{hookPath:i,error:e instanceof Error?e.message:String(e)})}let a=e[r];if("function"!=typeof a)throw new I("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function tX(e){let t=await tK(),{handleRequest:r,token:i}=e;return j.createServer((e,n)=>{if("GET"===e.method&&"/health"===e.url){n.statusCode=200,n.setHeader("content-type","application/json"),n.end(JSON.stringify({ok:!0}));return}if("POST"===e.method&&"/upload"===e.url)return void tY(e,n,t,i);if("GET"===e.method&&e.url?.startsWith("/upload/"))return void tZ(e,n,t,i);if("POST"!==e.method||"/rpc"!==e.url){n.statusCode=404,n.end("Not found");return}let a="";e.setEncoding("utf8"),e.on("data",t=>{(a+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{n.headersSent||tq(n,tj(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let i,o;try{i=JSON.parse(a)}catch{tq(n,tj(null,-32700,"Parse error"),400);return}if("2.0"!==i.jsonrpc||"string"!=typeof i.method)return void tq(n,tj(i.id??null,-32600,"Invalid Request"),400);if(!tB.has(i.method))return void tq(n,tj(i.id??null,-32601,`Method not found: ${i.method}`),404);if(!i.params||"object"!=typeof i.params)return void tq(n,tj(i.id??null,-32602,"Invalid params"),400);try{var s;let a=i.params,l=function(e,t,r){if(tU.has(e))return{token:tW(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=tG[e];if(i){let e;return{token:tW(t,r),session:tJ(t,"session")??"default",command:i,positionals:[],meta:{tenantId:tJ(t,"tenantId")??tJ(t,"tenant"),runId:tJ(t,"runId"),leaseId:tJ(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:tJ(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(i.method,a,e.headers);if(s=i.method,tU.has(s)&&("string"!=typeof l.command||0===l.command.length))return void tq(n,tj(i.id??null,-32602,"Invalid params: command is required"),400);o=ei(l.meta?.requestId,i.id),l.meta={...l.meta,requestId:o},en(o);let d=()=>{n.writableFinished||ea(o)};e.on("aborted",d),n.on("close",d);let u=await tz(t,{headers:e.headers,rpcRequest:i,daemonRequest:l});if(!u.ok)return void tq(n,u.response,u.statusCode);u.tenantId&&(l.meta={...l.meta,tenantId:u.tenantId,sessionIsolation:l.meta?.sessionIsolation??l.flags?.sessionIsolation??"tenant"});let c=await r(l);if(c.ok)return void tq(n,{jsonrpc:"2.0",id:i.id??null,result:c});tq(n,tj(i.id??null,-32e3,c.error.message,c.error),tH(c.error.code))}catch(t){let e=_(t);tq(n,tj(i.id??null,-32e3,e.message,e),tH(e.code))}finally{eo(o)}})})}async function tY(e,t,r,i){try{var n;let a,o,s=tW({},e.headers),l=tQ(s,i);if(l){t.statusCode=tH(l.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:l.message,code:l.code}));return}let d=await tz(r,{headers:e.headers,rpcRequest:{jsonrpc:"2.0",id:null,method:"agent_device.command"},daemonRequest:{token:s,session:"default",command:"upload",positionals:[]}});if(!d.ok){t.statusCode=d.statusCode,t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:d.response.error?.data?.message??d.response.error?.message??"Unauthorized"}));return}let c=await t$(e),p=(n={artifactPath:c.artifactPath,tempDir:c.tempDir,tenantId:d.tenantId},a=u.randomUUID(),o=setTimeout(()=>{tP(a)},3e5),tT.set(a,{artifactPath:n.artifactPath,tempDir:n.tempDir,tenantId:n.tenantId,timer:o}),a);t.statusCode=200,t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!0,uploadId:p}))}catch(r){let e=_(r);t.statusCode=tH(e.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:e.message,code:e.code}))}}async function tZ(e,t,r,i){let n=e.url?.slice("/upload/".length)??"";if(!n){t.statusCode=400,t.end("Missing artifact id");return}try{let a=tW({},e.headers),o=tQ(a,i);if(o){t.statusCode=tH(o.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:o.message,code:o.code}));return}let s=await tz(r,{headers:e.headers,rpcRequest:{jsonrpc:"2.0",id:null,method:"agent_device.command"},daemonRequest:{token:a,session:"default",command:"download_artifact",positionals:[n]}});if(!s.ok){t.statusCode=s.statusCode,t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:s.response.error?.data?.message??s.response.error?.message??"Unauthorized"}));return}let l=function(e,t){let r=tC.get(e);if(!r)throw new I("INVALID_ARGS",`Artifact not found: ${e}`);if(r.tenantId&&r.tenantId!==t)throw new I("UNAUTHORIZED","Artifact belongs to a different tenant");if(!$.existsSync(r.artifactPath))throw tR(e),new I("COMMAND_FAILED",`Artifact file is missing: ${r.artifactPath}`);return{artifactPath:r.artifactPath,fileName:r.fileName,deleteAfterDownload:r.deleteAfterDownload}}(n,s.tenantId),d=$.createReadStream(l.artifactPath);t.statusCode=200,t.setHeader("content-type","application/octet-stream"),l.fileName&&t.setHeader("content-disposition",`attachment; filename="${l.fileName.replace(/"/g,"")}"`),d.on("error",e=>{if(t.headersSent)t.destroy(e);else{let r=_(e);t.statusCode=tH(r.code),t.end(r.message)}}),t.on("close",()=>{t.writableFinished&&tR(n)}),d.pipe(t)}catch(r){let e=_(r);t.statusCode=tH(e.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:e.message,code:e.code}))}}function tQ(e,t){return t&&e!==t?_(new I("UNAUTHORIZED","Invalid token")):null}function t0(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function t1(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function t2(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class t3{leases=new Map;runBindings=new Map;maxActiveSimulatorLeases;defaultLeaseTtlMs;minLeaseTtlMs;maxLeaseTtlMs;now;constructor(e={}){this.maxActiveSimulatorLeases=Number.isInteger(e.maxActiveSimulatorLeases)?Math.max(0,Number(e.maxActiveSimulatorLeases)):0,this.defaultLeaseTtlMs=Number.isInteger(e.defaultLeaseTtlMs)?Math.max(1,Number(e.defaultLeaseTtlMs)):6e4,this.minLeaseTtlMs=Number.isInteger(e.minLeaseTtlMs)?Math.max(1,Number(e.minLeaseTtlMs)):5e3,this.maxLeaseTtlMs=Number.isInteger(e.maxLeaseTtlMs)?Math.max(this.minLeaseTtlMs,Number(e.maxLeaseTtlMs)):6e5,this.now=e.now??(()=>Date.now())}allocateLease(e){let t=t2(e.backend),r=o(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=t0(e.runId);if(!i)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");this.cleanupExpiredLeases();let n=this.resolveLeaseTtlMs(e.ttlMs),a=this.bindingKey(r,i,t),s=this.runBindings.get(a);if(s){let e=this.leases.get(s);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let l=this.now(),d={leaseId:u.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:l,heartbeatAt:l,expiresAt:l+n};return this.leases.set(d.leaseId,d),this.runBindings.set(a,d.leaseId),{...d}}heartbeatLease(e){let t=t1(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});this.assertOptionalScopeMatch(r,e.tenantId,e.runId);let i=this.resolveLeaseTtlMs(e.ttlMs);return this.refreshLease(r,i)}releaseLease(e){let t=t1(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);return r?(this.assertOptionalScopeMatch(r,e.tenantId,e.runId),this.leases.delete(t),this.runBindings.delete(this.bindingKey(r.tenantId,r.runId,r.backend)),{released:!0}):{released:!1}}assertLeaseAdmission(e){let t=t2(e.backend),r=o(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=t0(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=t1(e.leaseId);if(!n)throw new I("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}listActiveLeases(){return this.cleanupExpiredLeases(),Array.from(this.leases.values()).map(e=>({...e}))}cleanupExpiredLeases(){let e=this.now();for(let t of this.leases.values())t.expiresAt>e||(this.leases.delete(t.leaseId),this.runBindings.delete(this.bindingKey(t.tenantId,t.runId,t.backend)))}enforceCapacity(e){if("ios-simulator"!==e||this.maxActiveSimulatorLeases<=0)return;let t=Array.from(this.leases.values()).filter(e=>"ios-simulator"===e.backend).length;if(!(t<this.maxActiveSimulatorLeases))throw new I("COMMAND_FAILED","No simulator lease capacity available",{reason:"LEASE_CAPACITY_EXCEEDED",activeLeases:t,maxActiveLeases:this.maxActiveSimulatorLeases,backend:e,hint:"Retry after releasing another simulator lease."})}resolveLeaseTtlMs(e){if(!Number.isInteger(e))return this.defaultLeaseTtlMs;let t=Number(e);if(t<this.minLeaseTtlMs||t>this.maxLeaseTtlMs)throw new I("INVALID_ARGS",`Lease ttlMs must be between ${this.minLeaseTtlMs} and ${this.maxLeaseTtlMs}.`);return t}refreshLease(e,t){let r=this.now(),i={...e,heartbeatAt:r,expiresAt:r+t};return this.leases.set(i.leaseId,i),this.runBindings.set(this.bindingKey(i.tenantId,i.runId,i.backend),i.leaseId),{...i}}bindingKey(e,t,r){return`${e}:${t}:${r}`}assertOptionalScopeMatch(e,t,r){let i=o(t),n=t0(r);if(t&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(i&&e.tenantId!==i||n&&e.runId!==n)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}function t4(e,t){return["-s",e.id,...t]}async function t8(){if(!await A("adb"))throw new I("TOOL_MISSING","adb not found in PATH")}function t5(e,t){let r=`${e}
|
|
10
10
|
${t}`.toLowerCase();return r.includes("no shell command implementation")||r.includes("unknown command")}async function t6(e){await new Promise(t=>setTimeout(t,e))}function t9(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let r=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!r)return!1;let i=r[1]?.toLowerCase(),n=r[2]??"";return"http"!==i&&"https"!==i&&"ws"!==i&&"wss"!==i&&"ftp"!==i&&"ftps"!==i||n.startsWith("//")}function t7(e,t){let r,i=e?.trim();return i?i:"http"===(r=t.trim().split(":")[0]?.toLowerCase())||"https"===r?"com.apple.mobilesafari":void 0}let re=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];function rt(e){return`${e.stdout}
|
|
11
|
-
${e.stderr}`}function rr(e,t){return["-s",e,...t]}function ri(e){return e.startsWith("emulator-")}function rn(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function ra(e,t=z){return p("adb",rr(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function ro(e,t){let r=t.replace(/_/g," ").trim();if(!ri(e))return r||e;let i=await rs(e);return i?i.replace(/_/g," "):r||e}async function rs(e){for(let t of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let r=await p("adb",rr(e,["shell","getprop",t]),{allowFailure:!0,timeoutMs:1e4}),i=r.stdout.trim();if(0===r.exitCode&&i.length>0)return i}let t=await p("adb",rr(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:1e4}),r=t.stdout.trim();if(0===t.exitCode&&r.length>0)return r}async function rl(e,t){let r=rt(await p("adb",rr(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:z})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function rd(e){return(await Promise.all(re.map(async t=>await rl(e,t)))).some(e=>!0===e)}async function ru(e){var t;let r;return"tv"===((r=rt(await p("adb",rr(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:z})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await rd(e)?"tv":(t=rt(await p("adb",rr(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:z})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function rc(e={}){if(!await A("adb"))throw new I("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??eN(void 0),r=(await rp()).filter(e=>!t||t.has(e.serial));return await Promise.all(r.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([ro(e,t),rw(e),ru(e)]);return{platform:"android",id:e,name:r,kind:ri(e)?"emulator":"device",target:n,booted:i}}))}async function rp(){return(await p("adb",["devices","-l"],{timeoutMs:z})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}))}async function rf(){let e=await p("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:z});if(0!==e.exitCode)throw new I("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function rm(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await rh(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await new Promise(e=>setTimeout(e,1e3))}throw new I("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function rh(e,t){let r=rn(e);for(let e of(await rp()).filter(e=>(!t||e.serial===t)&&ri(e.serial)))if(rn(e.rawModel)===r||rn(await ro(e.serial,e.rawModel))===r)return e.serial}async function rw(e){try{let t=await ra(e);return"1"===t.stdout.trim()}catch{return!1}}async function rg(e){var t,r;let i,n=e.avdName.trim();if(!n)throw new I("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let a=e.timeoutMs??12e4;if(!await A("adb"))throw new I("TOOL_MISSING","adb not found in PATH");if(!await A("emulator"))throw new I("TOOL_MISSING","emulator not found in PATH");let o=await rf(),s=function(e,t){let r=e.find(e=>e===t);if(r)return r;let i=rn(t);return e.find(e=>rn(e)===i)}(o,n);if(!s)throw new I("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:n,availableAvds:o,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let d=Date.now(),u=(t=await rc(),r=e.serial,i=rn(s),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!r||e.id===r)&&rn(e.name)===i));if(!u){let t=["-avd",s];e.headless&&t.push("-no-window","-no-audio"),l("emulator",t)}let c=u??await rm({avdName:s,serial:e.serial,timeoutMs:a}),p=Math.max(1e3,a-(Date.now()-d));await rI(c.id,p);let f=(await rc()).find(e=>e.id===c.id);return f?{...f,name:s,booted:!0}:{...c,name:s,booted:!0}}async function rI(e,t=6e4){let r,i=K.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await X(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new I("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),s=await ra(e,Math.min(o,z));if(r=s,"1"!==s.stdout.trim())throw new I("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:n,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=eu({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:i,phase:"boot",classifyReason:e=>eu({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(c){let n=w(c),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=eu({error:c,stdout:o,stderr:s,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===d&&"Android device is still booting"===n.message&&(d="ANDROID_BOOT_TIMEOUT");let u={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:ec(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new I("COMMAND_FAILED","Android device did not finish booting in time",u);if("TOOL_MISSING"===n.code)throw new I("TOOL_MISSING",n.message,{...u,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new I("COMMAND_FAILED",n.message,{...u,...n.details??{}});throw new I(n.code,n.message,{...u,...n.details??{}},n.cause)}}let rv={settings:{type:"intent",value:"android.settings.SETTINGS"}},
|
|
12
|
-
${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let u=await
|
|
13
|
-
${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new I("COMMAND_FAILED",`adb uninstall failed for ${r.value}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return{package:r.value}}let
|
|
14
|
-
${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await p("adb",t4(e,["shell","cat",d])),c=
|
|
15
|
-
${t}`,i=r.indexOf("<?xml"),n=i>=0?i:r.indexOf("<hierarchy");if(n<0)return null;let a=r.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=r.slice(n,a+12).trim();return o.length>0?o:null}function r0(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}async function r1(e,t,r){await p("adb",t4(e,["shell","input","tap",String(t),String(r)]))}async function r2(e,t,r,i,n,a=250){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function r3(e){await p("adb",t4(e,["shell","input","keyevent","4"]))}async function r4(e){await p("adb",t4(e,["shell","input","keyevent","3"]))}async function r8(e){await p("adb",t4(e,["shell","input","keyevent","187"]))}async function r5(e,t,r,i=800){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function r6(e,t){let r=ia(t);if(!r||"ok"!==await io(e,t))try{let r=t.replace(/ /g,"%s");await p("adb",t4(e,["shell","input","text",r]))}catch(e){if(r&&function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return!!(t.includes("exception occurred while executing 'text'")||t.includes("nullpointerexception")&&t.includes("inputshellcommand.sendtext"))}(e))throw new I("COMMAND_FAILED","Non-ASCII text input is not supported on this Android shell. Install an ADB keyboard IME or use ASCII input.",{textPreview:t.slice(0,32)},e instanceof Error?e:void 0);throw e}}async function r9(e,t,r){await r1(e,t,r)}async function r7(e,t,r,i){let n=Array.from(i).length,a=ia(i),o=[{strategy:"input_text",clearPadding:12,minClear:8,maxClear:48}];a||(o.push({strategy:"clipboard_paste",clearPadding:12,minClear:8,maxClear:48}),o.push({strategy:"chunked_input",clearPadding:24,minClear:16,maxClear:96}));let s=null;for(let a of o){var l,d;await r9(e,t,r);let o=(l=n+a.clearPadding,d=a.minClear,Math.max(d,Math.min(a.maxClear,l)));if(await is(e,o),"input_text"===a.strategy)await r6(e,i);else if("clipboard_paste"===a.strategy){if("ok"!==await io(e,i))continue}else await ii(e,i,1,15);if((s=await il(e,t,r))===i)return}throw new I("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:s??null})}async function ie(e,t,r=.6){let{width:i,height:n}=await ir(e),a=Math.floor(i*r),o=Math.floor(n*r),s=Math.floor(i/2),l=Math.floor(n/2),d=s,u=l,c=s,f=l;switch(t){case"up":u=l-Math.floor(o/2),f=l+Math.floor(o/2);break;case"down":u=l+Math.floor(o/2),f=l-Math.floor(o/2);break;case"left":d=s-Math.floor(a/2),c=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),c=s-Math.floor(a/2);break;default:throw new I("INVALID_ARGS",`Unknown direction: ${t}`)}await p("adb",t4(e,["shell","input","swipe",String(d),String(u),String(c),String(f),"300"]))}async function it(e,t){for(let r=0;r<8;r+=1){let r="";try{r=await rY(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new I("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let r=t.toLowerCase(),i=/<node[^>]+>/g,n=i.exec(e);for(;n;){let t=rj(n[0]),a=(rq(t,"text")??"").toLowerCase(),o=(rq(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=rH(rq(t,"bounds"));if(e)return{x:Math.floor(e.x+e.width/2),y:Math.floor(e.y+e.height/2)};return{x:0,y:0}}n=i.exec(e)}return null}(r,t))return;await ie(e,"down",.5)}throw new I("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function ir(e){let t=(await p("adb",t4(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new I("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function ii(e,t,r,i){let n=Math.max(1,Math.floor(r)),a=Array.from(t);for(let t=0;t<a.length;t+=n){let r=a.slice(t,t+n).join("");await r6(e,r),i>0&&t+n<a.length&&await t6(i)}}function ia(e){for(let t of e){let e=t.codePointAt(0);if(void 0!==e&&(e<32||e>126))return!0}return!1}async function io(e,t){let r=await p("adb",t4(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":t5(r.stdout,r.stderr)?"unsupported":0===(await p("adb",t4(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",t4(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}async function is(e,t){let r=Math.max(0,t);await p("adb",t4(e,["shell","input","keyevent","KEYCODE_MOVE_END"]),{allowFailure:!0});for(let t=0;t<r;t+=24){let i=Math.min(24,r-t);await p("adb",t4(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function il(e,t,r){let i,n=await rY(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=rB(i[0]),n=rH(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!d)continue;let c=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(u&&id(a)){(!o||c<=o.area)&&(o={text:d,area:c});continue}if(p&&id(a)){(!s||c<=s.area)&&(s={text:d,area:c});continue}p&&(!l||c<=l.area)&&(l={text:d,area:c})}return o?.text??s?.text??l?.text??null}function id(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function iu(e){let t=await p("adb",t4(e,["shell","dumpsys","input_method"]),{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t=function(e){let t=new Map;for(let r of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=r[1],i=r[2]?.toLowerCase();e&&("true"===i||"false"===i)&&t.set(e,"true"===i)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),r=t??!1;if(null===t){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(r=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),n=i.length>0?i[i.length-1]?.[1]:void 0,a=n?`0x${n.toLowerCase()}`:void 0;return{visible:r,inputType:a,type:a?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let r=15&t;if(2===r)return"number";if(3===r)return"phone";if(4===r)return"datetime";if(1!==r)return"unknown";let i=4080&t;return 32===i||208===i?"email":128===i||224===i||144===i?"password":"text"}(a):void 0}}(t.stdout)}async function ic(e){let t=await iu(e),r=t,i=0;for(;r.visible&&i<2;)await r3(e),i+=1,await t6(120),r=await iu(e);return{attempts:i,wasVisible:t.visible,dismissed:t.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type}}async function ip(e){let t,r;return(r=(t=(await ih(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?r[1]??"":"null"===t.trim().toLowerCase()?"":t}async function im(e,t){await ih(e,["shell","cmd","clipboard","set","text",t],"write")}async function ih(e,t,r){let i=await p("adb",t4(e,t),{allowFailure:!0});if(t5(i.stdout,i.stderr))throw new I("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new I("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}let iw=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function ig(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new I("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function iI(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new I("INVALID_ARGS",`permission setting requires a target: ${iw.join("|")}`)}function iv(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new I("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}async function iA(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=ib(r);await p("adb",t4(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=ib(r);await p("adb",t4(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await p("adb",t4(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=ib(r);await p("adb",t4(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await iN(e,r);await p("adb",t4(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new I("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await iy(e,t);return}case"permission":{if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t=ig(r),a=function(e,t){let r=iI(e);if(t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===r)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===r)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===r)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===r)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new I("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(n?.permissionTarget,n?.permissionMode);if("notifications"===a.kind)return void await i_(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await iS(e,i,o);await p("adb",t4(e,["shell","pm",o,i,a.value]));return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function iy(e,t){var r;let i,n,a=(r=e,n=[["shell","cmd","fingerprint","touch",i="match"===t?"1":"9999"],["shell","cmd","fingerprint","finger",i]],"emulator"===r.kind&&n.push(["emu","finger","touch",i]),n),o=[];for(let t of a){let r=await p("adb",t4(e,t),{allowFailure:!0});if(0===r.exitCode)return;o.push({args:t,stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}let s=o.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(o.length>0&&o.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
16
|
-
${r}`.toLowerCase()).includes("unknown command")||i.includes("can't find service: fingerprint")||i.includes("service fingerprint was not found")||i.includes("fingerprint cmd unavailable")||i.includes("emu command is not supported")||i.includes("emulator console is not running")||i.includes("fingerprint")&&i.includes("not found")}))throw new I("UNSUPPORTED_OPERATION","Android fingerprint simulation is not supported on this target/runtime.",{deviceId:e.id,action:t,hint:"Use an Android emulator with biometric support, or a device/runtime that exposes cmd fingerprint.",attempts:s});throw new I("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:s})}function
|
|
17
|
-
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"yes"===i?"dark":"no"===i?"light":"auto"===i?"auto":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current Android appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"auto"===n?"dark":"dark"===n?"light":"dark"}async function
|
|
18
|
-
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}function
|
|
19
|
-
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",e_(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await
|
|
11
|
+
${e.stderr}`}function rr(e,t){return["-s",e,...t]}function ri(e){return e.startsWith("emulator-")}function rn(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function ra(e,t=z){return p("adb",rr(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function ro(e,t){let r=t.replace(/_/g," ").trim();if(!ri(e))return r||e;let i=await rs(e);return i?i.replace(/_/g," "):r||e}async function rs(e){for(let t of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let r=await p("adb",rr(e,["shell","getprop",t]),{allowFailure:!0,timeoutMs:1e4}),i=r.stdout.trim();if(0===r.exitCode&&i.length>0)return i}let t=await p("adb",rr(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:1e4}),r=t.stdout.trim();if(0===t.exitCode&&r.length>0)return r}async function rl(e,t){let r=rt(await p("adb",rr(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:z})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function rd(e){return(await Promise.all(re.map(async t=>await rl(e,t)))).some(e=>!0===e)}async function ru(e){var t;let r;return"tv"===((r=rt(await p("adb",rr(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:z})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await rd(e)?"tv":(t=rt(await p("adb",rr(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:z})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function rc(e={}){if(!await A("adb"))throw new I("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??eN(void 0),r=(await rp()).filter(e=>!t||t.has(e.serial));return await Promise.all(r.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([ro(e,t),rw(e),ru(e)]);return{platform:"android",id:e,name:r,kind:ri(e)?"emulator":"device",target:n,booted:i}}))}async function rp(){return(await p("adb",["devices","-l"],{timeoutMs:z})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}))}async function rf(){let e=await p("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:z});if(0!==e.exitCode)throw new I("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function rm(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await rh(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await new Promise(e=>setTimeout(e,1e3))}throw new I("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function rh(e,t){let r=rn(e);for(let e of(await rp()).filter(e=>(!t||e.serial===t)&&ri(e.serial)))if(rn(e.rawModel)===r||rn(await ro(e.serial,e.rawModel))===r)return e.serial}async function rw(e){try{let t=await ra(e);return"1"===t.stdout.trim()}catch{return!1}}async function rg(e){var t,r;let i,n=e.avdName.trim();if(!n)throw new I("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let a=e.timeoutMs??12e4;if(!await A("adb"))throw new I("TOOL_MISSING","adb not found in PATH");if(!await A("emulator"))throw new I("TOOL_MISSING","emulator not found in PATH");let o=await rf(),s=function(e,t){let r=e.find(e=>e===t);if(r)return r;let i=rn(t);return e.find(e=>rn(e)===i)}(o,n);if(!s)throw new I("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:n,availableAvds:o,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let d=Date.now(),u=(t=await rc(),r=e.serial,i=rn(s),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!r||e.id===r)&&rn(e.name)===i));if(!u){let t=["-avd",s];e.headless&&t.push("-no-window","-no-audio"),l("emulator",t)}let c=u??await rm({avdName:s,serial:e.serial,timeoutMs:a}),p=Math.max(1e3,a-(Date.now()-d));await rI(c.id,p);let f=(await rc()).find(e=>e.id===c.id);return f?{...f,name:s,booted:!0}:{...c,name:s,booted:!0}}async function rI(e,t=6e4){let r,i=K.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await X(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new I("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),s=await ra(e,Math.min(o,z));if(r=s,"1"!==s.stdout.trim())throw new I("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:n,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=eu({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:i,phase:"boot",classifyReason:e=>eu({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(c){let n=w(c),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=eu({error:c,stdout:o,stderr:s,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===d&&"Android device is still booting"===n.message&&(d="ANDROID_BOOT_TIMEOUT");let u={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:ec(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new I("COMMAND_FAILED","Android device did not finish booting in time",u);if("TOOL_MISSING"===n.code)throw new I("TOOL_MISSING",n.message,{...u,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new I("COMMAND_FAILED",n.message,{...u,...n.details??{}});throw new I(n.code,n.message,{...u,...n.details??{}},n.cause)}}let rv=/\.(?:apk|aab)$/i,rA=/^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$/;function ry(e){var t,r;let i=e.trim();return 0===i.length?"other":rv.test(i)?i.includes("/")||i.includes("\\")||i.startsWith(".")||i.startsWith("~")||(t=i,!rA.test(t))?"binary":"package":(r=i,rA.test(r))?"package":"other"}function rb(e){return`Android runtime hints require an installed package name, not "${e}". Install or reinstall the app first, then relaunch by package.`}let rN={settings:{type:"intent",value:"android.settings.SETTINGS"}},rS="android.intent.category.LAUNCHER",r_="android.intent.category.LEANBACK_LAUNCHER",rD="android.intent.category.DEFAULT";async function rE(e,t){let r=t.trim();if("package"===ry(r))return{type:"package",value:r};let i=rN[r.toLowerCase()];if(i)return i;let n=(await p("adb",t4(e,["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(r.toLowerCase()));if(1===n.length)return{type:"package",value:n[0]};if(n.length>1)throw new I("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function rk(e,t="all"){let r=await rO(e);return("user-installed"===t?(await rM(e)).filter(e=>r.has(e)):Array.from(r)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:function(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),r=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),i=r[r.length-1]??e;for(let e=r.length-1;e>=0;e-=1){let n=r[e];if(!t.has(n)){i=n;break}}return i.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}(e)}))}async function rO(e){let t=new Set;for(let r of rL(e,{includeFallbackWhenUnknown:!0})){let i=await p("adb",t4(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",r]),{allowFailure:!0});if(0===i.exitCode&&0!==i.stdout.trim().length)for(let e of i.stdout.split("\n")){let r=e.trim();if(!r)continue;let i=r.split(/\s+/)[0],n=i.includes("/")?i.split("/")[0]:i;n&&t.add(n)}}return t}function rL(e,t={}){return"tv"===e.target?[r_]:"mobile"===e.target?[rS]:t.includeFallbackWhenUnknown?[rS,r_]:[rS]}async function rM(e){return(await p("adb",t4(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function rx(e){let t=await rC(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let r=await rC(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return r||{}}async function rC(e,t){for(let r of t){let t=function(e){for(let t of[/mCurrentFocus=Window\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mFocusedApp=AppWindowToken\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/,/ResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/]){let r=t.exec(e);if(r)return{package:r[1],activity:r[2]}}return null}((await p("adb",t4(e,r),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function rR(e,t,r){var i,n;let a;e.booted||await rI(e.id);let o=t.trim();if(t9(o)){if(r)throw new I("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await p("adb",t4(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await rE(e,t),l=rL(e)[0]??rS;if("intent"===s.type){if(r)throw new I("INVALID_ARGS","Activity override requires a package name, not an intent");await p("adb",t4(e,["shell","am","start","-W","-a",s.value]));return}if(r){let t=r.includes("/")?r:`${s.value}/${r.startsWith(".")?r:`.${r}`}`;await p("adb",t4(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",rD,"-c",l,"-n",t]));return}let d=await p("adb",t4(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",rD,"-c",l,"-p",s.value]),{allowFailure:!0});if(0===d.exitCode&&(i=d.stdout,n=d.stderr,a=`${i}
|
|
12
|
+
${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let u=await rT(e,s.value);if(!u)throw new I("COMMAND_FAILED",`Failed to launch ${s.value}`,{stdout:d.stdout,stderr:d.stderr});await p("adb",t4(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",rD,"-c",l,"-n",u]))}async function rT(e,t){for(let r of Array.from(new Set(rL(e,{includeFallbackWhenUnknown:!0})))){let i=await p("adb",t4(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",r,t]),{allowFailure:!0});if(0!==i.exitCode)continue;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let r=t[e];if(r.includes("/"))return r.split(/\s+/)[0]}return null}(i.stdout);if(n)return n}return null}async function rP(e){e.booted||await rI(e.id)}async function r$(e,t){if("settings"===t.trim().toLowerCase())return void await p("adb",t4(e,["shell","am","force-stop","com.android.settings"]));let r=await rE(e,t);if("intent"===r.type)throw new I("INVALID_ARGS","Close requires a package name, not an intent");await p("adb",t4(e,["shell","am","force-stop",r.value]))}async function rF(e,t){let r=await rE(e,t);if("intent"===r.type)throw new I("INVALID_ARGS","App uninstall requires a package name, not an intent");let i=await p("adb",t4(e,["uninstall",r.value]),{allowFailure:!0});if(0!==i.exitCode){let e=`${i.stdout}
|
|
13
|
+
${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new I("COMMAND_FAILED",`adb uninstall failed for ${r.value}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return{package:r.value}}let rV=null;async function rU(){let e=`${process.env.PATH??""}::${process.env.AGENT_DEVICE_BUNDLETOOL_JAR??""}`;if(rV?.key===e)return rV.invocation;if(await A("bundletool")){let t={cmd:"bundletool",prefixArgs:[]};return rV={key:e,invocation:t},t}let t=process.env.AGENT_DEVICE_BUNDLETOOL_JAR?.trim();if(!t)throw new I("TOOL_MISSING","bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR to a bundletool-all.jar path.");try{await x.access(t)}catch{throw new I("TOOL_MISSING",`AGENT_DEVICE_BUNDLETOOL_JAR points to a missing file: ${t}`)}let r={cmd:"java",prefixArgs:["-jar",t]};return rV={key:e,invocation:r},r}async function rG(e){let t=await rU();await p(t.cmd,[...t.prefixArgs,...e])}async function rB(e,t){let r,i=await x.mkdtemp(n.join(V.tmpdir(),"agent-device-aab-")),a=n.join(i,"bundle.apks"),o=(r=process.env.AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE?.trim())&&r.length>0?r:"universal";try{await rG(["build-apks","--bundle",t,"--output",a,"--mode",o]),await rG(["install-apks","--apks",a,"--device-id",e.id])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function rj(e,t){".aab"===n.extname(t).toLowerCase()?await rB(e,t):await p("adb",t4(e,["install","-r",t]))}async function rq(e,t){e.booted||await rI(e.id),await rj(e,t)}async function rH(e,t,r){e.booted||await rI(e.id);let{package:i}=await rF(e,t);return await rj(e,r),{package:i}}function rW(e){let t=rJ(e),r=e=>{let r=rz(t,e);if(null!==r)return"true"===r};return{text:rz(t,"text"),desc:rz(t,"content-desc"),resourceId:rz(t,"resource-id"),className:rz(t,"class"),bounds:rz(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused")}}function rJ(e){let t=new Map,r=e.indexOf(" "),i=e.lastIndexOf(">");if(r<0||i<=r)return t;let n=/([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/y,a=r;for(;a<i;){for(;a<i;){let t=e[a];if(" "!==t&&"\n"!==t&&"\r"!==t&&" "!==t)break;a+=1}if(a>=i)break;let r=e[a];if("/"===r||">"===r)break;n.lastIndex=a;let o=n.exec(e);if(!o)break;t.set(o[1],o[3]),a=n.lastIndex}return t}function rz(e,t){return e.get(t)??null}function rK(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let r=Number(t[1]),i=Number(t[2]);return{x:r,y:i,width:Math.max(0,Number(t[3])-r),height:Math.max(0,Number(t[4])-i)}}function rX(e){return e?e.toLowerCase():""}function rY(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}async function rZ(e,t={}){return function(e,t,r){let i=function(e){let t={type:null,label:null,value:null,identifier:null,depth:-1,children:[]},r=[t],i=/<node\b[^>]*>|<\/node>/g,n=i.exec(e);for(;n;){let t=n[0];if(t.startsWith("</node")){r.length>1&&r.pop(),n=i.exec(e);continue}let a=rW(t),o=rK(a.bounds),s=r[r.length-1],l={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,rect:o,enabled:a.enabled,hittable:a.clickable??a.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||r.push(l),n=i.exec(e)}return t}(e),n=[],a=!1,o=r.depth??1/0,s=r.scope?function(e,t){let r=t.toLowerCase(),i=[...e.children];for(;i.length>0;){let e=i.shift(),t=e.label?.toLowerCase()??"",n=e.value?.toLowerCase()??"",a=e.identifier?.toLowerCase()??"";if(t.includes(r)||n.includes(r)||a.includes(r))return e;i.push(...e.children)}return null}(i,r.scope):null,l=s?[s]:i.children,d=new Map,u=e=>{let t=d.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||u(t))return d.set(e,!0),!0;return d.set(e,!1),!1},c=(e,t,i,s=!1,l=!1)=>{var d,p,f,m,h,w;let g,I,v,A,y,b,N,S;if(n.length>=800){a=!0;return}if(t>o)return;let _=!!r.raw||(d=e,p=r,f=s,m=u(e),h=l,I=rX(d.type),v=!!(d.label&&d.label.trim().length>0),A=!!(d.identifier&&d.identifier.trim().length>0),y=v&&!rY(d.label??""),b=A&&!rY(d.identifier??""),N=(g=(w=I).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,S="imageview"===I||"imagebutton"===I,p.interactiveOnly?!!d.hittable||!!(y||b)&&!S&&(!N||!!h)&&(f||m||h):p.compact?y||b||!!d.hittable:!N&&!S||!!d.hittable||!!y||!!b&&!!m||m),D=i;_&&(D=n.length,n.push({index:D,type:e.type??void 0,label:e.label??void 0,value:e.value??void 0,identifier:e.identifier??void 0,rect:e.rect,enabled:e.enabled,hittable:e.hittable,depth:t,parentIndex:i}));let E=s||!!e.hittable,k=l||function(e){if(!e)return!1;let t=rX(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let r of e.children)if(c(r,t+1,D,E,k),a)return};for(let e of l)if(c(e,0,void 0,!1,!1),a)break;return a?{nodes:n,truncated:a}:{nodes:n}}(await r1(e),0,t)}let rQ=Buffer.from([137,80,78,71,13,10,26,10]);async function r0(e,t){let r=await p("adb",t4(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!r.stdoutBuffer)throw new I("COMMAND_FAILED","Failed to capture screenshot");let i=r.stdoutBuffer.indexOf(rQ);if(i<0)throw new I("COMMAND_FAILED","Screenshot data does not contain a valid PNG header");let n=function(e,t){let r=t+rQ.length;for(;r+8<=e.length;){let t=e.readUInt32BE(r),i=r+4,n=e.toString("ascii",i,i+4),a=r+12+t;if(a>e.length)break;if("IEND"===n)return a;r=a}return null}(r.stdoutBuffer,i);if(!n)throw new I("COMMAND_FAILED","Screenshot data does not contain a complete PNG payload");await x.writeFile(t,r.stdoutBuffer.subarray(i,n))}async function r1(e){return Y(()=>r2(e),{shouldRetry:r4})}async function r2(e){var t,r,i;let n,a,o=await p("adb",t4(e,["exec-out","uiautomator","dump","/dev/tty"]),{allowFailure:!0});if(0===o.exitCode){let e=r3(o.stdout,o.stderr);if(e)return e}let s="/sdcard/window_dump.xml",l=await p("adb",t4(e,["shell","uiautomator","dump",s])),d=(t=s,r=l.stdout,i=l.stderr,n=`${r}
|
|
14
|
+
${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await p("adb",t4(e,["shell","cat",d])),c=r3(u.stdout,u.stderr);if(!c)throw new I("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:u.stdout,stderr:u.stderr});return c}function r3(e,t){let r=`${e}
|
|
15
|
+
${t}`,i=r.indexOf("<?xml"),n=i>=0?i:r.indexOf("<hierarchy");if(n<0)return null;let a=r.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=r.slice(n,a+12).trim();return o.length>0?o:null}function r4(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}async function r8(e,t,r){await p("adb",t4(e,["shell","input","tap",String(t),String(r)]))}async function r5(e,t,r,i,n,a=250){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function r6(e){await p("adb",t4(e,["shell","input","keyevent","4"]))}async function r9(e){await p("adb",t4(e,["shell","input","keyevent","3"]))}async function r7(e){await p("adb",t4(e,["shell","input","keyevent","187"]))}async function ie(e,t,r,i=800){await p("adb",t4(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function it(e,t){let r=id(t);if(!r||"ok"!==await iu(e,t))try{let r=t.replace(/ /g,"%s");await p("adb",t4(e,["shell","input","text",r]))}catch(e){if(r&&function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return!!(t.includes("exception occurred while executing 'text'")||t.includes("nullpointerexception")&&t.includes("inputshellcommand.sendtext"))}(e))throw new I("COMMAND_FAILED","Non-ASCII text input is not supported on this Android shell. Install an ADB keyboard IME or use ASCII input.",{textPreview:t.slice(0,32)},e instanceof Error?e:void 0);throw e}}async function ir(e,t,r){await r8(e,t,r)}async function ii(e,t,r,i){let n=Array.from(i).length,a=id(i),o=[{strategy:"input_text",clearPadding:12,minClear:8,maxClear:48}];a||(o.push({strategy:"clipboard_paste",clearPadding:12,minClear:8,maxClear:48}),o.push({strategy:"chunked_input",clearPadding:24,minClear:16,maxClear:96}));let s=null;for(let a of o){var l,d;await ir(e,t,r);let o=(l=n+a.clearPadding,d=a.minClear,Math.max(d,Math.min(a.maxClear,l)));if(await ic(e,o),"input_text"===a.strategy)await it(e,i);else if("clipboard_paste"===a.strategy){if("ok"!==await iu(e,i))continue}else await il(e,i,1,15);if((s=await ip(e,t,r))===i)return}throw new I("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:s??null})}async function ia(e,t,r=.6){let{width:i,height:n}=await is(e),a=Math.floor(i*r),o=Math.floor(n*r),s=Math.floor(i/2),l=Math.floor(n/2),d=s,u=l,c=s,f=l;switch(t){case"up":u=l-Math.floor(o/2),f=l+Math.floor(o/2);break;case"down":u=l+Math.floor(o/2),f=l-Math.floor(o/2);break;case"left":d=s-Math.floor(a/2),c=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),c=s-Math.floor(a/2);break;default:throw new I("INVALID_ARGS",`Unknown direction: ${t}`)}await p("adb",t4(e,["shell","input","swipe",String(d),String(u),String(c),String(f),"300"]))}async function io(e,t){for(let r=0;r<8;r+=1){let r="";try{r=await r1(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new I("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let r=t.toLowerCase(),i=/<node[^>]+>/g,n=i.exec(e);for(;n;){let t=rJ(n[0]),a=(rz(t,"text")??"").toLowerCase(),o=(rz(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=rK(rz(t,"bounds"));if(e)return{x:Math.floor(e.x+e.width/2),y:Math.floor(e.y+e.height/2)};return{x:0,y:0}}n=i.exec(e)}return null}(r,t))return;await ia(e,"down",.5)}throw new I("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function is(e){let t=(await p("adb",t4(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new I("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function il(e,t,r,i){let n=Math.max(1,Math.floor(r)),a=Array.from(t);for(let t=0;t<a.length;t+=n){let r=a.slice(t,t+n).join("");await it(e,r),i>0&&t+n<a.length&&await t6(i)}}function id(e){for(let t of e){let e=t.codePointAt(0);if(void 0!==e&&(e<32||e>126))return!0}return!1}async function iu(e,t){let r=await p("adb",t4(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":t5(r.stdout,r.stderr)?"unsupported":0===(await p("adb",t4(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",t4(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}async function ic(e,t){let r=Math.max(0,t);await p("adb",t4(e,["shell","input","keyevent","KEYCODE_MOVE_END"]),{allowFailure:!0});for(let t=0;t<r;t+=24){let i=Math.min(24,r-t);await p("adb",t4(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function ip(e,t,r){let i,n=await r1(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=rW(i[0]),n=rK(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!d)continue;let c=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(u&&im(a)){(!o||c<=o.area)&&(o={text:d,area:c});continue}if(p&&im(a)){(!s||c<=s.area)&&(s={text:d,area:c});continue}p&&(!l||c<=l.area)&&(l={text:d,area:c})}return o?.text??s?.text??l?.text??null}function im(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function ih(e){let t=await p("adb",t4(e,["shell","dumpsys","input_method"]),{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t=function(e){let t=new Map;for(let r of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=r[1],i=r[2]?.toLowerCase();e&&("true"===i||"false"===i)&&t.set(e,"true"===i)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),r=t??!1;if(null===t){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(r=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),n=i.length>0?i[i.length-1]?.[1]:void 0,a=n?`0x${n.toLowerCase()}`:void 0;return{visible:r,inputType:a,type:a?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let r=15&t;if(2===r)return"number";if(3===r)return"phone";if(4===r)return"datetime";if(1!==r)return"unknown";let i=4080&t;return 32===i||208===i?"email":128===i||224===i||144===i?"password":"text"}(a):void 0}}(t.stdout)}async function iw(e){let t=await ih(e),r=t,i=0;for(;r.visible&&i<2;)await r6(e),i+=1,await t6(120),r=await ih(e);return{attempts:i,wasVisible:t.visible,dismissed:t.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type}}async function ig(e){let t,r;return(r=(t=(await iv(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?r[1]??"":"null"===t.trim().toLowerCase()?"":t}async function iI(e,t){await iv(e,["shell","cmd","clipboard","set","text",t],"write")}async function iv(e,t,r){let i=await p("adb",t4(e,t),{allowFailure:!0});if(t5(i.stdout,i.stderr))throw new I("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new I("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}let iA=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function iy(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new I("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function ib(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new I("INVALID_ARGS",`permission setting requires a target: ${iA.join("|")}`)}function iN(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new I("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}async function iS(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=iD(r);await p("adb",t4(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=iD(r);await p("adb",t4(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await p("adb",t4(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=iD(r);await p("adb",t4(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await iE(e,r);await p("adb",t4(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new I("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await i_(e,t);return}case"permission":{if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t=iy(r),a=function(e,t){let r=ib(e);if(t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===r)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===r)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===r)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===r)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new I("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(n?.permissionTarget,n?.permissionMode);if("notifications"===a.kind)return void await iO(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await ik(e,i,o);await p("adb",t4(e,["shell","pm",o,i,a.value]));return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function i_(e,t){var r;let i,n,a=(r=e,n=[["shell","cmd","fingerprint","touch",i="match"===t?"1":"9999"],["shell","cmd","fingerprint","finger",i]],"emulator"===r.kind&&n.push(["emu","finger","touch",i]),n),o=[];for(let t of a){let r=await p("adb",t4(e,t),{allowFailure:!0});if(0===r.exitCode)return;o.push({args:t,stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}let s=o.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(o.length>0&&o.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
16
|
+
${r}`.toLowerCase()).includes("unknown command")||i.includes("can't find service: fingerprint")||i.includes("service fingerprint was not found")||i.includes("fingerprint cmd unavailable")||i.includes("emu command is not supported")||i.includes("emulator console is not running")||i.includes("fingerprint")&&i.includes("not found")}))throw new I("UNSUPPORTED_OPERATION","Android fingerprint simulation is not supported on this target/runtime.",{deviceId:e.id,action:t,hint:"Use an Android emulator with biometric support, or a device/runtime that exposes cmd fingerprint.",attempts:s});throw new I("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:s})}function iD(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function iE(e,t){let r=iN(t);if("toggle"!==r)return r;let i=await p("adb",t4(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current Android appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
|
|
17
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"yes"===i?"dark":"no"===i?"light":"auto"===i?"auto":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current Android appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"auto"===n?"dark":"dark"===n?"light":"dark"}async function ik(e,t,r){let i=await iL(e),n=[];for(let a of null!==i&&i>=33?["android.permission.READ_MEDIA_IMAGES","android.permission.READ_EXTERNAL_STORAGE"]:["android.permission.READ_EXTERNAL_STORAGE","android.permission.READ_MEDIA_IMAGES"]){let i=await p("adb",t4(e,["shell","pm",r,t,a]),{allowFailure:!0});if(0===i.exitCode)return;n.push({permission:a,stderr:i.stderr,exitCode:i.exitCode})}throw new I("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function iO(e,t,r,i){"grant"===r?await p("adb",t4(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await p("adb",t4(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await p("adb",t4(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await p("adb",t4(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await p("adb",t4(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function iL(e){let t=await p("adb",t4(e,["shell","getprop","ro.build.version.sdk"]),{allowFailure:!0});if(0!==t.exitCode)return null;let r=Number.parseInt(t.stdout.trim(),10);return!Number.isFinite(r)||r<=0?null:r}async function iM(e,t,r){let i="string"==typeof r.action&&r.action.trim()?r.action.trim():`${t}.TEST_PUSH`,n=["shell","am","broadcast","-a",i,"-p",t],a="string"==typeof r.receiver?r.receiver.trim():"";a&&n.push("-n",a);let o=r.extras;if(void 0!==o&&("object"!=typeof o||null===o||Array.isArray(o)))throw new I("INVALID_ARGS","Android push payload extras must be an object");let s=0;for(let[e,t]of Object.entries(o??{}))e&&(function(e,t,r){if("string"==typeof r)return e.push("--es",t,r);if("boolean"==typeof r)return e.push("--ez",t,r?"true":"false");if("number"==typeof r&&Number.isFinite(r))return Number.isInteger(r)?e.push("--ei",t,String(r)):e.push("--ef",t,String(r));throw new I("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(n,e,t),s+=1);return await p("adb",t4(e,n)),{action:i,extrasCount:s}}let ix=ew(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,J,5e3),iC=ew(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,W,1e3),iR=ew(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),iT=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3),iP=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_SCREENSHOT_TIMEOUT_MS,2e4,1e3),i$=ew(process.env.AGENT_DEVICE_IOS_RUNNER_SCREENSHOT_COPY_TIMEOUT_MS,2e4,1e3);async function iF(e,t){let r=["devicectl",...e],i=await p("xcrun",r,{allowFailure:!0,timeoutMs:iT});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new I("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:iG(n,a)??iU})}async function iV(e,t){let r=n.join(V.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",r],a=await p("xcrun",i,{allowFailure:!0,timeoutMs:iT});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new I("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:i,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:iG(t,r)??iU})}let n=await x.readFile(r,"utf8");return o=function(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let r=[];for(let e of t){if(!e||"object"!=typeof e)continue;let t="string"==typeof e.bundleIdentifier?e.bundleIdentifier.trim():"";if(!t)continue;let i="string"==typeof e.name&&e.name.trim().length>0?e.name.trim():t;r.push({bundleId:t,name:i})}return r}(JSON.parse(n)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof I)throw t;throw new I("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await x.unlink(r).catch(()=>{})}}let iU="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function iG(e,t){let r=`${e}
|
|
18
|
+
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}function iB(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function ij(e,t){let r=await p("xcrun",e_(e,["get_app_container",e.id,t]),{allowFailure:!0});if(0!==r.exitCode)return{installed:!1};let i=r.stdout.trim();if(!i)return{installed:!1};let n=await p("plutil",["-extract","CFBundleExecutable","raw","-o","-",`${i}/Info.plist`],{allowFailure:!0});if(0!==n.exitCode||!n.stdout.trim())return{installed:!0};let a=n.stdout.trim(),o=`${i}/${a}`,s=await p("otool",["-l",o],{allowFailure:!0});if(0!==s.exitCode)return{installed:!0};let l=s.stdout.toLowerCase();return{installed:!0,simulatorCompatible:l.includes("iossimulator")||l.includes("platform 7")}}function iq(e,t){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function iH(){await p("open",["-a","Simulator"],{allowFailure:!0})}async function iW(e){let t,r;if("simulator"!==e.kind||"Booted"===await iz(e))return;let i=K.fromTimeoutMs(ix);try{await X(async({deadline:i})=>{if(i?.isExpired())throw new I("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:ix});let n=Math.max(1e3,i?.remainingMs()??ix),a=await p("xcrun",e_(e,["boot",e.id]),{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
|
|
19
|
+
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",e_(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await iz(e);if("Booted"!==d)throw new I("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=eu({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});return"IOS_BOOT_TIMEOUT"!==i&&"CI_RESOURCE_STARVATION_SUSPECTED"!==i}},{deadline:i,phase:"boot",classifyReason:e=>eu({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=eu({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new I("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:ix,elapsedMs:i.elapsedMs(),reason:n,hint:ec(n),boot:t,bootstatus:r})}}async function iJ(e){let t=e_(e,["shutdown",e.id]),r=await p("xcrun",t,{allowFailure:!0,timeoutMs:15e3});return{success:0===r.exitCode,exitCode:r.exitCode,stdout:String(r.stdout??""),stderr:String(r.stderr??"")}}async function iz(e){let t="string"==typeof e?e:e.id,r="string"==typeof e?eS(["list","devices","-j"]):e_(e,["list","devices","-j"]),i=await p("xcrun",r,{allowFailure:!0,timeoutMs:iC});if(0!==i.exitCode)return null;try{let e=JSON.parse(String(i.stdout??""));for(let r of Object.values(e.devices??{})){let e=r.find(e=>e.udid===t);if(e)return e.state}return null}catch{return null}}function iK(e,t,r){return p("xcrun",e_(e,t),r)}let iX={ensureBooted:iW,captureWithRetry:iQ,captureWithRunner:i0,shouldFallbackToRunner:i8};async function iY(e,t,r){if("simulator"===e.kind)return void await iZ(e,t,r);try{await iF(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(t){if(!function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
20
20
|
${r}
|
|
21
|
-
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(t))throw t;
|
|
21
|
+
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(t))throw t;i4(e,"devicectl_screenshot",t)}await i0(e,t,r)}async function iZ(e,t,r,i=iX){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");await i.ensureBooted(e);try{await i.captureWithRetry(e,t);return}catch(t){if(!i.shouldFallbackToRunner(t))throw t;i4(e,"simctl_screenshot",t)}await i.captureWithRunner(e,t,r)}async function iQ(e,t){let r=K.fromTimeoutMs(iP);await iH(),await X(async({attempt:r,deadline:i})=>{r>1&&await iH(),await iK(e,["io",e.id,"screenshot",t],{timeoutMs:Math.max(1e3,i?.remainingMs()??iP)})},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>i8(e)},{deadline:r,phase:"ios_simulator_screenshot"})}async function i0(e,t,r){let i=(await ta(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new I("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");"simulator"===e.kind?await i2(e,i,t):await i1(e,i,t)}async function i1(e,t,r){let i=K.fromTimeoutMs(i$),n={exitCode:1,stdout:"",stderr:""};for(let a of eY)if(0===(n=await p("xcrun",["devicectl","device","copy","from","--device",e.id,"--source",t,"--destination",r,"--domain-type","appDataContainer","--domain-identifier",a],{allowFailure:!0,timeoutMs:i3(i,i$,"runner screenshot copy")})).exitCode)return;let a=n.stderr.trim()||n.stdout.trim()||`devicectl exited with code ${n.exitCode}`;throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}async function i2(e,t,r){let i=K.fromTimeoutMs(i$),a="Unable to locate runner container for simulator screenshot";for(let o of eY){let s=await iK(e,["get_app_container",e.id,o,"data"],{allowFailure:!0,timeoutMs:i3(i,i$,"runner screenshot container lookup")});if(0!==s.exitCode){let e=s.stderr.trim();e&&(a=e);continue}let l=s.stdout.trim();if(!l){a="simctl get_app_container returned empty output";continue}for(let e of function(e,t){let r=n.resolve(e),i=t.trim();if(!i)return[];let a=[],o=new Set,s=e=>{let t=n.normalize(e);o.has(t)||(o.add(t),a.push(t))},l=i.replace(/^\/+/,""),d=l.replace(/\\/g,"/");if(l&&s(n.join(r,l)),n.isAbsolute(i)&&s(n.normalize(i)),d.startsWith("tmp/"))s(n.join(r,d));else{let e=d.lastIndexOf("/tmp/");if(e>=0){let t=d.slice(e+1);s(n.join(r,t))}}let u=n.basename(i);return u&&s(n.join(r,"tmp",u)),a}(l,t))try{await x.copyFile(e,r);return}catch(e){a=e instanceof Error?e.message:String(e)}}throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}function i3(e,t,r){let i=e.remainingMs();if(i>0)return i;throw new I("COMMAND_FAILED",`iOS ${r} timed out after ${t}ms`,{timeoutMs:t,step:r})}function i4(e,t,r){let i=function(e){if(!(e instanceof I))return{reason:e instanceof Error?e.message:String(e)};let t=e.details??{},r=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):void 0;return{errorCode:e.code,reason:e.message,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:void 0,exitCode:"number"==typeof t.exitCode?t.exitCode:void 0,stderr:"string"==typeof t.stderr&&t.stderr.trim()?t.stderr:void 0,stdout:"string"==typeof t.stdout&&t.stdout.trim()?t.stdout:void 0,commandArgs:r}}(r);M({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...i}})}function i8(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):"",a=`${e.message}
|
|
22
22
|
${r}
|
|
23
23
|
${i}
|
|
24
|
-
${n}`.toLowerCase();return a.includes("timeout waiting for screen surfaces")||a.includes("nsposixerrordomain")&&a.includes("code=60")&&a.includes("screenshot")||a.includes("timed out")&&a.includes("screenshot")}let
|
|
25
|
-
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:
|
|
26
|
-
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function
|
|
27
|
-
`,"utf8"),await
|
|
28
|
-
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let
|
|
29
|
-
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return
|
|
30
|
-
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}async function nA(e,t){await iB(e),await iG();let r=0,i=K.fromTimeoutMs(iL);try{await X(async({deadline:r})=>{var i;if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:iL});let n=(i=["launch",e.id,t],e_(e,i)),a=await p("xcrun",n,{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${a.exitCode}`,{cmd:"xcrun",args:n,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode})},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>!!iF(e)&&(r+=1)<3},{deadline:i})}catch(r){if(iF(r)){var n;let i=(n=await iV(e,t)).installed?!1===n.simulatorCompatible?"ARCH_MISMATCH":"PERSISTENT_LAUNCH_FAIL":"APP_NOT_INSTALLED";r.details={...r.details,hint:function(e){switch(e){case"ARCH_MISMATCH":return"The app binary was not built for the simulator platform. Rebuild with a simulator destination or use a physical device.";case"APP_NOT_INSTALLED":return"The app bundle is not installed on this simulator. Run install before open.";case"PERSISTENT_LAUNCH_FAIL":return"The simulator repeatedly refused to launch the app. Inspect crash logs in Console.app or ~/Library/Logs/DiagnosticReports/ and consider reinstalling the app.";default:return"The simulator failed to launch the app. Retry with --debug and inspect diagnostics log for details."}}(i)}}throw r}}async function ny(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await iR(i,{action:"launch iOS app",deviceId:e.id})}let nb=/^[A-Za-z0-9_.:-]{1,64}$/,nN=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function nS(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function n_(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await nD(t)}async function nD(e){await new Promise(t=>setTimeout(t,e))}function nE(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!$.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function nk(e){let t=nE(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await nO(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function nO(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}let nL=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),nM=/^(iphone|ipad|ipod|appletv)/i,nx=/^appletv/i,nC=["apple tv","appletv","tvos"];function nR(e){return(e??"").trim().toLowerCase()}function nT(e){return nR(e.hardwareProperties?.platform)}function nP(e){return e.includes("tvos")}function n$(e){return nP(nR(e))?"tv":"mobile"}function nF(e){let t=nR(e);return t.includes("ios")||t.includes("tvos")}function nV(e){let t=nR(e);return nC.some(e=>t.includes(e))}function nU(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function nG(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function nB(e={}){let t,r,i=ey(e.simulatorSetPath),n=e.target;try{t=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:i}))}catch{return null}try{r=JSON.parse(t.stdout)}catch{return null}let a=null,o=null,s=null;for(let[e,t]of Object.entries(r.devices)){if(!nF(e))continue;let r=n$(e);if(!n||r===n)for(let e of t){if(!e.isAvailable)continue;let t={platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:r,booted:"Booted"===e.state,...i?{simulatorSetPath:i}:{}};t.booted&&(a=a??t),"mobile"===r&&(o=o??t),s=s??t}}return a??o??s}async function nj(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await A("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=ey(e.simulatorSetPath),i=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(nF(i))for(let e of n)e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:n$(i),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let a=null;try{a=n.join(V.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",a],{allowFailure:!0,timeoutMs:nL});if(0!==e.exitCode)return t;let r=await x.readFile(a,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=nT(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=nG(e),!!nM.test(t.trim())||nU(e).some(nV))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return nP(nT(e))?"tv":(t=nG(e),nx.test(t.trim())||nU(e).some(nV))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{a&&await x.rm(a,{force:!0}).catch(()=>{})}return t}async function nq(e,t,r,i){let n,a=!!(t.udid||t.serial||t.deviceName);try{n=await i.selectDevice(e,t,r)}catch(e){if(a||!(e instanceof I)||"DEVICE_NOT_FOUND"!==e.code)throw e}if(!a&&(!n||"device"===n.kind)){let e=await i.findBootableSimulator({simulatorSetPath:r.simulatorSetPath,target:t.target});if(e)return e}if(n)return n;throw new I("DEVICE_NOT_FOUND","No devices found",{selector:t})}async function nH(e){let t=ej(e.platform),r=ey(e.iosSimulatorDeviceSet),i=eN(e.androidDeviceAllowlist);return await L("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await t8();let e=await rc({serialAllowlist:i});return await eq(e,n)}if("ios"===n.platform){let e=await nj({simulatorSetPath:r});return await nq(e,n,{simulatorSetPath:r},{selectDevice:eq,findBootableSimulator:nB})}let a=[];try{a.push(...await rc({serialAllowlist:i}))}catch{}try{a.push(...await nj({simulatorSetPath:r}))}catch{}return await eq(a,n,{simulatorSetPath:r})},{platform:t,target:e.target})}async function nW(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>rL(e,t,r?.activity),openDevice:()=>rx(e),close:t=>rC(e,t),tap:(t,r)=>r1(e,t,r),doubleTap:async(t,r)=>{await r1(e,t,r),await r1(e,t,r)},swipe:(t,r,i,n,a)=>r2(e,t,r,i,n,a),longPress:(t,r,i)=>r5(e,t,r,i),focus:(t,r)=>r9(e,t,r),type:t=>r6(e,t),fill:(t,r,i)=>r7(e,t,r,i),scroll:(t,r)=>ie(e,t,r),scrollIntoView:t=>it(e,t),screenshot:(t,r)=>rX(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>nt(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>nr(e),close:t=>ni(e,t),screenshot:(t,r)=>iJ(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(es(i.requestId))throw el()},{tap:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await ta(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await ta(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await ta(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await ta(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await ta(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await ta(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await ta(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await L("platform_command",async()=>{switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(t9(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=nS(a?.count??1,"count",1,200),s=nS(a?.intervalMs??0,"interval-ms",0,1e4),l=nS(a?.holdMs??0,"hold-ms",0,1e4),d=nS(a?.jitterPx??0,"jitter-px",0,100),u=a?.doubleTap===!0;if(u&&l>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(u&&d>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if("ios"===e.platform&&n>1&&0===l&&0===d)return await ta(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:s,doubleTap:u,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u,timingMode:"runner-series"};return await n_(n,s,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=nN[e%nN.length];return[r*t,i*t]}(e,d),a=t+r,s=i+n;u?await o.doubleTap(a,s):l>0?await o.longPress(a,s,l):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=nS(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=nS(a?.count??1,"count",1,200),c=nS(a?.pauseMs??0,"pause-ms",0,1e4),p=a?.pattern??"one-way";if("one-way"!==p&&"ping-pong"!==p)throw new I("INVALID_ARGS",`Invalid pattern: ${p}`);if("ios"===e.platform&&u>1)return await ta(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:c,pattern:p,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:c,pattern:p};return await n_(u,c,async e=>{"ping-pong"===p&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:c,pattern:p}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await ta(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!nb.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await ta(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await r3(e),{action:"back"};case"home":if("ios"===e.platform)return await ta(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await r4(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await ta(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await r8(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await ns(e):await ip(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await nl(e,i):await im(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await ic(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await iu(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await nu(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await iA(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await nk(i);if("ios"===e.platform)return await nd(e,t,n),{platform:"ios",bundleId:t};let a=await iE(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await L("snapshot_capture",async()=>await ta(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await L("snapshot_capture",async()=>await rz(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let nJ={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},install:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function nz(e,t){let r=nJ[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function nK(e,t,r,i,n){return{requestId:n??O().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let nX=ew(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function nY(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:iB}));await t(e);return}if("device"===e.kind)return void await nZ(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:rI}));await t(e.id)}}async function nZ(e){let t=n.join(V.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(nX/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:nX+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await nQ(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:n0(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??nX),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?n0(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function nQ(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function n0(e,t){let r=i$(e,t);return r||(`${e}
|
|
31
|
-
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":iP)}function n1(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function n2(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function n3(e,t){return e.find(e=>e.ref===t)??null}function n4(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function n8(e,t){let r=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),i=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(r)||i.includes(r)||n.includes(r)})??null}function n5(e,t){let r=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return r&&n6(r)?r:function(e,t){if(!e.rect)return;let r=e.rect.y+e.rect.height/2,i=null;for(let e of t){if(!e.rect)continue;let t=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);if(!t||!n6(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-r);(!i||n<i.distance)&&(i={label:t,distance:n})}return i?.label}(e,t)??(r&&n6(r)?r:void 0)}function n6(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function n9(e){let t=[],r=[];for(let i of e){let e=i.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=n7(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&n6(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);r.push({...i,depth:s})}return r}function n7(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),r=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==r&&(t=t.slice(r+1)),t}function ae(e,t){let r=n7(e);return!r||("android"===t?r.includes("edittext")||r.includes("autocompletetextview"):r.includes("textfield")||r.includes("securetextfield")||r.includes("searchfield")||r.includes("textview")||r.includes("textarea")||"search"===r)}function at(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let ar=new Set(["id","role","text","label","value"]),ai=new Set(["visible","hidden","editable","selected","enabled","hittable"]),an=new Set([...ar,...ai]);function aa(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aN(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aN(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(ah)}})(e))}}function ao(e){try{return aa(e)}catch{return null}}function as(e,t,r){let i=r.requireRect??!1,n=r.requireUnique??!0,a=r.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,r){let i=0,n=null,a=null,o=!1;for(let s of e){if(r.requireRect&&!s.rect||!aw(s,t,r.platform))continue;if(i+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let r=e.depth??0,i=t.depth??0;if(r!==i)return r>i?1:-1;let n=ab(e),a=ab(t);return n!==a?n<a?1:-1:0}(s,a);if(e>0){a=s,o=!1;continue}0===e&&(o=!0)}return{count:i,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:r.platform,requireRect:i});if(o.push({selector:l.raw,matches:d.count}),0!==d.count&&d.firstNode){if(n&&1!==d.count){if(!a)continue;let e=d.disambiguated;if(!e)continue;return{node:e,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}return{node:d.firstNode,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}}return null}function al(e,t,r){let i=r.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,r){let i=0;for(let n of e)(!r.requireRect||n.rect)&&aw(n,t,r.platform)&&(i+=1);return i}(e,o,{platform:r.platform,requireRect:i});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function ad(e,t,r){let i=r.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return i?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function au(e,t={}){if(0===e.length)return null;let r=t.preferTrailingValue??!1,i=0,n=[];for(;i<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let r=t.indexOf("=");if(-1!==r){let e=t.slice(0,r).trim().toLowerCase();return an.has(e)}return an.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&ao(t)&&n.push(i)}if(0===n.length)return null;let a=n[n.length-1];if(r){for(let t=n.length-1;t>=0;t-=1)if(n[t]<e.length){a=n[t];break}}let o=e.slice(0,a).join(" ").trim();return o?{selectorExpression:o,rest:e.slice(a)}:null}function ac(e){let t=e[0]??"",r=au(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function ap(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function af(e,t){return ae(e.type??"",t)&&!1!==e.enabled}function am(e,t,r={}){let i=[],n=n7(e.type??""),a=ay(e.identifier),o=ay(e.label),s=ay(e.value),l=ay(at(e)),d="fill"===r.action;a&&i.push(`id=${aA(a)}`),n&&o&&i.push(d?`role=${aA(n)} label=${aA(o)} editable=true`:`role=${aA(n)} label=${aA(o)}`),o&&i.push(d?`label=${aA(o)} editable=true`:`label=${aA(o)}`),s&&i.push(d?`value=${aA(s)} editable=true`:`value=${aA(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${aA(l)} editable=true`:`text=${aA(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${aA(n)} editable=true`);let u=tl(i);return 0===u.length&&n&&u.push(d?`role=${aA(n)} editable=true`:`role=${aA(n)}`),0===u.length&&ap(e)&&u.push("visible=true"),u}function ah(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!ai.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!an.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(ai.has(i)){let e,t="true"===(e=ag(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:ag(n)}}function aw(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return aI(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return n7(e)}(i??"")===function(e){return n7(e)}(n);case"label":return aI(e.label,String(t.value));case"value":return aI(e.value,String(t.value));case"text":{let r=av(String(t.value));return av(at(e))===r}case"visible":return ap(e)===!!t.value;case"hidden":return!ap(e)==!!t.value;case"editable":return af(e,r)===!!t.value;case"selected":return!0===e.selected==!!t.value;case"enabled":return!1!==e.enabled==!!t.value;case"hittable":return!0===e.hittable==!!t.value;default:return!1}})(e,t,r))}function ag(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function aI(e,t){return av(e??"")===av(t)}function av(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function aA(e){return JSON.stringify(e)}function ay(e){if(!e)return null;let t=e.trim();return t||null}function ab(e){return e.rect?e.rect.width*e.rect.height:1/0}function aN(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}let aS=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),a_=/https?:\/\/[^\s"'<>\])]+/i,aD=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function aE(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function ak(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return aO(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function aO(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function aL(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function aM(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let ax="shared_prefs/ReactNativeDevPrefs.xml",aC="debug_http_host",aR="dev_server_https",aT="RCT_jsLocation",aP="RCT_packager_scheme",a$="React Native runtime hints require adb run-as access to the app sandbox. Verify the app is debuggable and the selected package/device are correct.",aF='<?xml version="1.0" encoding="utf-8" standalone="yes" ?>\n<map>\n</map>\n';function aV(e){return void 0!==aU(e)}function aU(e){if(!e)return;let t=aZ(e.metroHost),r=aQ(e.metroPort),i="http",n=aZ(e.bundleUrl);if(n){var a;let e;try{e=new v(n)}catch(e){throw new I("INVALID_ARGS",`Invalid runtime bundle URL: ${n}`,{},e)}("http:"===e.protocol||"https:"===e.protocol)&&(t??=aZ(e.hostname),r??=aQ(e.port.length>0?Number(e.port):"https:"===(a=e.protocol)?443:"http:"===a?80:void 0),i="https:"===e.protocol?"https":"http")}if(t&&r)return{host:t,port:r,scheme:i}}async function aG(e){let{device:t,appId:r,runtime:i}=e;if(!r)return;let n=aU(i);if(n){if("android"===t.platform)return void await aj(t,r,n);"ios"===t.platform&&"simulator"===t.kind&&await aJ(t,r,n)}}async function aB(e){let{device:t,appId:r}=e;if(r){if("android"===t.platform)return void await aq(t,r);"ios"===t.platform&&"simulator"===t.kind&&await az(t,r)}}async function aj(e,t,r){var i,n,a,o,s,l;let d,u,c=(i=await aH(e,t),n=aC,a=`${r.host}:${r.port}`,d=` <string name="${a0(n)}">${a0(a)}</string>`,aX(aY(i,n),d));o=c,s=aR,l="https"===r.scheme,u=` <boolean name="${a0(s)}" value="${l?"true":"false"}" />`,c=aX(aY(o,s),u),await aW(e,t,c)}async function aq(e,t){let r=await aH(e,t),i=aY(r,aC),n=aY(i,aR);n!==r&&await aW(e,t,n)}async function aH(e,t){let r=await p("adb",t4(e,["shell","run-as",t,"cat",ax]),{allowFailure:!0});return 0!==r.exitCode?aF:aK(r.stdout)}async function aW(e,t,r){let i=t4(e,["shell","run-as",t,"id"]),n=await p("adb",i,{allowFailure:!0});if(0!==n.exitCode){let e=a1(n.stdout,n.stderr);throw new I("COMMAND_FAILED",e?`Failed to access Android app sandbox for ${t}`:`Failed to probe Android app sandbox for ${t}`,{package:t,cmd:"adb",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:e?a$:"adb shell run-as probe failed. Check adb connectivity and that the device is reachable. Inspect stderr/details for more information."})}let a=`mkdir -p shared_prefs && cat > ${ax}`,o=t4(e,["shell","run-as",t,"sh","-c",`'${a}'`]);try{await p("adb",o,{stdin:r.trimEnd()})}catch(i){let e=w(i);if("TOOL_MISSING"===e.code)throw e;let r=a1("string"==typeof e.details?.stdout?e.details.stdout:"","string"==typeof e.details?.stderr?e.details.stderr:"");throw new I("COMMAND_FAILED",r?`Failed to access Android app sandbox for ${t}`:`Failed to write Android runtime hints for ${t}`,{...e.details??{},package:t,cmd:"adb",args:o,phase:"write-runtime-hints",hint:r?a$:"adb run-as succeeded, but writing ReactNativeDevPrefs.xml failed. Inspect stderr/details for the failing shell command."},e)}}async function aJ(e,t,r){await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aT,"-string",`${r.host}:${r.port}`])),await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aP,"-string",r.scheme]))}async function az(e,t){await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aT]),{allowFailure:!0}),await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aP]),{allowFailure:!0})}function aK(e){let t=e.trim();return t.includes("<map")&&t.includes("</map>")?`${t}
|
|
32
|
-
`:
|
|
33
|
-
</map>`)}function
|
|
34
|
-
${t}`.toLowerCase();return["run-as: package not debuggable","run-as: permission denied","run-as: package is unknown","run-as: unknown package","is unknown","is not an application","could not set capabilities"].some(e=>r.includes(e))}function a2(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=au(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function a3(e){return!!e&&!Number.isNaN(Number(e))}async function a4(e){let t,r,i,{deviceName:n,runtime:a,simulatorSetPath:o,reuseExisting:s,boot:l,ensureReady:d}=e;if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","ensure-simulator is only available on macOS");let u={simulatorSetPath:o??void 0};if(s){let e=await a8({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await a5({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a6(t,u),i=!0)}else t=(await a5({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await a6(t,u),i=!0;let c=!1;if(l){let e={platform:"ios",id:t,name:n,kind:"simulator",target:"mobile",...o?{simulatorSetPath:o}:{}};await d(e),c=!0}return{udid:t,device:n,runtime:r,created:i,booted:c}}async function a8(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",eS(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:iO});if(0!==n.exitCode)return null;try{let e=JSON.parse(String(n.stdout??""));for(let[i,n]of Object.entries(e.devices??{}))if(!r||a9(i).includes(a9(r))){for(let e of n)if(e.isAvailable&&e.name.toLowerCase()===t.toLowerCase())return{udid:e.udid,runtime:i}}return null}catch{return null}}async function a5(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",eS(n,i),{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED","Failed to create iOS simulator",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode,hint:"Ensure the device type and runtime identifiers are valid. Run `xcrun simctl list devicetypes` and `xcrun simctl list runtimes` to see available options."});let o=String(a.stdout??"").trim();if(!o)throw new I("COMMAND_FAILED","simctl create returned no UDID",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??"")});return{udid:o}}async function a6(e,t){let r=await p("xcrun",eS(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:iO});if(0!==r.exitCode)return"";try{let t=JSON.parse(String(r.stdout??""));for(let[r,i]of Object.entries(t.devices??{}))if(i.some(t=>t.udid===e))return r;return""}catch{return""}}function a9(e){return e.toLowerCase().replace(/[._-]/g,"")}let a7='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',oe=["platform","target","device","udid","serial","verbose","out"],ot=["platform","target","device","udid","serial","verbose","out"],or=["path","start","stop","doctor","mark","clear"],oi=`logs requires ${or.slice(0,-1).join(", ")}, or ${or.at(-1)}`,on="Not implemented for this platform in this release.",oa="open-command-roundtrip",oo=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),os=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function ol(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a,runtime:o}=e,s={session:t};return r&&(s.appName=r),i&&(s.appBundleId=i),n&&(s.startup=n),o&&od(o)>0&&(s.runtime=o),a?.platform==="ios"&&(s.device_udid=a.id,s.ios_simulator_device_set=a.simulatorSetPath??null),s}function od(e){return e?[e.metroHost,e.metroPort,e.bundleUrl,e.launchUrl].filter(e=>void 0!==e&&""!==e).length:0}function ou(e){let t=e?.trim();return t&&t.length>0?t:void 0}function oc(e,t,r){let i=e.getRuntimeHints(t);if(i){if(i.platform&&r&&i.platform!==r.platform)throw new I("INVALID_ARGS",`Session runtime hints target ${i.platform}, but session "${t}" is bound to ${r.platform}. Clear the runtime hints or use a different session.`);return r?.platform&&i.platform!==r.platform?{...i,platform:r.platform}:i}}async function op(e){let{runtime:t,device:r,dispatch:i,req:n,logPath:a,appBundleId:o,traceLogPath:s,openPositionals:l}=e,d=t?.launchUrl;if(!d||0===l.length||l.length>1)return;let u=l[0]?.trim();!u||t9(u)||await i(r,"open",[d],n.flags?.out,{...nK(a,n.flags,o,s)})}function of(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:oa,appTarget:t,appBundleId:r}}let om=["dump","log"],oh=`network requires ${om.join(" or ")}`,ow=["summary","headers","body","all"],og=`network include mode must be one of: ${ow.join(", ")}`;function oI(e,t,r){return t||ov(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function ov(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function oA(e){return"ios"===e.platform&&"simulator"===e.kind}async function oy(e,t){oA(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function ob(e){let{device:t,closeTarget:r,stopIosRunner:i,dispatch:n,outFlag:a,context:o,settleSimulator:s}=e;"ios"===t.platform&&await i(t.id),await n(t,"close",[r],a,o),await s(t,oo)}async function oN(e){let t=ov(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function oS(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let o_=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:rg}));return await i({avdName:e,serial:t,headless:r})};async function oD(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=oI(l,p,f);if(m)return m;let h=await oN({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nz(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...nK(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let oE={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:no}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:rG}));return await i(e,t,r)}},ok={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:na}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await oC(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:rU}));await i(e,r);let{package:n}=await oC(e,t);return n?{package:n}:{}}};async function oO(e){let{req:t,command:r,sessionName:i,sessionStore:n,ensureReady:a,resolveDevice:o,deployOps:s}=e,l=n.get(i),d=t.flags??{},u=oI(r,l,d);if(u)return u;let c=t.positionals?.[0]?.trim(),p=t.positionals?.[1]?.trim();if(!c||!p)return{ok:!1,error:{code:"INVALID_ARGS",message:`${r} requires: ${r} <app> <path-to-app-binary>`}};let f=t.meta?.uploadedArtifactId;try{let e,i=f?function(e,t){let r=tT.get(e);if(!r)throw new I("INVALID_ARGS",`Uploaded artifact not found: ${e}`);if(r.tenantId&&r.tenantId!==t)throw new I("UNAUTHORIZED","Uploaded artifact belongs to a different tenant");return clearTimeout(r.timer),r.artifactPath}(f,t.meta?.tenantId):tw.expandHome(p);if(!$.existsSync(i))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${i}`}};let u=await oN({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!1});if(!nz(r,u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}};if("ios"===u.platform){let t=(await s.ios(u,c,i)).bundleId;e=t?{app:c,appPath:i,platform:"ios",appId:t,bundleId:t}:{app:c,appPath:i,platform:"ios"}}else{let t=(await s.android(u,c,i)).package;e=t?{app:c,appPath:i,platform:"android",appId:t,package:t}:{app:c,appPath:i,platform:"android"}}return l&&n.recordAction(l,{command:r,positionals:t.positionals??[],flags:t.flags??{},result:e}),{ok:!0,data:e}}finally{f&&tP(f)}}async function oL(e,t,r){if("ios"===e.platform&&t)return t9(t)?"device"===e.kind?t7(r,t):void 0:await oM(e,t)}async function oM(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:ne}));return await r(e,t)}catch{return}}async function ox(e,t){if(!("android"!==e.platform||!t||t9(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:rN})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function oC(e,t){return"ios"===e.platform?{bundleId:await oM(e,t)}:{package:await ox(e,t)}}async function oR(e,t,r,i){return await oL(e,t,r)??await i(e,t)??("android"===e.platform&&t&&t9(t)?r:void 0)}async function oT(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=ej(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=oI("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!ov(e))return!0;let r=ej(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a7}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session",device_udid:o.device.id,ios_simulator_device_set:o.device.simulatorSetPath??null}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await oN({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:a7}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:rk})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function oP(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=oI("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await oN({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nz("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...nK(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function o$(e){var t,r;let{req:i,sessionName:n,logPath:a,sessionStore:o,invoke:s,dispatch:l,ensureReady:d,resolveTargetDevice:u,installOps:c=ok,reinstallOps:p=oE,stopIosRunner:f,appLogOps:m={start:tO,stop:tL},ensureAndroidEmulatorBoot:h=o_,resolveAndroidPackageForOpen:g=ox,applyRuntimeHints:v=aG,clearRuntimeHints:A=aB,settleSimulator:y,shutdownSimulator:b}=e,N=l??nW,S=d??nY,D=u??nH,E=f??e9,k=y??oy,O=i.command;if("session_list"===O)return{ok:!0,data:{sessions:o.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.id,ios_simulator_device_set:e.device.simulatorSetPath??null}}))}};if("runtime"===O){let e,a=(i.positionals?.[0]??"show").toLowerCase(),s=o.get(n),l=o.getRuntimeHints(n);if(!["set","show","clear"].includes(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime requires set, show, or clear"}};if("clear"===a){aV(l)&&s?.appBundleId&&await A({device:s.device,appId:s.appBundleId});let e=o.clearRuntimeHints(n);return{ok:!0,data:{session:n,cleared:e}}}if("show"===a)return{ok:!0,data:{session:n,configured:!!l,runtime:l}};let d=ej(i.flags?.platform)??l?.platform??s?.device.platform;if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires --platform when the session has not been opened yet."}};if(s&&s.device.platform!==d)return{ok:!1,error:{code:"INVALID_ARGS",message:`runtime set targets ${d}, but session "${n}" is already bound to ${s.device.platform}.`}};let u={platform:(t=i.flags,e=t?.metroPort,r={platform:d,metroHost:ou(t?.metroHost),metroPort:Number.isInteger(e)?e:void 0,bundleUrl:ou(t?.bundleUrl),launchUrl:ou(t?.launchUrl)}).platform??l?.platform,metroHost:r.metroHost??l?.metroHost,metroPort:r.metroPort??l?.metroPort,bundleUrl:r.bundleUrl??l?.bundleUrl,launchUrl:r.launchUrl??l?.launchUrl};return 0===od(u)?{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires at least one hint such as --metro-host, --metro-port, --bundle-url, or --launch-url."}}:(o.setRuntimeHints(n,u),{ok:!0,data:{session:n,configured:!0,runtime:u}})}if("ensure-simulator"===O)try{let e=i.flags??{},t=e.device,r=e.runtime,n=ey(e.iosSimulatorDeviceSet);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await a4({deviceName:t,runtime:r,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:S});return{ok:!0,data:{udid:s.udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:n??null,created:s.created,booted:s.booted}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("devices"===O)try{let e=[],t=ey(i.flags?.iosSimulatorDeviceSet),r=eN(i.flags?.androidDeviceAllowlist),n=ej(i.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:rc}));e.push(...await t({serialAllowlist:r}))}else if("ios"===n){let{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:nj}));e.push(...await r({simulatorSetPath:t}))}else{let{listAndroidDevices:i}=await Promise.resolve().then(()=>({listAndroidDevices:rc})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:nj}));try{e.push(...await i({serialAllowlist:r}))}catch{}try{e.push(...await n({simulatorSetPath:t}))}catch{}}let a=(i.flags?.target?e.filter(e=>(e.target??"mobile")===i.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===O){let e=o.get(n),t=i.flags??{},r=oI(O,e,t);if(r)return r;let a=await oN({session:e,flags:t,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!0});if(!nz("apps",a))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=i.flags?.appsFilter??"all";if("ios"===a.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:nc}));return{ok:!0,data:{apps:(await e(a,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:rS}));return{ok:!0,data:{apps:(await l(a,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===O){let e,t=o.get(n),r=i.flags??{},a=oI(O,t,r);if(a)return a;let s="android"===(ej(r.platform)??t?.device.platform),l=!0===r.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=oS({flags:r,sessionDevice:t?.device}),u=s&&!!d,c=!1;try{e=await oN({session:t,flags:r,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!1})}catch(i){let t=w(i);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw i;e=await h({avdName:d,serial:r.serial,headless:l}),c=!0}if(r.target&&(e.target??"mobile")!==r.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${r.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let i=oS({flags:r,sessionDevice:t?.device,resolvedDevice:e});if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await h({avdName:i,serial:r.serial,headless:!0})}await S(e)}else("android"!==e.platform||!0!==e.booted)&&await S(e);return nz("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===O)return await oT({req:i,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D});if("clipboard"===O)return await oP({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N});if("keyboard"===O)return await oD({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"keyboard",positionals:i.positionals??[]});if("perf"===O){let e,t,r,i=o.get(n);return i?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===oa&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:oa,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(i.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:oa,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:oa},{session:i.name,platform:i.device.platform,device:i.device.name,deviceId:i.device.id,metrics:{startup:r,fps:{available:!1,reason:on},memory:{available:!1,reason:on},cpu:{available:!1,reason:on}},sampling:{startup:{method:oa,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("install"===O||"reinstall"===O)return await oO({req:i,command:O,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D,deployOps:"install"===O?c:p});if("push"===O){let e,t=i.positionals?.[0]?.trim(),r=i.positionals?.[1]?.trim();if(!t||!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=nE(r,{subject:"Push payload",cwd:i.meta?.cwd,expandPath:(e,t)=>tw.expandHome(e,t)})).kind?e.path:e.text;return await oD({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"push",positionals:[t,s],recordPositionals:[t,r]})}if("trigger-app-event"===O)return await oD({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"trigger-app-event",positionals:i.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await oR(e.device,r,e.appBundleId,g)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===O){let e=i.flags?.relaunch===!0;if(o.has(n)){let t=o.get(n),r=i.positionals?.[0],s=r??(e?t?.appName:void 0);if(!t||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&t9(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await S(t.device);let l=oc(o,n,t?.device),d=await oR(t.device,s,t.appBundleId,g),u=r?i.positionals??[]:[s];if(e){let e=d??s;await ob({device:t.device,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nK(a,i.flags,d??t.appBundleId,t.trace?.outPath)},settleSimulator:k})}await v({device:t.device,appId:d,runtime:l});let c=Date.now();await N(t.device,"open",u,i.flags?.out,{...nK(a,i.flags,d)}),await op({runtime:l,device:t.device,dispatch:N,req:i,logPath:a,appBundleId:d,traceLogPath:t.trace?.outPath,openPositionals:u});let p=of(c,s,d);await k(t.device,os);let f={...t,appBundleId:d,appName:s,recordSession:t.recordSession||!!i.flags?.saveScript,snapshot:void 0},m=ol({sessionName:n,appName:s,appBundleId:d,startup:p,device:t.device,runtime:l});return o.recordAction(f,{command:O,positionals:u,flags:i.flags??{},result:m}),o.set(n,f),{ok:!0,data:m}}let t=i.positionals?.[0];if(e&&!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&t&&t9(t))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let r=await D(i.flags??{}),s=o.toArray().find(e=>e.device.id===r.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:r.id,deviceName:r.name}}};await S(r);let l=oc(o,n,r),d=await oR(r,t,void 0,g);if(e&&t){let e=d??t;await ob({device:r,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nK(a,i.flags,d)},settleSimulator:k})}await v({device:r,appId:d,runtime:l});let u=Date.now();await N(r,"open",i.positionals??[],i.flags?.out,{...nK(a,i.flags,d)}),await op({runtime:l,device:r,dispatch:N,req:i,logPath:a,appBundleId:d,openPositionals:i.positionals??[]});let c=t?of(u,t,d):void 0;await k(r,os);let p={name:n,device:r,createdAt:Date.now(),appBundleId:d,appName:t,recordSession:!!i.flags?.saveScript,actions:[]},f=ol({sessionName:n,appName:t,appBundleId:d,startup:c,device:r,runtime:l});return o.recordAction(p,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:f}),o.set(n,p),{ok:!0,data:f}}if("replay"===O){let e=i.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=tw.expandHome(e,i.meta?.cwd),r=$.readFileSync(t,"utf8"),l=r.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(tp(i)){let e=th(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return a3(r)&&a3(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=th(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(r),u=i.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let r=d[e];if(!r||"replay"===r.command)continue;let l=await s({token:i.token,session:n,command:r.command,positionals:r.positionals??[],flags:oG(i.flags,r.flags),meta:i.meta});if(l.ok)continue;if(!u)return oU(l,r,e,t);let p=await oB({action:r,sessionName:n,logPath:a,sessionStore:o,dispatch:N});if(!p)return oU(l,r,e,t);if(d[e]=p,!(l=await s({token:i.token,session:n,command:p.command,positionals:p.positionals??[],flags:oG(i.flags,p.flags),meta:i.meta})).ok)return oU(l,p,e,t);c+=1}if(u&&c>0){let e=o.get(n);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",tf(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(tf(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(tf(r));return tm(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
35
|
-
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;$.writeFileSync(a,n),$.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:n}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(i.positionals?.[0]??"path").toLowerCase(),r=!!i.flags?.restart;if(!
|
|
36
|
-
`,$.appendFileSync(r,e,"utf8"),{ok:!0,data:{path:r,marked:!0}}}if("clear"===t){if(e.appLog&&!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(r){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!nz("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=o.resolveAppLogPath(n);if(r){e.appLog&&await m.stop(e.appLog);let r=tx(t),i=o.resolveAppLogPidPath(n);try{let a=await m.start(e.device,e.appBundleId,t,i),s={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return o.set(n,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=_(r);return o.set(n,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:tx(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!nz("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=o.resolveAppLogPath(n),r=o.resolveAppLogPidPath(n);try{let i=await m.start(e.device,e.appBundleId,t,r),a={...e,appLog:{platform:e.device.platform,backend:i.backend,outPath:t,startedAt:i.startedAt,getState:i.getState,stop:i.stop,wait:i.wait}};return o.set(n,a),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:_(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await m.stop(e.appLog),o.set(n,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(i.positionals?.[0]??"dump").toLowerCase();if(!om.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:oh}};let r=i.positionals?.[1],a=r?Number.parseInt(r,10):25;if(!Number.isInteger(a)||a<1||a>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(i.positionals?.[2]??"summary").toLowerCase();if(!ow.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:og}};let l=function(e,t){let r=aM(t?.maxEntries,25,1,200),i=t?.include??"summary",n=aM(t?.maxPayloadChars,2048,64,16384),a=aM(t?.maxScanLines,4e3,100,2e4);if(!$.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=$.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=aE(n,["method","httpMethod"]),o=aE(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=aS.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=a_.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of aD){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:aL(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return aO(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=aL(t,i))}if("body"===r||"all"===r){let t=ak(e,n,["requestBody","body","payload","request"]),r=ak(e,n,["responseBody","response"]);t&&(f.requestBody=aL(t,i)),r&&(f.responseBody=aL(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(o.resolveAppLogPath(n),{maxEntries:a,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===O)return await oF(i,n,s);if("close"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await m.stop(e.appLog),i.positionals&&i.positionals.length>0&&("ios"===e.device.platform&&await E(e.device.id),await N(e.device,"close",i.positionals,i.flags?.out,{...nK(a,i.flags,e.appBundleId,e.trace?.outPath)}),await k(e.device,oo)),"ios"===e.device.platform&&await E(e.device.id),aV(o.getRuntimeHints(n))&&e.appBundleId&&await A({device:e.device,appId:e.appBundleId}).catch(()=>{}),o.recordAction(e,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:{session:n}}),i.flags?.saveScript&&(e.recordSession=!0),o.writeSessionLog(e),o.delete(n),i.flags?.shutdown&&oA(e.device)){let t;try{t=await (b??ij)(e.device)}catch(r){let e=_(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:n,shutdown:t}}}return{ok:!0,data:{session:n}}}return null}async function oF(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??C;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=c(e.flags?.batchSteps,n),a=Date.now(),o=[];for(let n=0;n<i.length;n+=1){let a=i[n],s=await oV(e,t,a,r,n+1);if(!s.ok)return{ok:!1,error:{code:s.error.code,message:`Batch failed at step ${s.step} (${a.command}): ${s.error.message}`,hint:s.error.hint,diagnosticId:s.error.diagnosticId,logPath:s.error.logPath,details:{...s.error.details??{},step:s.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:o}}};o.push(s.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:o}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function oV(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of oe)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function oU(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>tf(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function oG(e,t){let r={...t??{}},i=e??{};for(let e of ot)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function oB(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(tp(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=tp(t.command)||"fill"===t.command,l=tp(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await oj(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),tp(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=ac(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=a2(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return tl(t).filter(e=>e.trim().length>0)}(t)){let r=ao(e);if(!r)continue;let i=as(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=am(i.node,o.device.platform,{action:tp(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(tp(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ts(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=ac(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=a2(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=ao(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(n7(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=at(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(n7(e.type??"")))});if(0===s.length||1!==tl(s.map(e=>at(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=am(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function oj(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nK(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:n1(t.flags?.snapshotRaw?s:n9(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function oq(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function oH(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function oW(e,t){return t.flatten?e.map(e=>({text:i(e,0,!1),comparable:oH(e,0)})):y(e).map(e=>({text:e.text,comparable:oH(e.node,e.depth)}))}function oJ(e,t){return e.get(t)??0}async function oz(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??nW,o=e.runnerCommand??ta,s=t.command;if("snapshot"===s){let{session:e,device:o}=await oY(n,r,t.flags);if(!nz("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=oX(t.flags?.snapshotScope,e);return s.ok?await oZ(e,o,async()=>{let l=e?.appBundleId,d=await oK({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return oQ(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===s){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await oY(n,r,t.flags);if(!nz("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=oX(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await oZ(e,o,async()=>{let d=e?.appBundleId,u=(await oK({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return oW(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return oQ(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&oJ(a,n-1)<oJ(a,n+1)?oJ(a,n+1):oJ(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&oJ(n,l-1)<oJ(n,l+1)?l+1:l-1,u=oJ(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(oW(e,r),oW(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return oQ(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===s){let{session:e,device:o}=await oY(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=oq(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=oq(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=oq(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=oq(e[e.length-1]),i=au(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=ao(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),oQ(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):nz("wait",o)?await oZ(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...nK(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=n1(t.flags?.snapshotRaw?u:n9(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=al(c,s.selector,{platform:o.platform});if(p)return oQ(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=n2(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=n3(e.snapshot.nodes,t),i=r?n5(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await ta(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return oQ(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&n8(n1((await rz(o,{scope:l})).nodes??[]),l))return oQ(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===s){let{session:e,device:a}=await oY(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return nz("alert",a)?await oZ(e,a,async()=>{if("wait"===s){let r=oq(t.positionals?.[1])??1e4,s=Date.now();for(;Date.now()-s<r;){try{let r=await o(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return oQ(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r="accept"===s||"dismiss"===s?s:"get",l={verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId};if("accept"===r||"dismiss"===r){let i,s=Date.now();for(;Date.now()-s<2e3;){try{let i=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oQ(n,e,t,i),{ok:!0,data:i}}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await new Promise(e=>setTimeout(e,300))}throw i}let d=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return oQ(n,e,t,d),{ok:!0,data:d}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===s){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:f}};let{session:s,device:l}=await oY(n,r,t.flags);return nz("settings",l)?await oZ(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await nW(l,"settings",d,t.flags?.out,{...nK(i,t.flags,r,s?.trace?.outPath)});return oQ(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function oK(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nK(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:n1(n.flags?.snapshotRaw?l:n9(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function oX(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=n2(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=n3(t.snapshot.nodes,r),n=i?n5(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function oY(e,t,r){let i=e.get(t),n=i?.device??await nH(r??{});return i||await nY(n),{session:i,device:n}}async function oZ(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await e9(t.id)}}function oQ(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function o0(e,t,r,i={}){let n=o2(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return o1(e.label,r);case"value":return o1(e.value,r);case"id":return o1(e.identifier,r);default:return Math.max(o1(e.label,r),o1(e.value,r),o1(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function o1(e,t){let r=o2(e??"");return r?r===t?2:+!!r.includes(t):0}function o2(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function o3(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??nW,s=t.command;if("find"!==s)return null;let l=t.positionals??[];if(0===l.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:d,query:u,action:c,value:p,timeoutMs:f}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:oq(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(l);if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(r);if(!m&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await nH(t.flags??{});m||await nY(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,b=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nK(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=n1(t.flags?.snapshotRaw?s:n9(s));return A=e,y=l,m&&(m.snapshot={nodes:l,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,m)),{nodes:l,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=f??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await b();if(o0(e,d,u,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await b(),S=o0(N,d,u,{requireRect:v});if(v&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=at(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:S.matches.length,candidates:e}}}}let _=S.matches[0]??null;if(!_)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let D="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,_)??_:_,E=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=at(_);return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get text",text:e}}),{ok:!0,data:{ref:E,text:e,node:_}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get attrs"}}),{ok:!0,data:{ref:E,node:_}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[E],flags:k});if(!e.ok)return e;let i=D.rect?n4(D.rect):null,o={ref:E,locator:d,query:u};return i&&(o.x=i.x,o.y=i.y),m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"click",locator:d,query:u}}),{ok:!0,data:o}}if("fill"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[E,p],flags:k});return e.ok&&m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"fill"}}),e}if("focus"===c){let e=_.rect?n4(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nK(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"focus"}}),{ok:!0,data:r??{ref:E}}}if("type"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=_.rect?n4(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nK(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nK(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"type"}}),{ok:!0,data:r??{ref:E}}}return null}function o4(e){return e instanceof Error?e.message:String(e)}function o8(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function o5(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function o6(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:ta},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await nH(t.flags??{});d||await nY(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!nz("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?o8(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=tw.expandHome(d,t.meta?.cwd),h=t.meta?.clientArtifactPaths?.outPath;$.mkdirSync(n.dirname(m),{recursive:!0});let w=o5(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},w)};try{await n()}catch(e){if(!o4(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o4(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o4(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},w)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o4(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,clientOutPath:h,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",e_(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,clientOutPath:h,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,clientOutPath:h,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:h??d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=o8(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},o5(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o4(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of eY)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}});let m=[{field:"outPath",path:f.outPath,localPath:f.clientOutPath,fileName:n.basename(f.clientOutPath??f.outPath)}];return{ok:!0,data:{recording:"stopped",outPath:f.outPath,artifacts:m}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=tw.expandHome(e);return $.mkdirSync(n.dirname(r),{recursive:!0}),$.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=tw.expandHome(t.positionals[1]);$.mkdirSync(n.dirname(e),{recursive:!0}),$.existsSync(o)?$.renameSync(o,e):$.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function o9(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function o7(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function se(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function st(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??nW,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nz("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=sn("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=sa({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=so(p.rect);if(!m){let r=await sr(e,t.flags,i,n,{interactiveOnly:!0},a),o=n3(r.nodes,c),l=s.length>0?n8(r.nodes,s):null,d=so(l?.rect),u=so(o?.rect)?o:d?l:o??l,h=so(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=n5(p,f),w=am(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=aa(u),p=await sr(e,t.flags,i,n,{interactiveOnly:!0},a),f=await L("selector_resolve",()=>as(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:ad(c,f?.diagnostics??[],{unique:!0})}};let m=so(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=am(f.node,e.device.platform,{action:l}),v=n5(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!nz("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=sn("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=sa({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!ae(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=n5(c,p),w=am(c,e.device.platform,{action:"fill"}),{x:g,y:I}=n4(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=au(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=aa(s.selectorExpression),d=await sr(e,t.flags,i,n,{interactiveOnly:!0},a),u=await L("selector_resolve",()=>as(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:ad(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!ae(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=n4(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=am(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:n5(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nz("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=sn("get",t.flags);if(r)return r;let n=sa({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=am(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=at(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=aa(d),c=await sr(s,t.flags,i,n,{interactiveOnly:!1},a),p=await L("selector_resolve",()=>as(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:ad(u,[],{unique:!0})}};let f=p.node,m=am(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=at(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nz("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=ac(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=aa(l.selectorExpression),c=await sr(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=al(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:ad(u,[],{unique:!1})}}}let p=await L("selector_resolve",()=>as(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:ad(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=at(r),o=!1;switch(t){case"visible":o=ap(r);break;case"hidden":o=!ap(r);break;case"editable":o=af(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:ap(r),editable:af(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nz("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=sn("scrollintoview",t.flags);if(l)return l;let d=sa({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=n4(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=o7(n.map(e=>e.rect).filter(e=>o9(e,r.x,r.y)));if(a)return a;let o=o7(n.map(e=>e.rect));if(o)return o;let s=o7(i.map(e=>e.rect).filter(e=>o9(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:se(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:se(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=n5(c,p),w=am(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function sr(e,t,r,i,n,a=nW){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:n1(t?.snapshotRaw?s:n9(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let si=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function sn(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of si)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function sa(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=n2(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=n3(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=n8(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function so(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=n4(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function ss(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function sl(e){let{req:t,leaseRegistry:r}=e,i=ss(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let sd=new Set(["session_list","devices","ensure-simulator"]),su=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]);function sc(e,t,r,i){let n=O().requestId;return{...nK(e,t,r,i,n),requestId:n}}function sp(e){$.existsSync(e)&&$.unlinkSync(e)}function sf(e){if(!$.existsSync(e))return null;try{let t=JSON.parse($.readFileSync(e,"utf8"));if(!Number.isInteger(t.pid)||t.pid<=0)return null;return t}catch{return null}}function sm(e){let t=sf(e);if(!t||t.pid===process.pid)try{$.existsSync(e)&&$.unlinkSync(e)}catch{}}function sh(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}let{baseDir:sw,infoPath:sg,lockPath:sI,logPath:sv,sessionsDir:sA}=B(process.env.AGENT_DEVICE_STATE_DIR),sy=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var sb=sA;if($.existsSync(sb))for(let e of $.readdirSync(sb,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(sb,e.name,"app-log.pid");if($.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}($.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{tI(t)}}let sN=new tw(sA),sS=new t3({maxActiveSimulatorLeases:sh(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:sh(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:sh(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:sh(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),s_=E(),sD=u.randomBytes(24).toString("hex"),sE=T(process.pid)??void 0,sk=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=$.statSync(e),r=k(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}(),sO=function(e){let{logPath:t,token:r,sessionStore:i,leaseRegistry:a,trackDownloadableArtifact:s}=e;async function l(e){let d="click"===e.command?{...e,command:"press"}:e,u=!!(d.meta?.debug||d.flags?.verbose);return await P({session:d.session,requestId:d.meta?.requestId,command:d.command,debug:u,logPath:t},async()=>{if(d.token!==r)return{ok:!1,error:_(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=D(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=o(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(d);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let r=e.command,u=t=>(function(e,t,r){let i=O();if(!t.ok){M({level:"error",phase:"request_failed",data:{code:t.error.code,message:t.error.message}});let e=F({force:!0})??void 0;return{ok:!1,error:_(new I(t.error.code,t.error.message,{...t.error.details??{},hint:t.error.hint,diagnosticId:t.error.diagnosticId,logPath:t.error.logPath}),{diagnosticId:i.diagnosticId,logPath:e})}}return M({level:"info",phase:"request_success"}),F(),{ok:!0,data:function(e,t,r){var i,a;let o;if(!t)return t;let s=(i=e,a=t,o=Array.isArray(a.artifacts)?[...a.artifacts]:[],"screenshot"!==i.command||o.some(e=>e?.field==="path")||"string"!=typeof a.path||o.push({field:"path",path:a.path,localPath:i.meta?.clientArtifactPaths?.path,fileName:n.basename(i.meta?.clientArtifactPaths?.path??a.path)}),o.filter(e=>!!(e&&"string"==typeof e.field&&"string"==typeof e.path&&"string"==typeof e.localPath&&e.localPath.length>0)));return 0===s.length?t:{...t,artifacts:s.map(t=>{let i=t.path;return{field:t.field,artifactId:r({artifactPath:i,tenantId:e.meta?.tenantId,fileName:t.fileName}),fileName:t.fileName,localPath:t.localPath}})}}(e,t.data,r)}})(e,t,s),c=ss(e);su.has(r)||e.meta?.sessionIsolation!=="tenant"||a.assertLeaseAdmission({tenantId:c.tenantId,runId:c.runId,leaseId:c.leaseId,backend:c.leaseBackend});let p=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,i),f=i.get(p);f&&!sd.has(r)&&function(e,t){if(!t)return;let r=[],i=e.device,n=ej(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=eb(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(f,e.flags);let m=await sl({req:e,leaseRegistry:a});if(m)return u(m);let h=await o$({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(h)return u(h);let w=await oz({req:e,sessionName:p,logPath:t,sessionStore:i});if(w)return u(w);let g=await o6({req:e,sessionName:p,sessionStore:i,logPath:t});if(g)return u(g);let v=await o3({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(v)return u(v);let A=await st({req:e,sessionName:p,sessionStore:i,contextFromFlags:(e,r,i)=>sc(t,e,r,i)});if(A)return u(A);let y=i.get(p);if(!y)return u({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!nz(r,y.device))return u({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}});let b=await nW(y.device,r,e.positionals??[],e.flags?.out,{...sc(t,e.flags,y.appBundleId,y.trace?.outPath)});return i.recordAction(y,{command:r,positionals:e.positionals??[],flags:e.flags??{},result:b??{}}),u({ok:!0,data:b??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=O(),t=F({force:!0})??void 0;return{ok:!1,error:_(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}return l}({logPath:sv,token:sD,sessionStore:sN,leaseRegistry:sS,trackDownloadableArtifact:function(e){let t=u.randomUUID(),r=setTimeout(()=>{tR(t)},9e5);return tC.set(t,{artifactPath:e.artifactPath,tenantId:e.tenantId,fileName:e.fileName,deleteAfterDownload:!1!==e.deleteAfterDownload,timer:r}),t}});!async function(){let e,t;if(!function(e,t,r){$.existsSync(e)||$.mkdirSync(e,{recursive:!0});let i=JSON.stringify(r,null,2),n=()=>{try{return $.writeFileSync(t,i,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(n())return!0;let a=sf(t);if(a?.pid&&a.pid!==process.pid&&s(a.pid,a.processStartTime))return!1;try{$.unlinkSync(t)}catch{}return n()}(sw,sI,{pid:process.pid,version:s_,startedAt:Date.now(),processStartTime:sE})){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===sy||"dual"===sy){let t=U.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))ea(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await e7(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,o,s=t.slice(0,a).trim();if(t=t.slice(a+1),0===s.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(s);if(o=ei(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),en(o),es(o))throw el();n=await sO(e)}catch(e){n={ok:!1,error:_(e)}}finally{r-=1,o&&(i.delete(o),eo(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
37
|
-
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===
|
|
24
|
+
${n}`.toLowerCase();return a.includes("timeout waiting for screen surfaces")||a.includes("nsposixerrordomain")&&a.includes("code=60")&&a.includes("screenshot")||a.includes("timed out")&&a.includes("screenshot")}let i5={settings:"com.apple.Preferences"},i6=null;function i9(e,t,r){return p("xcrun",e_(e,t),r)}function i7(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function ne(e){let t=n.join(e,"Info.plist");try{let e=await p("plutil",["-extract","CFBundleIdentifier","raw","-o","-",t],{allowFailure:!0});if(0!==e.exitCode)return;let r=String(e.stdout??"").trim();return r.length>0?r:void 0}catch{return}}function nt(e){return e.bundleId?`${e.bundleName}.app (${e.bundleId})`:`${e.bundleName}.app`}async function nr(e){await Promise.all(e.map(async e=>{void 0===e.bundleId&&(e.bundleId=await ne(e.installPath))}))}async function ni(e,t){if(".ipa"!==n.extname(e).toLowerCase())return{installPath:e,cleanup:async()=>{}};let r=await x.mkdtemp(n.join(V.tmpdir(),"agent-device-ios-ipa-")),i=async()=>{await x.rm(r,{recursive:!0,force:!0})};try{await p("ditto",["-x","-k",e,r]);let a=n.join(r,"Payload"),o=(await x.readdir(a,{withFileTypes:!0}).catch(()=>{throw new I("INVALID_ARGS","Invalid IPA: missing Payload directory")})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(".app")).map(e=>({installPath:n.join(a,e.name),bundleName:e.name.replace(/\.app$/i,"")}));if(1===o.length)return{installPath:o[0].installPath,cleanup:i};if(0===o.length)throw new I("INVALID_ARGS","Invalid IPA: expected at least one .app under Payload, found 0");await nr(o);let s=t?.appIdentifierHint?.trim();if(s){let e=s.toLowerCase(),t=o.filter(t=>t.bundleName.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i};if(t.length>1)throw new I("INVALID_ARGS",`Invalid IPA: multiple app bundles matched "${s}" by name. Use a bundle id hint instead.`);if(s.includes(".")){let t=o.filter(t=>t.bundleId?.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i}}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload and none matched "${s}". Available bundles: ${o.map(nt).join(", ")}`)}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${o.map(nt).join(", ")}`)}catch(e){throw await i(),e}}async function nn(e,t){let r=t.trim();if(r.includes("."))return r;let i=i5[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await nw(e):await iV(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new I("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function na(e,t,r){let i=r?.url?.trim();if(i){if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await iW(e),await iH(),await i9(e,["openurl",e.id,i]);return}let n=t7(r?.appBundleId??await nn(e,t),i);if(!n)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await n_(e,n,{payloadUrl:i});return}let n=t.trim();if(t9(n)){if("simulator"===e.kind){await iW(e),await iH(),await i9(e,["openurl",e.id,n]);return}let t=t7(r?.appBundleId,n);if(!t)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await n_(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await nn(e,t);"simulator"===e.kind?await nS(e,a):await n_(e,a)}async function no(e){"simulator"!==e.kind||"Booted"!==await iz(e)&&(await iW(e),await iH())}async function ns(e,t){let r=await nn(e,t);if("simulator"===e.kind){await iW(e);let t=e_(e,["terminate",e.id,r]),i=await p("xcrun",t,{allowFailure:!0});if(0!==i.exitCode){if(i.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new I("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:t,stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return}await iF(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function nl(e,t){let r=await nn(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await p("xcrun",t,{allowFailure:!0,timeoutMs:iT});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!i7(`${n}
|
|
25
|
+
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:iG(n,a)??iU})}return{bundleId:r}}await iW(e);let i=await i9(e,["uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!i7(`${i.stdout}
|
|
26
|
+
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function nd(e,t,r){let{installPath:i,cleanup:n}=await ni(t,r);try{if("simulator"!==e.kind)return void await iF(["device","install","app","--device",e.id,i],{action:"install iOS app",deviceId:e.id});await iW(e),await i9(e,["install",e.id,i])}finally{await n()}}async function nu(e,t,r){let{bundleId:i}=await nl(e,t);return await nd(e,r,{appIdentifierHint:t}),{bundleId:i}}async function nc(e){iq(e,"clipboard"),await iW(e);let t=await i9(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to read iOS simulator clipboard",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return t.stdout.replace(/\r\n/g,"\n").replace(/\n$/,"")}async function np(e,t){iq(e,"clipboard"),await iW(e);let r=await i9(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new I("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function nf(e,t,r){iq(e,"push"),await iW(e);let i=await x.mkdtemp(n.join(V.tmpdir(),"agent-device-ios-push-")),a=n.join(i,"payload.apns");try{await x.writeFile(a,`${JSON.stringify(r)}
|
|
27
|
+
`,"utf8"),await i9(e,["push",e.id,t,a])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function nm(e,t,r,i,n){iq(e,"settings"),await iW(e);let a=t.toLowerCase();switch(a){case"wifi":{let t=ng(r);await i9(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(ng(r)?await i9(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await i9(e,["status_bar",e.id,"clear"]));case"location":{let t=ng(r);if(!i)throw new I("INVALID_ARGS","location setting requires an active app in session");await i9(e,["privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":case"touchid":{let t=nv[a],i=function(e,t){let r=e.trim().toLowerCase();if("match"===r)return"match";if("nonmatch"===r)return"nonmatch";if("enroll"===r)return"enroll";if("unenroll"===r)return"unenroll";throw new I("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r,a);await nN(e,i,{settingName:a,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await nI(e,r);await i9(e,["ui",e.id,"appearance",t]);return}case"permission":{var o;if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(o=iy(r))?"revoke":o,a=function(e,t){let r=ib(e);if("photos"!==r&&t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return"camera";if("microphone"===r)return"microphone";if("contacts"===r)return"contacts";if("contacts-limited"===r)return"contacts-limited";if("notifications"===r)return"notifications";if("calendar"===r)return"calendar";if("location"===r)return"location";if("location-always"===r)return"location-always";if("media-library"===r)return"media-library";if("motion"===r)return"motion";if("reminders"===r)return"reminders";if("siri"===r)return"siri";if("photos"===r){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new I("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new I("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(n?.permissionTarget,n?.permissionMode);await nA(e,t,a,i);return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function nh(e,t="all"){var r;return"simulator"===e.kind?(r=await nw(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await iV(e,t)}async function nw(e){let t=(await i9(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let r=null;if(t.startsWith("{"))try{r=JSON.parse(t)}catch{r=null}if(!r&&t.startsWith("{"))try{let e=await p("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(r=JSON.parse(e.stdout))}catch{r=null}return r?Object.entries(r).map(([e,t])=>({bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e})):[]}function ng(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function nI(e,t){let r=iN(t);if("toggle"!==r)return r;let i=await i9(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
|
|
28
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let nv={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function nA(e,t,r,i){let n=await nb(e);if(!n.has(r))throw new I("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["privacy",e.id,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await i9(e,a);return}catch(t){if(!(o&&ny(t)))throw t;throw new I("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await i9(e,a);return}catch(e){if(!ny(e))throw e}try{await i9(e,["privacy",e.id,"reset","all",i])}catch(t){throw new I("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function ny(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return(t.includes("failed to grant access")||t.includes("failed to revoke access")||t.includes("failed to reset access"))&&t.includes("operation not permitted")}async function nb(t){let r=ey(t.simulatorSetPath),i=`${process.env.PATH??""}::${r??""}`;if(i6&&e===i)return i6;let n=await i9(t,["privacy","help"],{allowFailure:!0}),a=function(e){let t=new Set,r=!1;for(let i of e.split("\n")){let e=i.trim();if(!e)continue;if("service"===e){r=!0;continue}if(!r)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${n.stdout}
|
|
29
|
+
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return i6=a,e=i,a}async function nN(e,t,r){let i=function(e,t,r){let i=r.length>0?r:["face"];switch(t){case"match":return i.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return i.flatMap(t=>[["biometric",e,"nonmatch",t],["biometric",e,"nomatch",t],["biometric","nonmatch",e,t],["biometric","nomatch",e,t]]);case"enroll":return[["biometric",e,"enroll","yes"],["biometric",e,"enroll","1"],["biometric","enroll",e,"yes"],["biometric","enroll",e,"1"]];case"unenroll":return[["biometric",e,"enroll","no"],["biometric",e,"enroll","0"],["biometric","enroll",e,"no"],["biometric","enroll",e,"0"]]}}(e.id,t,r.modalityAliases),n=[];for(let t of i){let r=e_(e,t),i=await p("xcrun",r,{allowFailure:!0});if(0===i.exitCode)return;n.push({args:r,stderr:i.stderr,stdout:i.stdout,exitCode:i.exitCode})}let a=n.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(n.length>0&&n.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
30
|
+
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}async function nS(e,t){await iW(e),await iH();let r=0,i=K.fromTimeoutMs(iR);try{await X(async({deadline:r})=>{var i;if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:iR});let n=(i=["launch",e.id,t],e_(e,i)),a=await p("xcrun",n,{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${a.exitCode}`,{cmd:"xcrun",args:n,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode})},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>!!iB(e)&&(r+=1)<3},{deadline:i})}catch(r){if(iB(r)){var n;let i=(n=await ij(e,t)).installed?!1===n.simulatorCompatible?"ARCH_MISMATCH":"PERSISTENT_LAUNCH_FAIL":"APP_NOT_INSTALLED";r.details={...r.details,hint:function(e){switch(e){case"ARCH_MISMATCH":return"The app binary was not built for the simulator platform. Rebuild with a simulator destination or use a physical device.";case"APP_NOT_INSTALLED":return"The app bundle is not installed on this simulator. Run install before open.";case"PERSISTENT_LAUNCH_FAIL":return"The simulator repeatedly refused to launch the app. Inspect crash logs in Console.app or ~/Library/Logs/DiagnosticReports/ and consider reinstalling the app.";default:return"The simulator failed to launch the app. Retry with --debug and inspect diagnostics log for details."}}(i)}}throw r}}async function n_(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await iF(i,{action:"launch iOS app",deviceId:e.id})}let nD=/^[A-Za-z0-9_.:-]{1,64}$/,nE=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function nk(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function nO(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await nL(t)}async function nL(e){await new Promise(t=>setTimeout(t,e))}function nM(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!$.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function nx(e){let t=nM(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await nC(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function nC(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}let nR=ew(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),nT=/^(iphone|ipad|ipod|appletv)/i,nP=/^appletv/i,n$=["apple tv","appletv","tvos"];function nF(e){return(e??"").trim().toLowerCase()}function nV(e){return nF(e.hardwareProperties?.platform)}function nU(e){return e.includes("tvos")}function nG(e){return nU(nF(e))?"tv":"mobile"}function nB(e){let t=nF(e);return t.includes("ios")||t.includes("tvos")}function nj(e){let t=nF(e);return n$.some(e=>t.includes(e))}function nq(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function nH(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function nW(e={}){let t,r,i=ey(e.simulatorSetPath),n=e.target;try{t=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:i}))}catch{return null}try{r=JSON.parse(t.stdout)}catch{return null}let a=null,o=null,s=null;for(let[e,t]of Object.entries(r.devices)){if(!nB(e))continue;let r=nG(e);if(!n||r===n)for(let e of t){if(!e.isAvailable)continue;let t={platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:r,booted:"Booted"===e.state,...i?{simulatorSetPath:i}:{}};t.booted&&(a=a??t),"mobile"===r&&(o=o??t),s=s??t}}return a??o??s}async function nJ(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await A("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=ey(e.simulatorSetPath),i=await p("xcrun",eS(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(nB(i))for(let e of n)e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:nG(i),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let a=null;try{a=n.join(V.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",a],{allowFailure:!0,timeoutMs:nR});if(0!==e.exitCode)return t;let r=await x.readFile(a,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=nV(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=nH(e),!!nT.test(t.trim())||nq(e).some(nj))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return nU(nV(e))?"tv":(t=nH(e),nP.test(t.trim())||nq(e).some(nj))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{a&&await x.rm(a,{force:!0}).catch(()=>{})}return t}async function nz(e,t,r,i){let n,a=!!(t.udid||t.serial||t.deviceName);try{n=await i.selectDevice(e,t,r)}catch(e){if(a||!(e instanceof I)||"DEVICE_NOT_FOUND"!==e.code)throw e}if(!a&&(!n||"device"===n.kind)){let e=await i.findBootableSimulator({simulatorSetPath:r.simulatorSetPath,target:t.target});if(e)return e}if(n)return n;throw new I("DEVICE_NOT_FOUND","No devices found",{selector:t})}async function nK(e){let t=ej(e.platform),r=ey(e.iosSimulatorDeviceSet),i=eN(e.androidDeviceAllowlist);return await L("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await t8();let e=await rc({serialAllowlist:i});return await eq(e,n)}if("ios"===n.platform){let e=await nJ({simulatorSetPath:r});return await nz(e,n,{simulatorSetPath:r},{selectDevice:eq,findBootableSimulator:nW})}let a=[];try{a.push(...await rc({serialAllowlist:i}))}catch{}try{a.push(...await nJ({simulatorSetPath:r}))}catch{}return await eq(a,n,{simulatorSetPath:r})},{platform:t,target:e.target})}async function nX(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>rR(e,t,r?.activity),openDevice:()=>rP(e),close:t=>r$(e,t),tap:(t,r)=>r8(e,t,r),doubleTap:async(t,r)=>{await r8(e,t,r),await r8(e,t,r)},swipe:(t,r,i,n,a)=>r5(e,t,r,i,n,a),longPress:(t,r,i)=>ie(e,t,r,i),focus:(t,r)=>ir(e,t,r),type:t=>it(e,t),fill:(t,r,i)=>ii(e,t,r,i),scroll:(t,r)=>ia(e,t,r),scrollIntoView:t=>io(e,t),screenshot:(t,r)=>r0(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>na(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>no(e),close:t=>ns(e,t),screenshot:(t,r)=>iY(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(es(i.requestId))throw el()},{tap:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await ta(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await ta(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await ta(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await ta(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await ta(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await ta(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await ta(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await ta(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await ta(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await L("platform_command",async()=>{switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(t9(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!t9(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=nk(a?.count??1,"count",1,200),s=nk(a?.intervalMs??0,"interval-ms",0,1e4),l=nk(a?.holdMs??0,"hold-ms",0,1e4),d=nk(a?.jitterPx??0,"jitter-px",0,100),u=a?.doubleTap===!0;if(u&&l>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(u&&d>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if("ios"===e.platform&&n>1&&0===l&&0===d)return await ta(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:s,doubleTap:u,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u,timingMode:"runner-series"};return await nO(n,s,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=nE[e%nE.length];return[r*t,i*t]}(e,d),a=t+r,s=i+n;u?await o.doubleTap(a,s):l>0?await o.longPress(a,s,l):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=nk(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=nk(a?.count??1,"count",1,200),c=nk(a?.pauseMs??0,"pause-ms",0,1e4),p=a?.pattern??"one-way";if("one-way"!==p&&"ping-pong"!==p)throw new I("INVALID_ARGS",`Invalid pattern: ${p}`);if("ios"===e.platform&&u>1)return await ta(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:c,pattern:p,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:c,pattern:p};return await nO(u,c,async e=>{"ping-pong"===p&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:c,pattern:p}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await ta(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!nD.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await ta(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await r6(e),{action:"back"};case"home":if("ios"===e.platform)return await ta(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await r9(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await ta(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await r7(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await nc(e):await ig(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await np(e,i):await iI(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await iw(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await ih(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await nm(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await iS(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await nx(i);if("ios"===e.platform)return await nf(e,t,n),{platform:"ios",bundleId:t};let a=await iM(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await L("snapshot_capture",async()=>await ta(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await L("snapshot_capture",async()=>await rZ(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let nY={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},install:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function nZ(e,t){let r=nY[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function nQ(e,t,r,i,n){return{requestId:n??O().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let n0=ew(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function n1(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:iW}));await t(e);return}if("device"===e.kind)return void await n2(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:rI}));await t(e.id)}}async function n2(e){let t=n.join(V.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(n0/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:n0+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await n3(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:n4(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??n0),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?n4(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function n3(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function n4(e,t){let r=iG(e,t);return r||(`${e}
|
|
31
|
+
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":iU)}function n8(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function n5(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function n6(e,t){return e.find(e=>e.ref===t)??null}function n9(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function n7(e,t){let r=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),i=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(r)||i.includes(r)||n.includes(r)})??null}function ae(e,t){let r=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return r&&at(r)?r:function(e,t){if(!e.rect)return;let r=e.rect.y+e.rect.height/2,i=null;for(let e of t){if(!e.rect)continue;let t=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);if(!t||!at(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-r);(!i||n<i.distance)&&(i={label:t,distance:n})}return i?.label}(e,t)??(r&&at(r)?r:void 0)}function at(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function ar(e){let t=[],r=[];for(let i of e){let e=i.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=ai(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&at(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);r.push({...i,depth:s})}return r}function ai(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),r=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==r&&(t=t.slice(r+1)),t}function an(e,t){let r=ai(e);return!r||("android"===t?r.includes("edittext")||r.includes("autocompletetextview"):r.includes("textfield")||r.includes("securetextfield")||r.includes("searchfield")||r.includes("textview")||r.includes("textarea")||"search"===r)}function aa(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let ao=new Set(["id","role","text","label","value"]),as=new Set(["visible","hidden","editable","selected","enabled","hittable"]),al=new Set([...ao,...as]);function ad(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aE(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!aE(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(av)}})(e))}}function au(e){try{return ad(e)}catch{return null}}function ac(e,t,r){let i=r.requireRect??!1,n=r.requireUnique??!0,a=r.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,r){let i=0,n=null,a=null,o=!1;for(let s of e){if(r.requireRect&&!s.rect||!aA(s,t,r.platform))continue;if(i+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let r=e.depth??0,i=t.depth??0;if(r!==i)return r>i?1:-1;let n=aD(e),a=aD(t);return n!==a?n<a?1:-1:0}(s,a);if(e>0){a=s,o=!1;continue}0===e&&(o=!0)}return{count:i,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:r.platform,requireRect:i});if(o.push({selector:l.raw,matches:d.count}),0!==d.count&&d.firstNode){if(n&&1!==d.count){if(!a)continue;let e=d.disambiguated;if(!e)continue;return{node:e,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}return{node:d.firstNode,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}}return null}function ap(e,t,r){let i=r.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,r){let i=0;for(let n of e)(!r.requireRect||n.rect)&&aA(n,t,r.platform)&&(i+=1);return i}(e,o,{platform:r.platform,requireRect:i});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function af(e,t,r){let i=r.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return i?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function am(e,t={}){if(0===e.length)return null;let r=t.preferTrailingValue??!1,i=0,n=[];for(;i<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let r=t.indexOf("=");if(-1!==r){let e=t.slice(0,r).trim().toLowerCase();return al.has(e)}return al.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&au(t)&&n.push(i)}if(0===n.length)return null;let a=n[n.length-1];if(r){for(let t=n.length-1;t>=0;t-=1)if(n[t]<e.length){a=n[t];break}}let o=e.slice(0,a).join(" ").trim();return o?{selectorExpression:o,rest:e.slice(a)}:null}function ah(e){let t=e[0]??"",r=am(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function aw(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function ag(e,t){return an(e.type??"",t)&&!1!==e.enabled}function aI(e,t,r={}){let i=[],n=ai(e.type??""),a=a_(e.identifier),o=a_(e.label),s=a_(e.value),l=a_(aa(e)),d="fill"===r.action;a&&i.push(`id=${aS(a)}`),n&&o&&i.push(d?`role=${aS(n)} label=${aS(o)} editable=true`:`role=${aS(n)} label=${aS(o)}`),o&&i.push(d?`label=${aS(o)} editable=true`:`label=${aS(o)}`),s&&i.push(d?`value=${aS(s)} editable=true`:`value=${aS(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${aS(l)} editable=true`:`text=${aS(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${aS(n)} editable=true`);let u=tl(i);return 0===u.length&&n&&u.push(d?`role=${aS(n)} editable=true`:`role=${aS(n)}`),0===u.length&&aw(e)&&u.push("visible=true"),u}function av(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!as.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!al.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(as.has(i)){let e,t="true"===(e=ay(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:ay(n)}}function aA(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return ab(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return ai(e)}(i??"")===function(e){return ai(e)}(n);case"label":return ab(e.label,String(t.value));case"value":return ab(e.value,String(t.value));case"text":{let r=aN(String(t.value));return aN(aa(e))===r}case"visible":return aw(e)===!!t.value;case"hidden":return!aw(e)==!!t.value;case"editable":return ag(e,r)===!!t.value;case"selected":return!0===e.selected==!!t.value;case"enabled":return!1!==e.enabled==!!t.value;case"hittable":return!0===e.hittable==!!t.value;default:return!1}})(e,t,r))}function ay(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function ab(e,t){return aN(e??"")===aN(t)}function aN(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function aS(e){return JSON.stringify(e)}function a_(e){if(!e)return null;let t=e.trim();return t||null}function aD(e){return e.rect?e.rect.width*e.rect.height:1/0}function aE(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}let ak=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),aO=/https?:\/\/[^\s"'<>\])]+/i,aL=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function aM(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function ax(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return aC(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function aC(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function aR(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function aT(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let aP="shared_prefs/ReactNativeDevPrefs.xml",a$="debug_http_host",aF="dev_server_https",aV="RCT_jsLocation",aU="RCT_packager_scheme",aG="React Native runtime hints require adb run-as access to the app sandbox. Verify the app is debuggable and the selected package/device are correct.",aB='<?xml version="1.0" encoding="utf-8" standalone="yes" ?>\n<map>\n</map>\n';function aj(e){return void 0!==aq(e)}function aq(e){if(!e)return;let t=a2(e.metroHost),r=a4(e.metroPort),i="http",n=a2(e.bundleUrl);if(n){var a;let e;try{e=new v(n)}catch(e){throw new I("INVALID_ARGS",`Invalid runtime bundle URL: ${n}`,{},e)}("http:"===e.protocol||"https:"===e.protocol)&&(t??=a2(e.hostname),r??=a4(e.port.length>0?Number(e.port):"https:"===(a=e.protocol)?443:"http:"===a?80:void 0),i="https:"===e.protocol?"https":"http")}if(t&&r)return{host:t,port:r,scheme:i}}async function aH(e){let{device:t,appId:r,runtime:i}=e;if(!r)return;let n=aq(i);if(n){if("android"===t.platform)return void await aJ(t,r,n);"ios"===t.platform&&"simulator"===t.kind&&await aY(t,r,n)}}async function aW(e){let{device:t,appId:r}=e;if(r){if("android"===t.platform)return void await az(t,r);"ios"===t.platform&&"simulator"===t.kind&&await aZ(t,r)}}async function aJ(e,t,r){var i,n,a,o,s,l;let d,u;a3(t);let c=(i=await aK(e,t),n=a$,a=`${r.host}:${r.port}`,d=` <string name="${a8(n)}">${a8(a)}</string>`,a0(a1(i,n),d));o=c,s=aF,l="https"===r.scheme,u=` <boolean name="${a8(s)}" value="${l?"true":"false"}" />`,c=a0(a1(o,s),u),await aX(e,t,c)}async function az(e,t){a3(t);let r=await aK(e,t),i=a1(r,a$),n=a1(i,aF);n!==r&&await aX(e,t,n)}async function aK(e,t){let r=await p("adb",t4(e,["shell","run-as",t,"cat",aP]),{allowFailure:!0});return 0!==r.exitCode?aB:aQ(r.stdout)}async function aX(e,t,r){let i=t4(e,["shell","run-as",t,"id"]),n=await p("adb",i,{allowFailure:!0});if(0!==n.exitCode){let e=a5(n.stdout,n.stderr);throw new I("COMMAND_FAILED",e?`Failed to access Android app sandbox for ${t}`:`Failed to probe Android app sandbox for ${t}`,{package:t,cmd:"adb",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:e?aG:"adb shell run-as probe failed. Check adb connectivity and that the device is reachable. Inspect stderr/details for more information."})}try{await p("adb",t4(e,["shell","run-as",t,"mkdir","-p","shared_prefs"])),await p("adb",t4(e,["shell","run-as",t,"tee",aP]),{stdin:r.trimEnd()})}catch(i){let e=w(i);if("TOOL_MISSING"===e.code)throw e;let r=a5("string"==typeof e.details?.stdout?e.details.stdout:"","string"==typeof e.details?.stderr?e.details.stderr:"");throw new I("COMMAND_FAILED",r?`Failed to access Android app sandbox for ${t}`:`Failed to write Android runtime hints for ${t}`,{...e.details??{},package:t,cmd:"adb",phase:"write-runtime-hints",hint:r?aG:"adb run-as succeeded, but writing ReactNativeDevPrefs.xml failed. Inspect stderr/details for the failing shell command."},e)}}async function aY(e,t,r){await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aV,"-string",`${r.host}:${r.port}`])),await p("xcrun",e_(e,["spawn",e.id,"defaults","write",t,aU,"-string",r.scheme]))}async function aZ(e,t){await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aV]),{allowFailure:!0}),await p("xcrun",e_(e,["spawn",e.id,"defaults","delete",t,aU]),{allowFailure:!0})}function aQ(e){let t=e.trim();return t.includes("<map")&&t.includes("</map>")?`${t}
|
|
32
|
+
`:aB}function a0(e,t){return aQ(e).replace("</map>",`${t}
|
|
33
|
+
</map>`)}function a1(e,t){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return aQ(e).replace(RegExp(`^\\s*<string name="${r}">[\\s\\S]*?<\\/string>\\n?`,"m"),"").replace(RegExp(`^\\s*<boolean name="${r}" value="(?:true|false)"\\s*\\/?>\\n?`,"m"),"")}function a2(e){let t=e?.trim();return t&&t.length>0?t:void 0}function a3(e){if("binary"!==ry(e))return;let t=rb(e);throw new I("INVALID_ARGS",t,{package:e,hint:t})}function a4(e){if(Number.isInteger(e)&&!(e<=0)&&!(e>65535))return e}function a8(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function a5(e,t){let r=`${e}
|
|
34
|
+
${t}`.toLowerCase();return["run-as: package not debuggable","run-as: permission denied","run-as: package is unknown","run-as: unknown package","is unknown","is not an application","could not set capabilities"].some(e=>r.includes(e))}function a6(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=am(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function a9(e){return!!e&&!Number.isNaN(Number(e))}async function a7(e){let t,r,i,{deviceName:n,runtime:a,simulatorSetPath:o,reuseExisting:s,boot:l,ensureReady:d}=e;if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","ensure-simulator is only available on macOS");let u={simulatorSetPath:o??void 0};if(s){let e=await oe({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await ot({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await or(t,u),i=!0)}else t=(await ot({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await or(t,u),i=!0;let c=!1;if(l){let e={platform:"ios",id:t,name:n,kind:"simulator",target:"mobile",...o?{simulatorSetPath:o}:{}};await d(e),c=!0}return{udid:t,device:n,runtime:r,created:i,booted:c}}async function oe(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",eS(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:iC});if(0!==n.exitCode)return null;try{let e=JSON.parse(String(n.stdout??""));for(let[i,n]of Object.entries(e.devices??{}))if(!r||oi(i).includes(oi(r))){for(let e of n)if(e.isAvailable&&e.name.toLowerCase()===t.toLowerCase())return{udid:e.udid,runtime:i}}return null}catch{return null}}async function ot(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",eS(n,i),{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED","Failed to create iOS simulator",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode,hint:"Ensure the device type and runtime identifiers are valid. Run `xcrun simctl list devicetypes` and `xcrun simctl list runtimes` to see available options."});let o=String(a.stdout??"").trim();if(!o)throw new I("COMMAND_FAILED","simctl create returned no UDID",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??"")});return{udid:o}}async function or(e,t){let r=await p("xcrun",eS(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:iC});if(0!==r.exitCode)return"";try{let t=JSON.parse(String(r.stdout??""));for(let[r,i]of Object.entries(t.devices??{}))if(i.some(t=>t.udid===e))return r;return""}catch{return""}}function oi(e){return e.toLowerCase().replace(/[._-]/g,"")}let on='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',oa=["platform","target","device","udid","serial","verbose","out"],oo=["platform","target","device","udid","serial","verbose","out"],os=["path","start","stop","doctor","mark","clear"],ol=`logs requires ${os.slice(0,-1).join(", ")}, or ${os.at(-1)}`,od="Not implemented for this platform in this release.",ou="open-command-roundtrip",oc=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),op=ew(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function of(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a,runtime:o}=e,s={session:t};return r&&(s.appName=r),i&&(s.appBundleId=i),n&&(s.startup=n),o&&om(o)>0&&(s.runtime=o),a?.platform==="ios"&&(s.device_udid=a.id,s.ios_simulator_device_set=a.simulatorSetPath??null),s}function om(e){return e?[e.metroHost,e.metroPort,e.bundleUrl,e.launchUrl].filter(e=>void 0!==e&&""!==e).length:0}function oh(e){let t=e?.trim();return t&&t.length>0?t:void 0}function ow(e,t,r){let i=e.getRuntimeHints(t);if(i){if(i.platform&&r&&i.platform!==r.platform)throw new I("INVALID_ARGS",`Session runtime hints target ${i.platform}, but session "${t}" is bound to ${r.platform}. Clear the runtime hints or use a different session.`);return r?.platform&&i.platform!==r.platform?{...i,platform:r.platform}:i}}async function og(e){let{runtime:t,device:r,dispatch:i,req:n,logPath:a,appBundleId:o,traceLogPath:s,openPositionals:l}=e,d=t?.launchUrl;if(!d||0===l.length||l.length>1)return;let u=l[0]?.trim();!u||t9(u)||await i(r,"open",[d],n.flags?.out,{...nQ(a,n.flags,o,s)})}function oI(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:ou,appTarget:t,appBundleId:r}}let ov=["dump","log"],oA=`network requires ${ov.join(" or ")}`,oy=["summary","headers","body","all"],ob=`network include mode must be one of: ${oy.join(", ")}`;function oN(e,t,r){return t||oS(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function oS(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function o_(e){return"ios"===e.platform&&"simulator"===e.kind}async function oD(e,t){o_(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function oE(e){let{device:t,closeTarget:r,stopIosRunner:i,dispatch:n,outFlag:a,context:o,settleSimulator:s}=e;"ios"===t.platform&&await i(t.id),await n(t,"close",[r],a,o),await s(t,oc)}async function ok(e){let t=oS(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function oO(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let oL=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:rg}));return await i({avdName:e,serial:t,headless:r})};async function oM(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=oN(l,p,f);if(m)return m;let h=await ok({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nZ(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...nQ(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let ox={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:nu}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:rH}));return await i(e,t,r)}},oC={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:nd}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await oF(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:rq}));await i(e,r);let{package:n}=await oF(e,t);return n?{package:n}:{}}};async function oR(e){let{req:t,command:r,sessionName:i,sessionStore:n,ensureReady:a,resolveDevice:o,deployOps:s}=e,l=n.get(i),d=t.flags??{},u=oN(r,l,d);if(u)return u;let c=t.positionals?.[0]?.trim(),p=t.positionals?.[1]?.trim();if(!c||!p)return{ok:!1,error:{code:"INVALID_ARGS",message:`${r} requires: ${r} <app> <path-to-app-binary>`}};let f=t.meta?.uploadedArtifactId;try{let e,i=f?function(e,t){let r=tT.get(e);if(!r)throw new I("INVALID_ARGS",`Uploaded artifact not found: ${e}`);if(r.tenantId&&r.tenantId!==t)throw new I("UNAUTHORIZED","Uploaded artifact belongs to a different tenant");return clearTimeout(r.timer),r.artifactPath}(f,t.meta?.tenantId):tw.expandHome(p);if(!$.existsSync(i))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${i}`}};let u=await ok({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!1});if(!nZ(r,u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}};if("ios"===u.platform){let t=(await s.ios(u,c,i)).bundleId;e=t?{app:c,appPath:i,platform:"ios",appId:t,bundleId:t}:{app:c,appPath:i,platform:"ios"}}else{let t=(await s.android(u,c,i)).package;e=t?{app:c,appPath:i,platform:"android",appId:t,package:t}:{app:c,appPath:i,platform:"android"}}return l&&n.recordAction(l,{command:r,positionals:t.positionals??[],flags:t.flags??{},result:e}),{ok:!0,data:e}}finally{f&&tP(f)}}async function oT(e,t,r){if("ios"===e.platform&&t)return t9(t)?"device"===e.kind?t7(r,t):void 0:await oP(e,t)}async function oP(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:nn}));return await r(e,t)}catch{return}}async function o$(e,t){if(!("android"!==e.platform||!t||t9(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:rE})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function oF(e,t){return"ios"===e.platform?{bundleId:await oP(e,t)}:{package:await o$(e,t)}}async function oV(e,t,r,i){return await oT(e,t,r)??await i(e,t)??("android"===e.platform&&t&&t9(t)?r:void 0)}async function oU(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=ej(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=oN("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!oS(e))return!0;let r=ej(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:on}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session",device_udid:o.device.id,ios_simulator_device_set:o.device.simulatorSetPath??null}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await ok({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:on}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:rx})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function oG(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=oN("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await ok({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!nZ("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...nQ(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function oB(e){var t,r;let{req:i,sessionName:n,logPath:a,sessionStore:o,invoke:s,dispatch:l,ensureReady:d,resolveTargetDevice:u,installOps:c=oC,reinstallOps:p=ox,stopIosRunner:f,appLogOps:m={start:tO,stop:tL},ensureAndroidEmulatorBoot:h=oL,resolveAndroidPackageForOpen:g=o$,applyRuntimeHints:v=aH,clearRuntimeHints:A=aW,settleSimulator:y,shutdownSimulator:b}=e,N=l??nX,S=d??n1,D=u??nK,E=f??e9,k=y??oD,O=i.command;if("session_list"===O)return{ok:!0,data:{sessions:o.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.id,ios_simulator_device_set:e.device.simulatorSetPath??null}}))}};if("runtime"===O){let e,a=(i.positionals?.[0]??"show").toLowerCase(),s=o.get(n),l=o.getRuntimeHints(n);if(!["set","show","clear"].includes(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime requires set, show, or clear"}};if("clear"===a){aj(l)&&s?.appBundleId&&await A({device:s.device,appId:s.appBundleId});let e=o.clearRuntimeHints(n);return{ok:!0,data:{session:n,cleared:e}}}if("show"===a)return{ok:!0,data:{session:n,configured:!!l,runtime:l}};let d=ej(i.flags?.platform)??l?.platform??s?.device.platform;if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires --platform when the session has not been opened yet."}};if(s&&s.device.platform!==d)return{ok:!1,error:{code:"INVALID_ARGS",message:`runtime set targets ${d}, but session "${n}" is already bound to ${s.device.platform}.`}};let u={platform:(t=i.flags,e=t?.metroPort,r={platform:d,metroHost:oh(t?.metroHost),metroPort:Number.isInteger(e)?e:void 0,bundleUrl:oh(t?.bundleUrl),launchUrl:oh(t?.launchUrl)}).platform??l?.platform,metroHost:r.metroHost??l?.metroHost,metroPort:r.metroPort??l?.metroPort,bundleUrl:r.bundleUrl??l?.bundleUrl,launchUrl:r.launchUrl??l?.launchUrl};return 0===om(u)?{ok:!1,error:{code:"INVALID_ARGS",message:"runtime set requires at least one hint such as --metro-host, --metro-port, --bundle-url, or --launch-url."}}:(o.setRuntimeHints(n,u),{ok:!0,data:{session:n,configured:!0,runtime:u}})}if("ensure-simulator"===O)try{let e=i.flags??{},t=e.device,r=e.runtime,n=ey(e.iosSimulatorDeviceSet);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await a7({deviceName:t,runtime:r,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:S});return{ok:!0,data:{udid:s.udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:n??null,created:s.created,booted:s.booted}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("devices"===O)try{let e=[],t=ey(i.flags?.iosSimulatorDeviceSet),r=eN(i.flags?.androidDeviceAllowlist),n=ej(i.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:rc}));e.push(...await t({serialAllowlist:r}))}else if("ios"===n){let{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:nJ}));e.push(...await r({simulatorSetPath:t}))}else{let{listAndroidDevices:i}=await Promise.resolve().then(()=>({listAndroidDevices:rc})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:nJ}));try{e.push(...await i({serialAllowlist:r}))}catch{}try{e.push(...await n({simulatorSetPath:t}))}catch{}}let a=(i.flags?.target?e.filter(e=>(e.target??"mobile")===i.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===O){let e=o.get(n),t=i.flags??{},r=oN(O,e,t);if(r)return r;let a=await ok({session:e,flags:t,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!0});if(!nZ("apps",a))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=i.flags?.appsFilter??"all";if("ios"===a.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:nh}));return{ok:!0,data:{apps:(await e(a,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:rk}));return{ok:!0,data:{apps:(await l(a,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===O){let e,t=o.get(n),r=i.flags??{},a=oN(O,t,r);if(a)return a;let s="android"===(ej(r.platform)??t?.device.platform),l=!0===r.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=oO({flags:r,sessionDevice:t?.device}),u=s&&!!d,c=!1;try{e=await ok({session:t,flags:r,ensureReadyFn:S,resolveTargetDeviceFn:D,ensureReady:!1})}catch(i){let t=w(i);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw i;e=await h({avdName:d,serial:r.serial,headless:l}),c=!0}if(r.target&&(e.target??"mobile")!==r.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${r.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let i=oO({flags:r,sessionDevice:t?.device,resolvedDevice:e});if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await h({avdName:i,serial:r.serial,headless:!0})}await S(e)}else("android"!==e.platform||!0!==e.booted)&&await S(e);return nZ("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===O)return await oU({req:i,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D});if("clipboard"===O)return await oG({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N});if("keyboard"===O)return await oM({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"keyboard",positionals:i.positionals??[]});if("perf"===O){let e,t,r,i=o.get(n);return i?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===ou&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:ou,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(i.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:ou,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:ou},{session:i.name,platform:i.device.platform,device:i.device.name,deviceId:i.device.id,metrics:{startup:r,fps:{available:!1,reason:od},memory:{available:!1,reason:od},cpu:{available:!1,reason:od}},sampling:{startup:{method:ou,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("install"===O||"reinstall"===O)return await oR({req:i,command:O,sessionName:n,sessionStore:o,ensureReady:S,resolveDevice:D,deployOps:"install"===O?c:p});if("push"===O){let e,t=i.positionals?.[0]?.trim(),r=i.positionals?.[1]?.trim();if(!t||!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=nM(r,{subject:"Push payload",cwd:i.meta?.cwd,expandPath:(e,t)=>tw.expandHome(e,t)})).kind?e.path:e.text;return await oM({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"push",positionals:[t,s],recordPositionals:[t,r]})}if("trigger-app-event"===O)return await oM({req:i,sessionName:n,logPath:a,sessionStore:o,ensureReady:S,resolveDevice:D,dispatch:N,command:"trigger-app-event",positionals:i.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await oV(e.device,r,e.appBundleId,g)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===O){let e=i.flags?.relaunch===!0;if(o.has(n)){let t=o.get(n),r=i.positionals?.[0],s=r??(e?t?.appName:void 0);if(!t||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&t9(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};if(e&&"android"===t.device.platform&&"binary"===ry(s))return{ok:!1,error:{code:"INVALID_ARGS",message:rb(s)}};await S(t.device);let l=ow(o,n,t?.device),d=await oV(t.device,s,t.appBundleId,g),u=r?i.positionals??[]:[s];if(e){let e=d??s;await oE({device:t.device,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nQ(a,i.flags,d??t.appBundleId,t.trace?.outPath)},settleSimulator:k})}await v({device:t.device,appId:d,runtime:l});let c=Date.now();await N(t.device,"open",u,i.flags?.out,{...nQ(a,i.flags,d)}),await og({runtime:l,device:t.device,dispatch:N,req:i,logPath:a,appBundleId:d,traceLogPath:t.trace?.outPath,openPositionals:u});let p=oI(c,s,d);await k(t.device,op);let f={...t,appBundleId:d,appName:s,recordSession:t.recordSession||!!i.flags?.saveScript,snapshot:void 0},m=of({sessionName:n,appName:s,appBundleId:d,startup:p,device:t.device,runtime:l});return o.recordAction(f,{command:O,positionals:u,flags:i.flags??{},result:m}),o.set(n,f),{ok:!0,data:m}}let t=i.positionals?.[0];if(e&&!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&t&&t9(t))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let r=await D(i.flags??{});if(e&&"android"===r.platform&&t&&"binary"===ry(t))return{ok:!1,error:{code:"INVALID_ARGS",message:rb(t)}};let s=o.toArray().find(e=>e.device.id===r.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:r.id,deviceName:r.name}}};await S(r);let l=ow(o,n,r),d=await oV(r,t,void 0,g);if(e&&t){let e=d??t;await oE({device:r,closeTarget:e,stopIosRunner:E,dispatch:N,outFlag:i.flags?.out,context:{...nQ(a,i.flags,d)},settleSimulator:k})}await v({device:r,appId:d,runtime:l});let u=Date.now();await N(r,"open",i.positionals??[],i.flags?.out,{...nQ(a,i.flags,d)}),await og({runtime:l,device:r,dispatch:N,req:i,logPath:a,appBundleId:d,openPositionals:i.positionals??[]});let c=t?oI(u,t,d):void 0;await k(r,op);let p={name:n,device:r,createdAt:Date.now(),appBundleId:d,appName:t,recordSession:!!i.flags?.saveScript,actions:[]},f=of({sessionName:n,appName:t,appBundleId:d,startup:c,device:r,runtime:l});return o.recordAction(p,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:f}),o.set(n,p),{ok:!0,data:f}}if("replay"===O){let e=i.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=tw.expandHome(e,i.meta?.cwd),r=$.readFileSync(t,"utf8"),l=r.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(tp(i)){let e=th(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return a9(r)&&a9(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=th(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(r),u=i.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let r=d[e];if(!r||"replay"===r.command)continue;let l=await s({token:i.token,session:n,command:r.command,positionals:r.positionals??[],flags:oW(i.flags,r.flags),meta:i.meta});if(l.ok)continue;if(!u)return oH(l,r,e,t);let p=await oJ({action:r,sessionName:n,logPath:a,sessionStore:o,dispatch:N});if(!p)return oH(l,r,e,t);if(d[e]=p,!(l=await s({token:i.token,session:n,command:p.command,positionals:p.positionals??[],flags:oW(i.flags,p.flags),meta:i.meta})).ok)return oH(l,p,e,t);c+=1}if(u&&c>0){let e=o.get(n);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",tf(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(tf(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(tf(r));return tm(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
35
|
+
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;$.writeFileSync(a,n),$.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:n}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(i.positionals?.[0]??"path").toLowerCase(),r=!!i.flags?.restart;if(!os.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:ol}};if(r&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=o.resolveAppLogPath(n),r=function(e){if(!$.existsSync(e))return{exists:!1,sizeBytes:0};let t=$.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),i=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:i,sizeBytes:r.sizeBytes,modifiedAt:r.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===t){let t=o.resolveAppLogPath(n),r=await tM(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:r.checks,notes:r.notes}}}if("mark"===t){let e,t=i.positionals?.slice(1).join(" ")??"",r=o.resolveAppLogPath(n);return tk(r),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
|
|
36
|
+
`,$.appendFileSync(r,e,"utf8"),{ok:!0,data:{path:r,marked:!0}}}if("clear"===t){if(e.appLog&&!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(r){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!nZ("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=o.resolveAppLogPath(n);if(r){e.appLog&&await m.stop(e.appLog);let r=tx(t),i=o.resolveAppLogPidPath(n);try{let a=await m.start(e.device,e.appBundleId,t,i),s={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return o.set(n,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=_(r);return o.set(n,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:tx(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!nZ("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=o.resolveAppLogPath(n),r=o.resolveAppLogPidPath(n);try{let i=await m.start(e.device,e.appBundleId,t,r),a={...e,appLog:{platform:e.device.platform,backend:i.backend,outPath:t,startedAt:i.startedAt,getState:i.getState,stop:i.stop,wait:i.wait}};return o.set(n,a),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:_(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await m.stop(e.appLog),o.set(n,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(i.positionals?.[0]??"dump").toLowerCase();if(!ov.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:oA}};let r=i.positionals?.[1],a=r?Number.parseInt(r,10):25;if(!Number.isInteger(a)||a<1||a>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(i.positionals?.[2]??"summary").toLowerCase();if(!oy.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:ob}};let l=function(e,t){let r=aT(t?.maxEntries,25,1,200),i=t?.include??"summary",n=aT(t?.maxPayloadChars,2048,64,16384),a=aT(t?.maxScanLines,4e3,100,2e4);if(!$.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=$.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=aM(n,["method","httpMethod"]),o=aM(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=ak.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=aO.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of aL){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:aR(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return aC(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=aR(t,i))}if("body"===r||"all"===r){let t=ax(e,n,["requestBody","body","payload","request"]),r=ax(e,n,["responseBody","response"]);t&&(f.requestBody=aR(t,i)),r&&(f.responseBody=aR(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(o.resolveAppLogPath(n),{maxEntries:a,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===O)return await oj(i,n,s);if("close"===O){let e=o.get(n);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await m.stop(e.appLog),i.positionals&&i.positionals.length>0&&("ios"===e.device.platform&&await E(e.device.id),await N(e.device,"close",i.positionals,i.flags?.out,{...nQ(a,i.flags,e.appBundleId,e.trace?.outPath)}),await k(e.device,oc)),"ios"===e.device.platform&&await E(e.device.id),aj(o.getRuntimeHints(n))&&e.appBundleId&&await A({device:e.device,appId:e.appBundleId}).catch(()=>{}),o.recordAction(e,{command:O,positionals:i.positionals??[],flags:i.flags??{},result:{session:n}}),i.flags?.saveScript&&(e.recordSession=!0),o.writeSessionLog(e),o.delete(n),i.flags?.shutdown&&o_(e.device)){let t;try{t=await (b??iJ)(e.device)}catch(r){let e=_(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:n,shutdown:t}}}return{ok:!0,data:{session:n}}}return null}async function oj(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??C;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=c(e.flags?.batchSteps,n),a=Date.now(),o=[];for(let n=0;n<i.length;n+=1){let a=i[n],s=await oq(e,t,a,r,n+1);if(!s.ok)return{ok:!1,error:{code:s.error.code,message:`Batch failed at step ${s.step} (${a.command}): ${s.error.message}`,hint:s.error.hint,diagnosticId:s.error.diagnosticId,logPath:s.error.logPath,details:{...s.error.details??{},step:s.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:o}}};o.push(s.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:o}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function oq(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of oa)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function oH(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>tf(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function oW(e,t){let r={...t??{}},i=e??{};for(let e of oo)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function oJ(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(tp(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=tp(t.command)||"fill"===t.command,l=tp(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await oz(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),tp(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=ah(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=a6(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return tl(t).filter(e=>e.trim().length>0)}(t)){let r=au(e);if(!r)continue;let i=ac(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=aI(i.node,o.device.platform,{action:tp(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(tp(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ts(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=ah(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=a6(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=au(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(ai(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=aa(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(ai(e.type??"")))});if(0===s.length||1!==tl(s.map(e=>aa(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=aI(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function oz(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nQ(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:n8(t.flags?.snapshotRaw?s:ar(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function oK(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function oX(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function oY(e,t){return t.flatten?e.map(e=>({text:i(e,0,!1),comparable:oX(e,0)})):y(e).map(e=>({text:e.text,comparable:oX(e.node,e.depth)}))}function oZ(e,t){return e.get(t)??0}async function oQ(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??nX,o=e.runnerCommand??ta,s=t.command;if("snapshot"===s){let{session:e,device:o}=await o2(n,r,t.flags);if(!nZ("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=o1(t.flags?.snapshotScope,e);return s.ok?await o3(e,o,async()=>{let l=e?.appBundleId,d=await o0({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return o4(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===s){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await o2(n,r,t.flags);if(!nZ("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=o1(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await o3(e,o,async()=>{let d=e?.appBundleId,u=(await o0({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return oY(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return o4(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&oZ(a,n-1)<oZ(a,n+1)?oZ(a,n+1):oZ(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&oZ(n,l-1)<oZ(n,l+1)?l+1:l-1,u=oZ(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(oY(e,r),oY(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return o4(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===s){let{session:e,device:o}=await o2(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=oK(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=oK(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=oK(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=oK(e[e.length-1]),i=am(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=au(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),o4(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):nZ("wait",o)?await o3(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...nQ(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=n8(t.flags?.snapshotRaw?u:ar(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=ap(c,s.selector,{platform:o.platform});if(p)return o4(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=n5(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=n6(e.snapshot.nodes,t),i=r?ae(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await ta(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return o4(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&n7(n8((await rZ(o,{scope:l})).nodes??[]),l))return o4(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===s){let{session:e,device:a}=await o2(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return nZ("alert",a)?await o3(e,a,async()=>{if("wait"===s){let r=oK(t.positionals?.[1])??1e4,s=Date.now();for(;Date.now()-s<r;){try{let r=await o(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return o4(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r="accept"===s||"dismiss"===s?s:"get",l={verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId};if("accept"===r||"dismiss"===r){let i,s=Date.now();for(;Date.now()-s<2e3;){try{let i=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return o4(n,e,t,i),{ok:!0,data:i}}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await new Promise(e=>setTimeout(e,300))}throw i}let d=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return o4(n,e,t,d),{ok:!0,data:d}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===s){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:f}};let{session:s,device:l}=await o2(n,r,t.flags);return nZ("settings",l)?await o3(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await nX(l,"settings",d,t.flags?.out,{...nQ(i,t.flags,r,s?.trace?.outPath)});return o4(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function o0(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nQ(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:n8(n.flags?.snapshotRaw?l:ar(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function o1(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=n5(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=n6(t.snapshot.nodes,r),n=i?ae(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function o2(e,t,r){let i=e.get(t),n=i?.device??await nK(r??{});return i||await n1(n),{session:i,device:n}}async function o3(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await e9(t.id)}}function o4(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function o8(e,t,r,i={}){let n=o6(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return o5(e.label,r);case"value":return o5(e.value,r);case"id":return o5(e.identifier,r);default:return Math.max(o5(e.label,r),o5(e.value,r),o5(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function o5(e,t){let r=o6(e??"");return r?r===t?2:+!!r.includes(t):0}function o6(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function o9(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??nX,s=t.command;if("find"!==s)return null;let l=t.positionals??[];if(0===l.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:d,query:u,action:c,value:p,timeoutMs:f}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:oK(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(l);if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(r);if(!m&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await nK(t.flags??{});m||await n1(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,b=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nQ(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=n8(t.flags?.snapshotRaw?s:ar(s));return A=e,y=l,m&&(m.snapshot={nodes:l,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,m)),{nodes:l,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=f??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await b();if(o8(e,d,u,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await b(),S=o8(N,d,u,{requireRect:v});if(v&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=aa(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:S.matches.length,candidates:e}}}}let _=S.matches[0]??null;if(!_)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let D="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,_)??_:_,E=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=aa(_);return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get text",text:e}}),{ok:!0,data:{ref:E,text:e,node:_}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get attrs"}}),{ok:!0,data:{ref:E,node:_}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[E],flags:k});if(!e.ok)return e;let i=D.rect?n9(D.rect):null,o={ref:E,locator:d,query:u};return i&&(o.x=i.x,o.y=i.y),m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"click",locator:d,query:u}}),{ok:!0,data:o}}if("fill"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[E,p],flags:k});return e.ok&&m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"fill"}}),e}if("focus"===c){let e=_.rect?n9(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nQ(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"focus"}}),{ok:!0,data:r??{ref:E}}}if("type"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=_.rect?n9(_.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...nQ(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nQ(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"type"}}),{ok:!0,data:r??{ref:E}}}return null}function o7(e){return e instanceof Error?e.message:String(e)}function se(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function st(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function sr(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:ta},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await nK(t.flags??{});d||await n1(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!nZ("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?se(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=tw.expandHome(d,t.meta?.cwd),h=t.meta?.clientArtifactPaths?.outPath;$.mkdirSync(n.dirname(m),{recursive:!0});let w=st(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},w)};try{await n()}catch(e){if(!o7(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o7(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o7(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},w)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${o7(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,clientOutPath:h,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",e_(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,clientOutPath:h,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,clientOutPath:h,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:h??d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=se(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},st(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:o7(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of eY)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}});let m=[{field:"outPath",path:f.outPath,localPath:f.clientOutPath,fileName:n.basename(f.clientOutPath??f.outPath)}];return{ok:!0,data:{recording:"stopped",outPath:f.outPath,artifacts:m}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=tw.expandHome(e);return $.mkdirSync(n.dirname(r),{recursive:!0}),$.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=tw.expandHome(t.positionals[1]);$.mkdirSync(n.dirname(e),{recursive:!0}),$.existsSync(o)?$.renameSync(o,e):$.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function si(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function sn(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function sa(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function so(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??nX,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nZ("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=sd("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=su({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=sc(p.rect);if(!m){let r=await ss(e,t.flags,i,n,{interactiveOnly:!0},a),o=n6(r.nodes,c),l=s.length>0?n7(r.nodes,s):null,d=sc(l?.rect),u=sc(o?.rect)?o:d?l:o??l,h=sc(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=ae(p,f),w=aI(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=ad(u),p=await ss(e,t.flags,i,n,{interactiveOnly:!0},a),f=await L("selector_resolve",()=>ac(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:af(c,f?.diagnostics??[],{unique:!0})}};let m=sc(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=aI(f.node,e.device.platform,{action:l}),v=ae(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!nZ("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=sd("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=su({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!an(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=ae(c,p),w=aI(c,e.device.platform,{action:"fill"}),{x:g,y:I}=n9(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=am(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=ad(s.selectorExpression),d=await ss(e,t.flags,i,n,{interactiveOnly:!0},a),u=await L("selector_resolve",()=>ac(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:af(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!an(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=n9(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=aI(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:ae(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nZ("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=sd("get",t.flags);if(r)return r;let n=su({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=aI(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=aa(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=ad(d),c=await ss(s,t.flags,i,n,{interactiveOnly:!1},a),p=await L("selector_resolve",()=>ac(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:af(u,[],{unique:!0})}};let f=p.node,m=aI(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=aa(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nZ("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=ah(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=ad(l.selectorExpression),c=await ss(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=ap(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:af(u,[],{unique:!1})}}}let p=await L("selector_resolve",()=>ac(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:af(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=aa(r),o=!1;switch(t){case"visible":o=aw(r);break;case"hidden":o=!aw(r);break;case"editable":o=ag(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:aw(r),editable:ag(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!nZ("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=sd("scrollintoview",t.flags);if(l)return l;let d=su({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=n9(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=sn(n.map(e=>e.rect).filter(e=>si(e,r.x,r.y)));if(a)return a;let o=sn(n.map(e=>e.rect));if(o)return o;let s=sn(i.map(e=>e.rect).filter(e=>si(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:sa(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:sa(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=ae(c,p),w=aI(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function ss(e,t,r,i,n,a=nX){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:n8(t?.snapshotRaw?s:ar(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let sl=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function sd(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of sl)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function su(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=n5(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=n6(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=n7(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function sc(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=n9(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function sp(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function sf(e){let{req:t,leaseRegistry:r}=e,i=sp(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let sm=new Set(["session_list","devices","ensure-simulator"]),sh=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]);function sw(e,t,r,i){let n=O().requestId;return{...nQ(e,t,r,i,n),requestId:n}}function sg(e){$.existsSync(e)&&$.unlinkSync(e)}function sI(e){if(!$.existsSync(e))return null;try{let t=JSON.parse($.readFileSync(e,"utf8"));if(!Number.isInteger(t.pid)||t.pid<=0)return null;return t}catch{return null}}function sv(e){let t=sI(e);if(!t||t.pid===process.pid)try{$.existsSync(e)&&$.unlinkSync(e)}catch{}}function sA(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}let{baseDir:sy,infoPath:sb,lockPath:sN,logPath:sS,sessionsDir:s_}=B(process.env.AGENT_DEVICE_STATE_DIR),sD=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var sE=s_;if($.existsSync(sE))for(let e of $.readdirSync(sE,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(sE,e.name,"app-log.pid");if($.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}($.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{tI(t)}}let sk=new tw(s_),sO=new t3({maxActiveSimulatorLeases:sA(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:sA(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:sA(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:sA(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),sL=E(),sM=u.randomBytes(24).toString("hex"),sx=T(process.pid)??void 0,sC=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=$.statSync(e),r=k(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}(),sR=function(e){let{logPath:t,token:r,sessionStore:i,leaseRegistry:a,trackDownloadableArtifact:s}=e;async function l(e){let d="click"===e.command?{...e,command:"press"}:e,u=!!(d.meta?.debug||d.flags?.verbose);return await P({session:d.session,requestId:d.meta?.requestId,command:d.command,debug:u,logPath:t},async()=>{if(d.token!==r)return{ok:!1,error:_(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=D(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=o(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(d);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let r=e.command,u=t=>(function(e,t,r){let i=O();if(!t.ok){M({level:"error",phase:"request_failed",data:{code:t.error.code,message:t.error.message}});let e=F({force:!0})??void 0;return{ok:!1,error:_(new I(t.error.code,t.error.message,{...t.error.details??{},hint:t.error.hint,diagnosticId:t.error.diagnosticId,logPath:t.error.logPath}),{diagnosticId:i.diagnosticId,logPath:e})}}return M({level:"info",phase:"request_success"}),F(),{ok:!0,data:function(e,t,r){var i,a;let o;if(!t)return t;let s=(i=e,a=t,o=Array.isArray(a.artifacts)?[...a.artifacts]:[],"screenshot"!==i.command||o.some(e=>e?.field==="path")||"string"!=typeof a.path||o.push({field:"path",path:a.path,localPath:i.meta?.clientArtifactPaths?.path,fileName:n.basename(i.meta?.clientArtifactPaths?.path??a.path)}),o.filter(e=>!!(e&&"string"==typeof e.field&&"string"==typeof e.path&&"string"==typeof e.localPath&&e.localPath.length>0)));return 0===s.length?t:{...t,artifacts:s.map(t=>{let i=t.path;return{field:t.field,artifactId:r({artifactPath:i,tenantId:e.meta?.tenantId,fileName:t.fileName}),fileName:t.fileName,localPath:t.localPath}})}}(e,t.data,r)}})(e,t,s),c=sp(e);sh.has(r)||e.meta?.sessionIsolation!=="tenant"||a.assertLeaseAdmission({tenantId:c.tenantId,runId:c.runId,leaseId:c.leaseId,backend:c.leaseBackend});let p=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,i),f=i.get(p);f&&!sm.has(r)&&function(e,t){if(!t)return;let r=[],i=e.device,n=ej(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=eb(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(f,e.flags);let m=await sf({req:e,leaseRegistry:a});if(m)return u(m);let h=await oB({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(h)return u(h);let w=await oQ({req:e,sessionName:p,logPath:t,sessionStore:i});if(w)return u(w);let g=await sr({req:e,sessionName:p,sessionStore:i,logPath:t});if(g)return u(g);let v=await o9({req:e,sessionName:p,logPath:t,sessionStore:i,invoke:l});if(v)return u(v);let A=await so({req:e,sessionName:p,sessionStore:i,contextFromFlags:(e,r,i)=>sw(t,e,r,i)});if(A)return u(A);let y=i.get(p);if(!y)return u({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!nZ(r,y.device))return u({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}});let b=await nX(y.device,r,e.positionals??[],e.flags?.out,{...sw(t,e.flags,y.appBundleId,y.trace?.outPath)});return i.recordAction(y,{command:r,positionals:e.positionals??[],flags:e.flags??{},result:b??{}}),u({ok:!0,data:b??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=O(),t=F({force:!0})??void 0;return{ok:!1,error:_(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}return l}({logPath:sS,token:sM,sessionStore:sk,leaseRegistry:sO,trackDownloadableArtifact:function(e){let t=u.randomUUID(),r=setTimeout(()=>{tR(t)},9e5);return tC.set(t,{artifactPath:e.artifactPath,tenantId:e.tenantId,fileName:e.fileName,deleteAfterDownload:!1!==e.deleteAfterDownload,timer:r}),t}});!async function(){let e,t;if(!function(e,t,r){$.existsSync(e)||$.mkdirSync(e,{recursive:!0});let i=JSON.stringify(r,null,2),n=()=>{try{return $.writeFileSync(t,i,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(n())return!0;let a=sI(t);if(a?.pid&&a.pid!==process.pid&&s(a.pid,a.processStartTime))return!1;try{$.unlinkSync(t)}catch{}return n()}(sy,sN,{pid:process.pid,version:sL,startedAt:Date.now(),processStartTime:sx})){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===sD||"dual"===sD){let t=U.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))ea(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await e7(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,o,s=t.slice(0,a).trim();if(t=t.slice(a+1),0===s.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(s);if(o=ei(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),en(o),es(o))throw el();n=await sR(e)}catch(e){n={ok:!1,error:_(e)}}finally{r-=1,o&&(i.delete(o),eo(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
37
|
+
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===sD||"dual"===sD){let e=await tX({handleRequest:sR,token:sM});r.push(e),t=await new Promise((t,r)=>{e.once("error",r),e.listen(0,"127.0.0.1",()=>{e.off("error",r);let i=e.address();"object"==typeof i&&i?.port?t(i.port):r(new I("COMMAND_FAILED","Failed to bind HTTP server"))})})}i={socketPort:e,httpPort:t,token:sM,version:sL,codeSignature:sC,processStartTime:sx},$.existsSync(sy)||$.mkdirSync(sy,{recursive:!0}),$.writeFileSync(sS,""),n=i.socketPort&&i.httpPort?"dual":i.httpPort?"http":"socket",$.writeFileSync(sb,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:i.token,pid:process.pid,version:i.version,codeSignature:i.codeSignature,processStartTime:i.processStartTime,stateDir:sy},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
38
38
|
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
39
39
|
`)}catch(t){let e=w(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|
|
40
|
-
`),r))try{t.close(()=>{})}catch{}
|
|
40
|
+
`),r))try{t.close(()=>{})}catch{}sg(sb),sv(sN),process.exit(1);return}let n=!1,a=async()=>{await Promise.all(r.map(async e=>{await new Promise(t=>{try{e.close(()=>t())}catch{t()}})}))},o=async()=>{if(!n){for(let e of(n=!0,await a(),sk.toArray()))sk.writeSessionLog(e);await te(),sg(sb),sv(sN),process.exit(0)}};process.on("SIGINT",()=>{o()}),process.on("SIGTERM",()=>{o()}),process.on("SIGHUP",()=>{o()}),process.on("uncaughtException",e=>{let t=e instanceof I?e:w(e);process.stderr.write(`Daemon error: ${t.message}
|
|
41
41
|
`),o()})}();
|
package/package.json
CHANGED
|
@@ -28,6 +28,14 @@ Use this skill as a router, not a full manual.
|
|
|
28
28
|
- Remote multi-tenant run: allocate lease -> point client at remote daemon base URL -> run commands with tenant isolation flags -> heartbeat/release lease
|
|
29
29
|
- Device-scope isolation run: set iOS simulator set / Android allowlist -> run selectors within scope only
|
|
30
30
|
|
|
31
|
+
## Target Selection Rules
|
|
32
|
+
|
|
33
|
+
- iOS local QA: use simulators unless the task explicitly requires a physical device.
|
|
34
|
+
- iOS local QA in mixed simulator/device environments: run `ensure-simulator` first and pass `--device`, `--udid`, or `--ios-simulator-device-set` on later commands.
|
|
35
|
+
- Android local QA: use `install` or `reinstall` for `.apk`/`.aab` files, then relaunch by installed package name.
|
|
36
|
+
- Android React Native + Metro flows: set runtime hints with `runtime set` before `open <package> --relaunch`.
|
|
37
|
+
- In mixed-device environments, always pin the exact target with `--serial`, `--device`, `--udid`, or an isolation scope.
|
|
38
|
+
|
|
31
39
|
## Canonical Flows
|
|
32
40
|
|
|
33
41
|
### 1) Normal Interaction Flow
|
|
@@ -41,6 +49,30 @@ agent-device fill @e5 "test"
|
|
|
41
49
|
agent-device close
|
|
42
50
|
```
|
|
43
51
|
|
|
52
|
+
### 1a) Local iOS Simulator QA Flow
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
agent-device ensure-simulator --platform ios --device "iPhone 16" --boot
|
|
56
|
+
agent-device open MyApp --platform ios --device "iPhone 16" --session qa-ios --relaunch
|
|
57
|
+
agent-device snapshot -i
|
|
58
|
+
agent-device press @e3
|
|
59
|
+
agent-device close
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use this when a physical iPhone is also connected and you want deterministic simulator-only automation.
|
|
63
|
+
|
|
64
|
+
### 1b) Android React Native + Metro QA Flow
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
agent-device reinstall MyApp /path/to/app-debug.apk --platform android --serial emulator-5554
|
|
68
|
+
agent-device runtime set --session qa-android --platform android --metro-host 10.0.2.2 --metro-port 8081
|
|
69
|
+
agent-device open com.example.myapp --platform android --serial emulator-5554 --session qa-android --relaunch
|
|
70
|
+
agent-device snapshot -i
|
|
71
|
+
agent-device close
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Do not use `open <apk|aab> --relaunch` on Android. Install/reinstall binaries first, then relaunch by package.
|
|
75
|
+
|
|
44
76
|
### 2) Debug/Crash Flow
|
|
45
77
|
|
|
46
78
|
```bash
|
|
@@ -118,6 +150,8 @@ Use `boot` only as fallback when `open` cannot find/connect to a ready target.
|
|
|
118
150
|
For Android emulators by AVD name, use `boot --platform android --device <avd-name>`.
|
|
119
151
|
For Android emulators without GUI, add `--headless`.
|
|
120
152
|
Use `--target mobile|tv` with `--platform` (required) to pick phone/tablet vs TV targets (AndroidTV/tvOS).
|
|
153
|
+
For Android React Native + Metro flows, install or reinstall the APK first, set runtime hints with `runtime set`, then use `open <package> --relaunch`; do not use `open <apk|aab> --relaunch`.
|
|
154
|
+
For local iOS QA in mixed simulator/device environments, use `ensure-simulator` and pass `--device` or `--udid` so automation does not attach to a physical device by accident.
|
|
121
155
|
|
|
122
156
|
Isolation scoping quick reference:
|
|
123
157
|
- `--ios-simulator-device-set <path>` scopes iOS simulator discovery + command execution to one simulator set.
|
|
@@ -219,6 +253,12 @@ agent-device batch --steps-file /tmp/batch-steps.json --json
|
|
|
219
253
|
`AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST` (compat `ANDROID_DEVICE_ALLOWLIST`).
|
|
220
254
|
- For explicit remote client mode, prefer `AGENT_DEVICE_DAEMON_BASE_URL` / `--daemon-base-url` instead of relying on local daemon metadata or loopback-only ports.
|
|
221
255
|
|
|
256
|
+
## Common Failure Patterns
|
|
257
|
+
|
|
258
|
+
- `Failed to access Android app sandbox for /path/app-debug.apk`: Android relaunch/runtime-hint flow received an APK path instead of an installed package name. Use `reinstall` first, then `open <package> --relaunch`.
|
|
259
|
+
- `mkdir: Needs 1 argument` while writing `ReactNativeDevPrefs.xml`: likely an older `agent-device` build or stale global install is still using the shell-based Android runtime-hint writer. Verify the exact binary being invoked.
|
|
260
|
+
- `Failed to terminate iOS app`: the flow may have selected a physical iPhone or an unavailable iOS target. Re-run with `ensure-simulator`, then pin the simulator with `--device` or `--udid`.
|
|
261
|
+
|
|
222
262
|
## Security and Trust Notes
|
|
223
263
|
|
|
224
264
|
- Prefer a preinstalled `agent-device` binary over on-demand package execution.
|