agent-device 0.7.10 → 0.7.11
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 +1 -1
- package/package.json +1 -1
package/dist/src/daemon.js
CHANGED
|
@@ -30,7 +30,7 @@ ${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode de
|
|
|
30
30
|
`)}function nq(e){if(e&&R.existsSync(e))try{R.unlinkSync(e)}catch{}}async function nW(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function nH(e){await new Promise(t=>setTimeout(t,e))}function nJ(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}
|
|
31
31
|
`)},flush:()=>{i&&(n(i),i="")}}}function nz(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 nK(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 nX(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await nK(e,t);if(!d){await nH(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=nJ(r,{redactionPatterns:i});o=nz(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&nj(n,u.pid);let p=await o;if(nq(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await nH(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),nq(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await nW(o),a&&!a.killed&&a.kill("SIGKILL"),await nW(d),nq(n)}}}async function nY(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=nJ(t,{redactionPatterns:r});"number"==typeof a.pid&&nj(i,a.pid);let s=nz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nq(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nW(s),a.killed||a.kill("SIGKILL"),await nW(s),nq(i)}}}async function nZ(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=nJ(t,{redactionPatterns:r});"number"==typeof a.pid&&nj(i,a.pid);let s=nz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nq(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nW(s),a.killed||a.kill("SIGKILL"),await nW(s),nq(i)}}}function nQ(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 n0(e){let t=n.dirname(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),function(e,t){if(R.existsSync(e)&&!(R.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}`;R.existsSync(t)&&(R.existsSync(i)&&R.unlinkSync(i),R.renameSync(t,i))}}(e,{maxBytes:nQ("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:nQ("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function n1(e,t,r,i){n0(r);let n=R.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 nZ(e.id,n,a,i):await nY(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 nX(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function n2(e){await e.stop(),await nW(e.wait)}async function n3(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 n4(e){let t=n.dirname(e),r=n.basename(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),R.existsSync(e)?R.truncateSync(e,0):R.writeFileSync(e,"","utf8");let i=0;for(let e of R.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{R.unlinkSync(n.join(t,e)),i+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:i}}let n8=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),n5=/https?:\/\/[^\s"'<>\])]+/i,n6=[/\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 n9(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 n7(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return ae(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 ae(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function at(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function ar(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}function ai(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=nO(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 an(e){return!!e&&!Number.isNaN(Number(e))}async function aa(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 ao({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await as({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await al(t,u),i=!0)}else t=(await as({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await al(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 ao(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",tX(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:tU});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||ad(i).includes(ad(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 as(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",tX(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 al(e,t){let r=await p("xcrun",tX(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:tU});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 ad(e){return e.toLowerCase().replace(/[._-]/g,"")}let au='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',ac=["platform","target","device","udid","serial","verbose","out"],ap=["platform","target","device","udid","serial","verbose","out"],af=["path","start","stop","doctor","mark","clear"],am=`logs requires ${af.slice(0,-1).join(", ")}, or ${af.at(-1)}`,ah="Not implemented for this platform in this release.",aw="open-command-roundtrip",ag=tV(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),aI=tV(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function av(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a}=e,o={session:t};return r&&(o.appName=r),i&&(o.appBundleId=i),n&&(o.startup=n),a?.platform==="ios"&&(o.device_udid=a.id,o.ios_simulator_device_set=a.simulatorSetPath??null),o}function aA(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:aw,appTarget:t,appBundleId:r}}let ay=["dump","log"],aS=`network requires ${ay.join(" or ")}`,aN=["summary","headers","body","all"],ab=`network include mode must be one of: ${aN.join(", ")}`;function a_(e,t,r){return t||aD(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function aD(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function aE(e){return"ios"===e.platform&&"simulator"===e.kind}async function ak(e,t){aE(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function aO(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,ag)}async function aL(e){let t=aD(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function aM(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 ax=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:eL}));return await i({avdName:e,serial:t,headless:r})};async function aC(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=a_(l,p,f);if(m)return m;let h=await aL({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!i1(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,{...nr(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 aT={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:iw}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e0}));return await i(e,t,r)}},aR={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:ih}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await aG(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:eQ}));await i(e,r);let{package:n}=await aG(e,t);return n?{package:n}:{}}};async function aP(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=a_(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=ni.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):nt.expandHome(p);if(!R.existsSync(i))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${i}`}};let u=await aL({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!1});if(!i1(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&&nn(f)}}async function a$(e,t,r){if("ios"===e.platform&&t)return J(t)?"device"===e.kind?z(r,t):void 0:await aF(e,t)}async function aF(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:id}));return await r(e,t)}catch{return}}async function aV(e,t){if(!("android"!==e.platform||!t||J(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eP})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function aG(e,t){return"ios"===e.platform?{bundleId:await aF(e,t)}:{package:await aV(e,t)}}async function aU(e,t,r,i){return await a$(e,t,r)??await i(e,t)??("android"===e.platform&&t&&J(t)?r:void 0)}async function aB(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=r_(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=a_("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!aD(e))return!0;let r=r_(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:au}};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 aL({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:au}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eU})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function aj(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=a_("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 aL({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!i1("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,{...nr(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 aq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a,dispatch:o,ensureReady:s,resolveTargetDevice:l,installOps:d=aR,reinstallOps:u=aT,stopIosRunner:c,appLogOps:p={start:n1,stop:n2},ensureAndroidEmulatorBoot:f=ax,resolveAndroidPackageForOpen:m=aV,settleSimulator:h,shutdownSimulator:g}=e,v=o??iQ,A=s??no,y=l??iZ,S=c??rq,N=h??ak,_=t.command;if("session_list"===_)return{ok:!0,data:{sessions:n.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("ensure-simulator"===_)try{let e=t.flags??{},r=e.device,i=e.runtime,n=el(e.iosSimulatorDeviceSet);if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await aa({deviceName:r,runtime:i,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:A});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"===_)try{let e=[],r=el(t.flags?.iosSimulatorDeviceSet),i=eu(t.flags?.androidDeviceAllowlist),n=r_(t.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eb}));e.push(...await t({serialAllowlist:i}))}else if("ios"===n){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:iY}));e.push(...await t({simulatorSetPath:r}))}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eb})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:iY}));try{e.push(...await t({serialAllowlist:i}))}catch{}try{e.push(...await n({simulatorSetPath:r}))}catch{}}let a=(t.flags?.target?e.filter(e=>(e.target??"mobile")===t.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"===_){let e=n.get(r),i=t.flags??{},a=a_(_,e,i);if(a)return a;let o=await aL({session:e,flags:i,ensureReadyFn:A,resolveTargetDeviceFn:y,ensureReady:!0});if(!i1("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=t.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:iy}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:e$}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===_){let e,i=n.get(r),a=t.flags??{},o=a_(_,i,a);if(o)return o;let s="android"===(r_(a.platform)??i?.device.platform),l=!0===a.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=aM({flags:a,sessionDevice:i?.device}),u=s&&!!d,c=!1;try{e=await aL({session:i,flags:a,ensureReadyFn:A,resolveTargetDeviceFn:y,ensureReady:!1})}catch(r){let t=w(r);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 r;e=await f({avdName:d,serial:a.serial,headless:l}),c=!0}if(a.target&&(e.target??"mobile")!==a.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${a.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 t=aM({flags:a,sessionDevice:i?.device,resolvedDevice:e});if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await f({avdName:t,serial:a.serial,headless:!0})}await A(e)}else("android"!==e.platform||!0!==e.booted)&&await A(e);return i1("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"===_)return await aB({req:t,sessionName:r,sessionStore:n,ensureReady:A,resolveDevice:y});if("clipboard"===_)return await aj({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v});if("keyboard"===_)return await aC({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"keyboard",positionals:t.positionals??[]});if("perf"===_){let e,t,i,a=n.get(r);return a?{ok:!0,data:(i=(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===aw&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:aw,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)}(a.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:aw,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:aw},{session:a.name,platform:a.device.platform,device:a.device.name,deviceId:a.device.id,metrics:{startup:i,fps:{available:!1,reason:ah},memory:{available:!1,reason:ah},cpu:{available:!1,reason:ah}},sampling:{startup:{method:aw,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"===_||"reinstall"===_)return await aP({req:t,command:_,sessionName:r,sessionStore:n,ensureReady:A,resolveDevice:y,deployOps:"install"===_?d:u});if("push"===_){let e,a=t.positionals?.[0]?.trim(),o=t.positionals?.[1]?.trim();if(!a||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=iF(o,{subject:"Push payload",cwd:t.meta?.cwd,expandPath:(e,t)=>nt.expandHome(e,t)})).kind?e.path:e.text;return await aC({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"push",positionals:[a,s],recordPositionals:[a,o]})}if("trigger-app-event"===_)return await aC({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"trigger-app-event",positionals:t.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await aU(e.device,r,e.appBundleId,m)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===_){let e=t.flags?.relaunch===!0;if(n.has(r)){let a=n.get(r),o=t.positionals?.[0],s=o??(e?a?.appName:void 0);if(!a||!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&&J(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await A(a.device);let l=await aU(a.device,s,a.appBundleId,m),d=o?t.positionals??[]:[s];if(e){let e=l??s;await aO({device:a.device,closeTarget:e,stopIosRunner:S,dispatch:v,outFlag:t.flags?.out,context:{...nr(i,t.flags,l??a.appBundleId,a.trace?.outPath)},settleSimulator:N})}let u=Date.now();await v(a.device,"open",d,t.flags?.out,{...nr(i,t.flags,l)});let c=aA(u,s,l);await N(a.device,aI);let p={...a,appBundleId:l,appName:s,recordSession:a.recordSession||!!t.flags?.saveScript,snapshot:void 0},f=av({sessionName:r,appName:s,appBundleId:l,startup:c,device:a.device});return n.recordAction(p,{command:_,positionals:d,flags:t.flags??{},result:f}),n.set(r,p),{ok:!0,data:f}}let a=t.positionals?.[0];if(e&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&a&&J(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let o=await y(t.flags??{}),s=n.toArray().find(e=>e.device.id===o.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:o.id,deviceName:o.name}}};await A(o);let l=await aU(o,a,void 0,m);if(e&&a){let e=l??a;await aO({device:o,closeTarget:e,stopIosRunner:S,dispatch:v,outFlag:t.flags?.out,context:{...nr(i,t.flags,l)},settleSimulator:N})}let d=Date.now();await v(o,"open",t.positionals??[],t.flags?.out,{...nr(i,t.flags,l)});let u=a?aA(d,a,l):void 0;await N(o,aI);let c={name:r,device:o,createdAt:Date.now(),appBundleId:l,appName:a,recordSession:!!t.flags?.saveScript,actions:[]},p=av({sessionName:r,appName:a,appBundleId:l,startup:u,device:o});return n.recordAction(c,{command:_,positionals:t.positionals??[],flags:t.flags??{},result:p}),n.set(r,c),{ok:!0,data:p}}if("replay"===_){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=nt.expandHome(e,t.meta?.cwd),s=R.readFileSync(o,"utf8"),l=s.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(i6(i)){let e=ne(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 an(r)&&an(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=ne(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}(s),u=t.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await a({token:t.token,session:r,command:s.command,positionals:s.positionals??[],flags:az(t.flags,s.flags),meta:t.meta});if(l.ok)continue;if(!u)return aJ(l,s,e,o);let p=await aK({action:s,sessionName:r,logPath:i,sessionStore:n,dispatch:v});if(!p)return aJ(l,s,e,o);if(d[e]=p,!(l=await a({token:t.token,session:r,command:p.command,positionals:p.positionals??[],flags:az(t.flags,p.flags),meta:t.meta})).ok)return aJ(l,p,e,o);c+=1}if(u&&c>0){let e=n.get(r);!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",i9(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(i9(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(i9(r));return i7(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
32
32
|
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;R.writeFileSync(a,n),R.renameSync(a,e)}(o,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:r}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===_){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let i=(t.positionals?.[0]??"path").toLowerCase(),a=!!t.flags?.restart;if(!af.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:am}};if(a&&"clear"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===i){let t=n.resolveAppLogPath(r),i=function(e){if(!R.existsSync(e))return{exists:!1,sizeBytes:0};let t=R.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),a=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:a,sizeBytes:i.sizeBytes,modifiedAt:i.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"===i){let t=n.resolveAppLogPath(r),i=await n3(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:i.checks,notes:i.notes}}}if("mark"===i){let e,i=t.positionals?.slice(1).join(" ")??"",a=n.resolveAppLogPath(r);return n0(a),e=`[agent-device][mark][${new Date().toISOString()}] ${i.trim()||"marker"}
|
|
33
|
-
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!i1("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await p.stop(e.appLog);let i=n4(t),a=n.resolveAppLogPidPath(r);try{let o=await p.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=b(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:n4(t)}}if("start"===i){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(!i1("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await p.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await p.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===_){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!ay.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:aS}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!aN.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:ab}};let l=function(e,t){let r=ar(t?.maxEntries,25,1,200),i=t?.include??"summary",n=ar(t?.maxPayloadChars,2048,64,16384),a=ar(t?.maxScanLines,4e3,100,2e4);if(!R.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=R.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=n9(n,["method","httpMethod"]),o=n9(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=n8.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=n5.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of n6){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:at(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 ae(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=at(t,i))}if("body"===r||"all"===r){let t=n7(e,n,["requestBody","body","payload","request"]),r=n7(e,n,["responseBody","response"]);t&&(f.requestBody=at(t,i)),r&&(f.responseBody=at(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}}}(n.resolveAppLogPath(r),{maxEntries:o,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"===_)return await aW(t,r,a);if("close"===_){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await p.stop(e.appLog),t.positionals&&t.positionals.length>0&&("ios"===e.device.platform&&await S(e.device.id),await v(e.device,"close",t.positionals,t.flags?.out,{...nr(i,t.flags,e.appBundleId,e.trace?.outPath)}),await N(e.device,ag)),"ios"===e.device.platform&&await S(e.device.id),n.recordAction(e,{command:_,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),t.flags?.shutdown&&aE(e.device)){let t;try{t=await (g??t1)(e.device)}catch(r){let e=b(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:r,shutdown:t}}}return{ok:!0,data:{session:r}}}return null}async function aW(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??M;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=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await aH(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function aH(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 ac)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 aJ(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>i9(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 az(e,t){let r={...t??{}},i=e??{};for(let e of ap)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function aK(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(i6(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=i6(t.command)||"fill"===t.command,l=i6(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await aX(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),i6(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}=nL(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=ai(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 i3(t).filter(e=>e.trim().length>0)}(t)){let r=n_(e);if(!r)continue;let i=nD(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=nC(i.node,o.device.platform,{action:i6(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(i6(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=i2(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}=nL(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}=ai(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=n_(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(nI(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=nA(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(nI(e.type??"")))});if(0===s.length||1!==i3(s.map(e=>nA(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=nC(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function aX(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nr(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:nu(t.flags?.snapshotRaw?s:ng(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function aY(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function aZ(e,t){let r=N(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 aQ(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:aZ(e,0)})):A(e).map(e=>({text:e.text,comparable:aZ(e.node,e.depth)}))}function a0(e,t){return e.get(t)??0}async function a1(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??iQ,o=e.runnerCommand??rY,s=t.command;if("snapshot"===s){let{session:e,device:o}=await a4(n,r,t.flags);if(!i1("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=a3(t.flags?.snapshotScope,e);return s.ok?await a8(e,o,async()=>{let l=e?.appBundleId,d=await a2({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 a5(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 a4(n,r,t.flags);if(!i1("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=a3(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await a8(e,o,async()=>{let d=e?.appBundleId,u=(await a2({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return aQ(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 a5(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&&a0(a,n-1)<a0(a,n+1)?a0(a,n+1):a0(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&&a0(n,l-1)<a0(n,l+1)?l+1:l-1,u=a0(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[]}(aQ(e,r),aQ(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 a5(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 a4(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=aY(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=aY(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=aY(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=aY(e[e.length-1]),i=nO(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=n_(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)),a5(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):i1("wait",o)?await a8(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,{...nr(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=nu(t.flags?.snapshotRaw?u:ng(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=nE(c,s.selector,{platform:o.platform});if(p)return a5(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=nc(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=np(e.snapshot.nodes,t),i=r?nh(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 rY(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 a5(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&nm(nu((await e6(o,{scope:l})).nodes??[]),l))return a5(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 a4(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return i1("alert",a)?await a8(e,a,async()=>{if("wait"===s){let r=aY(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 a5(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 a5(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 a5(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:c}};let{session:s,device:l}=await a4(n,r,t.flags);return i1("settings",l)?await a8(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await iQ(l,"settings",d,t.flags?.out,{...nr(i,t.flags,r,s?.trace?.outPath)});return a5(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 a2(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nr(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:nu(n.flags?.snapshotRaw?l:ng(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function a3(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=nc(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=np(t.snapshot.nodes,r),n=i?nh(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 a4(e,t,r){let i=e.get(t),n=i?.device??await iZ(r??{});return i||await no(n),{session:i,device:n}}async function a8(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rq(t.id)}}function a5(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function a6(e,t,r,i={}){let n=a7(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 a9(e.label,r);case"value":return a9(e.value,r);case"id":return a9(e.identifier,r);default:return Math.max(a9(e.label,r),a9(e.value,r),a9(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 a9(e,t){let r=a7(e??"");return r?r===t?2:+!!r.includes(t):0}function a7(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function oe(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??iQ,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:aY(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 iZ(t.flags??{});m||await no(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,S=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nr(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=nu(t.flags?.snapshotRaw?s:ng(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 S();if(a6(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 S(),b=a6(N,d,u,{requireRect:v});if(v&&b.matches.length>1){let e=b.matches.slice(0,8).map(e=>{let t=nA(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${b.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:b.matches.length,candidates:e}}}}let _=b.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=nA(_);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?nf(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?nf(_.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,{...nr(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?nf(_.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,{...nr(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nr(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 ot(e){return e instanceof Error?e.message:String(e)}function or(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function oi(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function on(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rY},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 iZ(t.flags??{});d||await no(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(!i1("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?or(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=nt.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=oi(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},h)};try{await n()}catch(e){if(!ot(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ot(e)}`}};{var l,u;L({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ot(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},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ot(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",tY(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,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,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: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=or(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},oi(t,a,p))}catch(e){L({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ot(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of rC)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}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}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=nt.expandHome(e);return R.mkdirSync(n.dirname(r),{recursive:!0}),R.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=nt.expandHome(t.positionals[1]);R.mkdirSync(n.dirname(e),{recursive:!0}),R.existsSync(o)?R.renameSync(o,e):R.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 oa(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function oo(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 os(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function ol(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??iQ,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(!i1("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=oc("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=op({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=of(p.rect);if(!m){let r=await od(e,t.flags,i,n,{interactiveOnly:!0},a),o=np(r.nodes,c),l=s.length>0?nm(r.nodes,s):null,d=of(l?.rect),u=of(o?.rect)?o:d?l:o??l,h=of(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=nh(p,f),w=nC(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=nb(u),p=await od(e,t.flags,i,n,{interactiveOnly:!0},a),f=await O("selector_resolve",()=>nD(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:nk(c,f?.diagnostics??[],{unique:!0})}};let m=of(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=nC(f.node,e.device.platform,{action:l}),v=nh(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&&!i1("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=oc("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=op({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&&!nv(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=nh(c,p),w=nC(c,e.device.platform,{action:"fill"}),{x:g,y:I}=nf(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=nO(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=nb(s.selectorExpression),d=await od(e,t.flags,i,n,{interactiveOnly:!0},a),u=await O("selector_resolve",()=>nD(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:nk(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!nv(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=nf(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=nC(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:nh(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(!i1("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=oc("get",t.flags);if(r)return r;let n=op({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=nC(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=nA(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=nb(d),c=await od(s,t.flags,i,n,{interactiveOnly:!1},a),p=await O("selector_resolve",()=>nD(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:nk(u,[],{unique:!0})}};let f=p.node,m=nC(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=nA(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(!i1("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=nL(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=nb(l.selectorExpression),c=await od(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=nE(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:nk(u,[],{unique:!1})}}}let p=await O("selector_resolve",()=>nD(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:nk(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=nA(r),o=!1;switch(t){case"visible":o=nM(r);break;case"hidden":o=!nM(r);break;case"editable":o=nx(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:nM(r),editable:nx(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(!i1("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=oc("scrollintoview",t.flags);if(l)return l;let d=op({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=nf(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=oo(n.map(e=>e.rect).filter(e=>oa(e,r.x,r.y)));if(a)return a;let o=oo(n.map(e=>e.rect));if(o)return o;let s=oo(i.map(e=>e.rect).filter(e=>oa(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:os(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:os(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=nh(c,p),w=nC(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 od(e,t,r,i,n,a=iQ){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:nu(t?.snapshotRaw?s:ng(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let ou=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function oc(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of ou)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 op(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=nc(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=np(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=nm(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 of(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=nf(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function om(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 oh(e){let{req:t,leaseRegistry:r}=e,i=om(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}}async function ow(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=R.mkdtempSync(n.join(F.tmpdir(),"agent-device-upload-"));try{if("file"===t){let t=n.join(a,i);return await og(e,t),{artifactPath:t,tempDir:a}}let r=n.join(a,"artifact.tar");await og(e,r),await oI(r,i),await p("tar",["xf",r,"-C",a]),R.rmSync(r,{force:!0});let o=n.join(a,i);if(!R.existsSync(o))throw new I("INVALID_ARGS",`Expected extracted bundle "${i}" not found in archive`);return{artifactPath:o,tempDir:a}}catch(e){throw R.rmSync(a,{recursive:!0,force:!0}),e}}function og(e,t){return new Promise((r,i)=>{let n=R.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 oI(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 ov=new Set(["agent_device.command","agent-device.command"]),oA={"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"},oy=new Set([...ov,...Object.keys(oA)]);function oS(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function oN(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function ob(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function o_(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 oD(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function oE(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=b(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:oS(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:oS(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=f(r.tenantId);if(!e){let e=b(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:oS(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function ok(){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 oO(e){let t=await ok(),{handleRequest:r}=e;return i.createServer((e,i)=>{if("GET"===e.method&&"/health"===e.url){i.statusCode=200,i.setHeader("content-type","application/json"),i.end(JSON.stringify({ok:!0}));return}if("POST"===e.method&&"/upload"===e.url)return void oL(e,i,t);if("POST"!==e.method||"/rpc"!==e.url){i.statusCode=404,i.end("Not found");return}let n="";e.setEncoding("utf8"),e.on("data",t=>{(n+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{i.headersSent||oN(i,oS(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a,o;try{a=JSON.parse(n)}catch{oN(i,oS(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void oN(i,oS(a.id??null,-32600,"Invalid Request"),400);if(!oy.has(a.method))return void oN(i,oS(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void oN(i,oS(a.id??null,-32602,"Invalid params"),400);try{var s;let n=a.params,l=function(e,t,r){if(ov.has(e))return{token:o_(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=oA[e];if(i){let e;return{token:o_(t,r),session:oD(t,"session")??"default",command:i,positionals:[],meta:{tenantId:oD(t,"tenantId")??oD(t,"tenant"),runId:oD(t,"runId"),leaseId:oD(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:oD(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(s=a.method,ov.has(s)&&("string"!=typeof l.command||0===l.command.length))return void oN(i,oS(a.id??null,-32602,"Invalid params: command is required"),400);o=t6(l.meta?.requestId,a.id),l.meta={...l.meta,requestId:o},t9(o),e.on("close",()=>{i.writableFinished||t7(o)});let d=await oE(t,{headers:e.headers,rpcRequest:a,daemonRequest:l});if(!d.ok)return void oN(i,d.response,d.statusCode);d.tenantId&&(l.meta={...l.meta,tenantId:d.tenantId,sessionIsolation:l.meta?.sessionIsolation??l.flags?.sessionIsolation??"tenant"});let u=await r(l);if(u.ok)return void oN(i,{jsonrpc:"2.0",id:a.id??null,result:u});oN(i,oS(a.id??null,-32e3,u.error.message,u.error),ob(u.error.code))}catch(t){let e=b(t);oN(i,oS(a.id??null,-32e3,e.message,e),ob(e.code))}finally{re(o)}})})}async function oL(e,t,r){try{var i;let n,a,o=o_({},e.headers),s=await oE(r,{headers:e.headers,rpcRequest:{jsonrpc:"2.0",id:null,method:"agent_device.command"},daemonRequest:{token:o,session:"default",command:"upload",positionals:[]}});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=await ow(e),d=(i={artifactPath:l.artifactPath,tempDir:l.tempDir,tenantId:s.tenantId},n=u.randomUUID(),a=setTimeout(()=>{nn(n)},3e5),ni.set(n,{artifactPath:i.artifactPath,tempDir:i.tempDir,tenantId:i.tenantId,timer:a}),n);t.statusCode=200,t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!0,uploadId:d}))}catch(r){let e=b(r);t.statusCode=ob(e.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:e.message,code:e.code}))}}function oM(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function ox(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function oC(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class oT{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=oC(e.backend),r=f(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=oM(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),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:u.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=ox(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=ox(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=oC(e.backend),r=f(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=oM(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=ox(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=f(t),n=oM(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"})}}let{baseDir:oR,infoPath:oP,lockPath:o$,logPath:oF,sessionsDir:oV}=U(process.env.AGENT_DEVICE_STATE_DIR),oG=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var oU=oV;if(R.existsSync(oU))for(let e of R.readdirSync(oU,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(oU,e.name,"app-log.pid");if(R.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}}(R.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{nq(t)}}let oB=new nt(oV),oj=new oT({maxActiveSimulatorLeases:o2(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),oq=D(),oW=u.randomBytes(24).toString("hex"),oH=new Set(["session_list","devices","ensure-simulator"]),oJ=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]),oz=T(process.pid)??void 0,oK=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function oX(e,t,r){let i=k().requestId;return{...nr(oF,e,t,r,i),requestId:i}}async function oY(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:oF},async()=>{if(r.token!==oW)return{ok:!1,error:b(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=_(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=f(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}}}(r);L({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=om(e);oJ.has(t)||e.meta?.sessionIsolation!=="tenant"||oj.assertLeaseAdmission({tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId,backend:i.leaseBackend});let n=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,oB),a=oB.get(n);a&&!oH.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=r_(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=ed(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.`)}}(a,e.flags);let o=await oh({req:e,leaseRegistry:oj});if(o)return oZ(o);let s=await aq({req:e,sessionName:n,logPath:oF,sessionStore:oB,invoke:oY});if(s)return oZ(s);let l=await a1({req:e,sessionName:n,logPath:oF,sessionStore:oB});if(l)return oZ(l);let d=await on({req:e,sessionName:n,sessionStore:oB,logPath:oF});if(d)return oZ(d);let u=await oe({req:e,sessionName:n,logPath:oF,sessionStore:oB,invoke:oY});if(u)return oZ(u);let c=await ol({req:e,sessionName:n,sessionStore:oB,contextFromFlags:oX});if(c)return oZ(c);let p=oB.get(n);if(!p)return oZ({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!i1(t,p.device))return oZ({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await iQ(p.device,t,e.positionals??[],e.flags?.out,{...oX(e.flags,p.appBundleId,p.trace?.outPath)});return oB.recordAction(p,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),oZ({ok:!0,data:m??{}})}catch(r){L({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=k(),t=$({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function oZ(e){let t=k();if(!e.ok){L({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:b(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return L({level:"info",phase:"request_success"}),$(),e}function oQ(){R.existsSync(oP)&&R.unlinkSync(oP)}function o0(){if(!R.existsSync(o$))return null;try{let e=JSON.parse(R.readFileSync(o$,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function o1(){let e=o0();if(!e||e.pid===process.pid)try{R.existsSync(o$)&&R.unlinkSync(o$)}catch{}}function o2(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}(async function e(){let e,t;if(!function(){R.existsSync(oR)||R.mkdirSync(oR,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:oq,startedAt:Date.now(),processStartTime:oz},null,2),t=()=>{try{return R.writeFileSync(o$,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=o0();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(o$)}catch{}return t()}()){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"===oG||"dual"===oG){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))t7(e);L({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await rW(),!(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=t6(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),t9(o),rt(o))throw rr();n=await oY(e)}catch(e){n={ok:!1,error:b(e)}}finally{r-=1,o&&(i.delete(o),re(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
33
|
+
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!i1("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await p.stop(e.appLog);let i=n4(t),a=n.resolveAppLogPidPath(r);try{let o=await p.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=b(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:n4(t)}}if("start"===i){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(!i1("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await p.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await p.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===_){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!ay.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:aS}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!aN.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:ab}};let l=function(e,t){let r=ar(t?.maxEntries,25,1,200),i=t?.include??"summary",n=ar(t?.maxPayloadChars,2048,64,16384),a=ar(t?.maxScanLines,4e3,100,2e4);if(!R.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=R.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=n9(n,["method","httpMethod"]),o=n9(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=n8.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=n5.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of n6){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:at(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 ae(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=at(t,i))}if("body"===r||"all"===r){let t=n7(e,n,["requestBody","body","payload","request"]),r=n7(e,n,["responseBody","response"]);t&&(f.requestBody=at(t,i)),r&&(f.responseBody=at(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}}}(n.resolveAppLogPath(r),{maxEntries:o,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"===_)return await aW(t,r,a);if("close"===_){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await p.stop(e.appLog),t.positionals&&t.positionals.length>0&&("ios"===e.device.platform&&await S(e.device.id),await v(e.device,"close",t.positionals,t.flags?.out,{...nr(i,t.flags,e.appBundleId,e.trace?.outPath)}),await N(e.device,ag)),"ios"===e.device.platform&&await S(e.device.id),n.recordAction(e,{command:_,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),t.flags?.shutdown&&aE(e.device)){let t;try{t=await (g??t1)(e.device)}catch(r){let e=b(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:r,shutdown:t}}}return{ok:!0,data:{session:r}}}return null}async function aW(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??M;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=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await aH(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function aH(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 ac)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 aJ(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>i9(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 az(e,t){let r={...t??{}},i=e??{};for(let e of ap)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function aK(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(i6(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=i6(t.command)||"fill"===t.command,l=i6(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await aX(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),i6(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}=nL(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=ai(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 i3(t).filter(e=>e.trim().length>0)}(t)){let r=n_(e);if(!r)continue;let i=nD(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=nC(i.node,o.device.platform,{action:i6(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(i6(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=i2(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}=nL(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}=ai(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=n_(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(nI(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=nA(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(nI(e.type??"")))});if(0===s.length||1!==i3(s.map(e=>nA(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=nC(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function aX(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...nr(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:nu(t.flags?.snapshotRaw?s:ng(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function aY(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function aZ(e,t){let r=N(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 aQ(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:aZ(e,0)})):A(e).map(e=>({text:e.text,comparable:aZ(e.node,e.depth)}))}function a0(e,t){return e.get(t)??0}async function a1(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??iQ,o=e.runnerCommand??rY,s=t.command;if("snapshot"===s){let{session:e,device:o}=await a4(n,r,t.flags);if(!i1("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=a3(t.flags?.snapshotScope,e);return s.ok?await a8(e,o,async()=>{let l=e?.appBundleId,d=await a2({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 a5(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 a4(n,r,t.flags);if(!i1("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=a3(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await a8(e,o,async()=>{let d=e?.appBundleId,u=(await a2({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return aQ(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 a5(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&&a0(a,n-1)<a0(a,n+1)?a0(a,n+1):a0(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&&a0(n,l-1)<a0(n,l+1)?l+1:l-1,u=a0(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[]}(aQ(e,r),aQ(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 a5(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 a4(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=aY(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=aY(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=aY(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=aY(e[e.length-1]),i=nO(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=n_(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)),a5(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):i1("wait",o)?await a8(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,{...nr(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=nu(t.flags?.snapshotRaw?u:ng(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=nE(c,s.selector,{platform:o.platform});if(p)return a5(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=nc(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=np(e.snapshot.nodes,t),i=r?nh(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 rY(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 a5(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&nm(nu((await e6(o,{scope:l})).nodes??[]),l))return a5(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 a4(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return i1("alert",a)?await a8(e,a,async()=>{if("wait"===s){let r=aY(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 a5(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 a5(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 a5(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:c}};let{session:s,device:l}=await a4(n,r,t.flags);return i1("settings",l)?await a8(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await iQ(l,"settings",d,t.flags?.out,{...nr(i,t.flags,r,s?.trace?.outPath)});return a5(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 a2(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...nr(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:nu(n.flags?.snapshotRaw?l:ng(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function a3(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=nc(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=np(t.snapshot.nodes,r),n=i?nh(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 a4(e,t,r){let i=e.get(t),n=i?.device??await iZ(r??{});return i||await no(n),{session:i,device:n}}async function a8(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rq(t.id)}}function a5(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function a6(e,t,r,i={}){let n=a7(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 a9(e.label,r);case"value":return a9(e.value,r);case"id":return a9(e.identifier,r);default:return Math.max(a9(e.label,r),a9(e.value,r),a9(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 a9(e,t){let r=a7(e??"");return r?r===t?2:+!!r.includes(t):0}function a7(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function oe(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??iQ,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:aY(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 iZ(t.flags??{});m||await no(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,S=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...nr(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=nu(t.flags?.snapshotRaw?s:ng(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 S();if(a6(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 S(),b=a6(N,d,u,{requireRect:v});if(v&&b.matches.length>1){let e=b.matches.slice(0,8).map(e=>{let t=nA(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${b.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:b.matches.length,candidates:e}}}}let _=b.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=nA(_);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?nf(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?nf(_.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,{...nr(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?nf(_.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,{...nr(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...nr(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 ot(e){return e instanceof Error?e.message:String(e)}function or(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function oi(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function on(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rY},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 iZ(t.flags??{});d||await no(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(!i1("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?or(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=nt.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=oi(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},h)};try{await n()}catch(e){if(!ot(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ot(e)}`}};{var l,u;L({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ot(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},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ot(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",tY(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,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,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: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=or(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},oi(t,a,p))}catch(e){L({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ot(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of rC)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}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}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=nt.expandHome(e);return R.mkdirSync(n.dirname(r),{recursive:!0}),R.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=nt.expandHome(t.positionals[1]);R.mkdirSync(n.dirname(e),{recursive:!0}),R.existsSync(o)?R.renameSync(o,e):R.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 oa(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function oo(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 os(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function ol(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??iQ,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(!i1("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=oc("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=op({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=of(p.rect);if(!m){let r=await od(e,t.flags,i,n,{interactiveOnly:!0},a),o=np(r.nodes,c),l=s.length>0?nm(r.nodes,s):null,d=of(l?.rect),u=of(o?.rect)?o:d?l:o??l,h=of(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=nh(p,f),w=nC(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=nb(u),p=await od(e,t.flags,i,n,{interactiveOnly:!0},a),f=await O("selector_resolve",()=>nD(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:nk(c,f?.diagnostics??[],{unique:!0})}};let m=of(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=nC(f.node,e.device.platform,{action:l}),v=nh(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&&!i1("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=oc("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=op({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&&!nv(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=nh(c,p),w=nC(c,e.device.platform,{action:"fill"}),{x:g,y:I}=nf(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=nO(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=nb(s.selectorExpression),d=await od(e,t.flags,i,n,{interactiveOnly:!0},a),u=await O("selector_resolve",()=>nD(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:nk(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!nv(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=nf(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=nC(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:nh(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(!i1("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=oc("get",t.flags);if(r)return r;let n=op({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=nC(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=nA(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=nb(d),c=await od(s,t.flags,i,n,{interactiveOnly:!1},a),p=await O("selector_resolve",()=>nD(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:nk(u,[],{unique:!0})}};let f=p.node,m=nC(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=nA(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(!i1("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=nL(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=nb(l.selectorExpression),c=await od(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=nE(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:nk(u,[],{unique:!1})}}}let p=await O("selector_resolve",()=>nD(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:nk(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=nA(r),o=!1;switch(t){case"visible":o=nM(r);break;case"hidden":o=!nM(r);break;case"editable":o=nx(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:nM(r),editable:nx(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(!i1("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=oc("scrollintoview",t.flags);if(l)return l;let d=op({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=nf(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=oo(n.map(e=>e.rect).filter(e=>oa(e,r.x,r.y)));if(a)return a;let o=oo(n.map(e=>e.rect));if(o)return o;let s=oo(i.map(e=>e.rect).filter(e=>oa(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:os(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:os(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=nh(c,p),w=nC(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 od(e,t,r,i,n,a=iQ){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:nu(t?.snapshotRaw?s:ng(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let ou=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function oc(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of ou)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 op(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=nc(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=np(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=nm(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 of(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=nf(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function om(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 oh(e){let{req:t,leaseRegistry:r}=e,i=om(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}}async function ow(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=R.mkdtempSync(n.join(F.tmpdir(),"agent-device-upload-"));try{if("file"===t){let t=n.join(a,i);return await og(e,t),{artifactPath:t,tempDir:a}}let r=n.join(a,"artifact.tar");await og(e,r),await oI(r,i),await p("tar",["xf",r,"-C",a]),R.rmSync(r,{force:!0});let o=n.join(a,i);if(!R.existsSync(o))throw new I("INVALID_ARGS",`Expected extracted bundle "${i}" not found in archive`);return{artifactPath:o,tempDir:a}}catch(e){throw R.rmSync(a,{recursive:!0,force:!0}),e}}function og(e,t){return new Promise((r,i)=>{let n=R.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 oI(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 ov=new Set(["agent_device.command","agent-device.command"]),oA={"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"},oy=new Set([...ov,...Object.keys(oA)]);function oS(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function oN(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function ob(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function o_(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 oD(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function oE(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=b(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:oS(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:oS(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=f(r.tenantId);if(!e){let e=b(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:oS(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function ok(){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 oO(e){let t=await ok(),{handleRequest:r}=e;return i.createServer((e,i)=>{if("GET"===e.method&&"/health"===e.url){i.statusCode=200,i.setHeader("content-type","application/json"),i.end(JSON.stringify({ok:!0}));return}if("POST"===e.method&&"/upload"===e.url)return void oL(e,i,t);if("POST"!==e.method||"/rpc"!==e.url){i.statusCode=404,i.end("Not found");return}let n="";e.setEncoding("utf8"),e.on("data",t=>{(n+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{i.headersSent||oN(i,oS(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a,o;try{a=JSON.parse(n)}catch{oN(i,oS(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void oN(i,oS(a.id??null,-32600,"Invalid Request"),400);if(!oy.has(a.method))return void oN(i,oS(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void oN(i,oS(a.id??null,-32602,"Invalid params"),400);try{var s;let n=a.params,l=function(e,t,r){if(ov.has(e))return{token:o_(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=oA[e];if(i){let e;return{token:o_(t,r),session:oD(t,"session")??"default",command:i,positionals:[],meta:{tenantId:oD(t,"tenantId")??oD(t,"tenant"),runId:oD(t,"runId"),leaseId:oD(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:oD(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(s=a.method,ov.has(s)&&("string"!=typeof l.command||0===l.command.length))return void oN(i,oS(a.id??null,-32602,"Invalid params: command is required"),400);o=t6(l.meta?.requestId,a.id),l.meta={...l.meta,requestId:o},t9(o);let d=()=>{i.writableFinished||t7(o)};e.on("aborted",d),i.on("close",d);let u=await oE(t,{headers:e.headers,rpcRequest:a,daemonRequest:l});if(!u.ok)return void oN(i,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 oN(i,{jsonrpc:"2.0",id:a.id??null,result:c});oN(i,oS(a.id??null,-32e3,c.error.message,c.error),ob(c.error.code))}catch(t){let e=b(t);oN(i,oS(a.id??null,-32e3,e.message,e),ob(e.code))}finally{re(o)}})})}async function oL(e,t,r){try{var i;let n,a,o=o_({},e.headers),s=await oE(r,{headers:e.headers,rpcRequest:{jsonrpc:"2.0",id:null,method:"agent_device.command"},daemonRequest:{token:o,session:"default",command:"upload",positionals:[]}});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=await ow(e),d=(i={artifactPath:l.artifactPath,tempDir:l.tempDir,tenantId:s.tenantId},n=u.randomUUID(),a=setTimeout(()=>{nn(n)},3e5),ni.set(n,{artifactPath:i.artifactPath,tempDir:i.tempDir,tenantId:i.tenantId,timer:a}),n);t.statusCode=200,t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!0,uploadId:d}))}catch(r){let e=b(r);t.statusCode=ob(e.code),t.setHeader("content-type","application/json"),t.end(JSON.stringify({ok:!1,error:e.message,code:e.code}))}}function oM(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function ox(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function oC(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class oT{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=oC(e.backend),r=f(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=oM(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),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:u.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=ox(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=ox(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=oC(e.backend),r=f(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=oM(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=ox(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=f(t),n=oM(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"})}}let{baseDir:oR,infoPath:oP,lockPath:o$,logPath:oF,sessionsDir:oV}=U(process.env.AGENT_DEVICE_STATE_DIR),oG=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var oU=oV;if(R.existsSync(oU))for(let e of R.readdirSync(oU,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(oU,e.name,"app-log.pid");if(R.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}}(R.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{nq(t)}}let oB=new nt(oV),oj=new oT({maxActiveSimulatorLeases:o2(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:o2(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),oq=D(),oW=u.randomBytes(24).toString("hex"),oH=new Set(["session_list","devices","ensure-simulator"]),oJ=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]),oz=T(process.pid)??void 0,oK=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function oX(e,t,r){let i=k().requestId;return{...nr(oF,e,t,r,i),requestId:i}}async function oY(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:oF},async()=>{if(r.token!==oW)return{ok:!1,error:b(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=_(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=f(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}}}(r);L({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=om(e);oJ.has(t)||e.meta?.sessionIsolation!=="tenant"||oj.assertLeaseAdmission({tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId,backend:i.leaseBackend});let n=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,oB),a=oB.get(n);a&&!oH.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=r_(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=ed(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.`)}}(a,e.flags);let o=await oh({req:e,leaseRegistry:oj});if(o)return oZ(o);let s=await aq({req:e,sessionName:n,logPath:oF,sessionStore:oB,invoke:oY});if(s)return oZ(s);let l=await a1({req:e,sessionName:n,logPath:oF,sessionStore:oB});if(l)return oZ(l);let d=await on({req:e,sessionName:n,sessionStore:oB,logPath:oF});if(d)return oZ(d);let u=await oe({req:e,sessionName:n,logPath:oF,sessionStore:oB,invoke:oY});if(u)return oZ(u);let c=await ol({req:e,sessionName:n,sessionStore:oB,contextFromFlags:oX});if(c)return oZ(c);let p=oB.get(n);if(!p)return oZ({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!i1(t,p.device))return oZ({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await iQ(p.device,t,e.positionals??[],e.flags?.out,{...oX(e.flags,p.appBundleId,p.trace?.outPath)});return oB.recordAction(p,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),oZ({ok:!0,data:m??{}})}catch(r){L({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=k(),t=$({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function oZ(e){let t=k();if(!e.ok){L({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:b(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return L({level:"info",phase:"request_success"}),$(),e}function oQ(){R.existsSync(oP)&&R.unlinkSync(oP)}function o0(){if(!R.existsSync(o$))return null;try{let e=JSON.parse(R.readFileSync(o$,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function o1(){let e=o0();if(!e||e.pid===process.pid)try{R.existsSync(o$)&&R.unlinkSync(o$)}catch{}}function o2(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}(async function e(){let e,t;if(!function(){R.existsSync(oR)||R.mkdirSync(oR,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:oq,startedAt:Date.now(),processStartTime:oz},null,2),t=()=>{try{return R.writeFileSync(o$,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=o0();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(o$)}catch{}return t()}()){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"===oG||"dual"===oG){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))t7(e);L({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await rW(),!(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=t6(e.meta?.requestId,"socket"),e.meta={...e.meta,requestId:o},i.add(o),t9(o),rt(o))throw rr();n=await oY(e)}catch(e){n={ok:!1,error:b(e)}}finally{r-=1,o&&(i.delete(o),re(o))}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
34
34
|
`),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"===oG||"dual"===oG){let e=await oO({handleRequest:oY});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},R.existsSync(oR)||R.mkdirSync(oR,{recursive:!0}),R.writeFileSync(oF,""),n=i.httpPort&&i.socketPort?"dual":i.httpPort?"http":"socket",R.writeFileSync(oP,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:oW,pid:process.pid,version:oq,codeSignature:oK,processStartTime:oz,stateDir:oR},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
35
35
|
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
36
36
|
`)}catch(t){let e=w(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|