agent-device 0.7.17 → 0.7.18
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
|
@@ -2,7 +2,7 @@ let e;import{isCancel as t,select as r}from"@clack/prompts";import{formatSnapsho
|
|
|
2
2
|
`)}let Q=new Set,ee=new Map,et="request_canceled",er="request canceled";function ei(e,t){if("string"==typeof e&&e.length>0)return e;let r=("string"==typeof t?t:"number"==typeof t&&Number.isFinite(t)?String(t):"generated").trim().replace(/[^a-zA-Z0-9_-]/g,"_").slice(0,32)||"generated",i=Math.random().toString(36).slice(2,10);return`req:${r}:${process.pid}:${Date.now()}:${i}`}function en(e){if(!e)return;let t=new AbortController;ee.set(e,t),Q.has(e)&&t.abort()}function ea(e){e&&(Q.add(e),ee.get(e)?.abort())}function eo(e){e&&(Q.delete(e),ee.delete(e))}function es(e){return!!e&&Q.has(e)}function el(){return new I("COMMAND_FAILED",er,{reason:et})}function ed(e){return e instanceof I&&"COMMAND_FAILED"===e.code&&(e.details?.reason===et||e.message===er)}function eu(e){let t=e.error?w(e.error):null,r=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===r?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let n=t?.details??{},a="string"==typeof n.message?n.message:void 0,o="string"==typeof n.stdout?n.stdout:void 0,s="string"==typeof n.stderr?n.stderr:void 0,l=n.boot&&"object"==typeof n.boot?n.boot:null,d=n.bootstatus&&"object"==typeof n.bootstatus?n.bootstatus:null,u=[e.message,t?.message,e.stdout,e.stderr,a,o,s,"string"==typeof l?.stdout?l.stdout:void 0,"string"==typeof l?.stderr?l.stderr:void 0,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===r&&(u.includes("runner did not accept connection")||"connect"===i&&(u.includes("timed out")||u.includes("timeout")||u.includes("econnrefused")||u.includes("connection refused")||u.includes("fetch failed")||u.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===r&&"boot"===i&&(u.includes("timed out")||u.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===r&&"boot"===i&&(u.includes("timed out")||u.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":u.includes("resource temporarily unavailable")||u.includes("killed: 9")||u.includes("cannot allocate memory")||u.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===r&&(u.includes("device not found")||u.includes("no devices")||u.includes("device offline")||u.includes("offline")||u.includes("unauthorized")||u.includes("not authorized")||u.includes("unable to locate device")||u.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||u.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function ec(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI consider increasing AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS.";case"IOS_RUNNER_CONNECT_TIMEOUT":return"Retry runner startup, inspect xcodebuild logs, and verify simulator responsiveness before command execution.";case"ANDROID_BOOT_TIMEOUT":return"Retry emulator startup and verify sys.boot_completed reaches 1; consider increasing startup budget in CI.";case"ADB_TRANSPORT_UNAVAILABLE":return"Check adb server/device transport (adb devices -l), restart adb, and ensure the target device is online and authorized.";case"CI_RESOURCE_STARVATION_SUSPECTED":return"CI machine may be resource constrained; reduce parallel jobs or use a larger runner.";case"IOS_TOOL_MISSING":return"Xcode command-line tools are missing or not in PATH; run xcode-select --install and verify xcrun works.";case"BOOT_COMMAND_FAILED":return"Inspect command stderr/stdout for the failing boot phase and retry after environment validation.";default:return"Retry once and inspect verbose logs for the failing phase."}}function ep(e){return!(e instanceof I)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}function ef(e){let{port:t,endpoints:r,logPath:i,lastError:n}=e,a="Runner did not accept connection";return new I("COMMAND_FAILED",a,{port:t,endpoints:r,logPath:i,lastError:n?String(n):void 0,reason:eu({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:ec("IOS_RUNNER_CONNECT_TIMEOUT")})}async function em(e){var t,r;let i,{session:n,port:a,logPath:o}=e,s=await n.testPromise,l="Runner did not accept connection (xcodebuild exited early)",d=eu({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new I("COMMAND_FAILED",l,{port:a,logPath:o,xcodebuild:{exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr},reason:d,hint:(t=s.stdout,r=s.stderr,(i=`${l}
|
|
3
3
|
${t}
|
|
4
4
|
${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":ec("IOS_RUNNER_CONNECT_TIMEOUT"))})}function eh(e){if(es(e))throw el()}function ew(e,t,r){if(!e)return t;let i=Number(e);return Number.isFinite(i)?Math.max(r,Math.floor(i)):t}let eg=["AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET","IOS_SIMULATOR_DEVICE_SET"],eI=["AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST","ANDROID_DEVICE_ALLOWLIST"];function ev(e){return e?.trim()||void 0}function eA(e,t){for(let r of e){let e=ev(t[r]);if(e)return e}}function ey(e,t=process.env){return ev(e)??eA(eg,t)}function eb(e){return new Set(e.split(/[\s,]+/).map(e=>e.trim()).filter(Boolean))}function eN(e,t=process.env){let r=ev(e)??eA(eI,t);if(r)return eb(r)}function eS(e,t={}){let r=ey(t.simulatorSetPath);return r?["simctl","--set",r,...e]:["simctl",...e]}function e_(e,t){return"ios"!==e.platform||"simulator"!==e.kind?["simctl",...t]:eS(t,{simulatorSetPath:e.simulatorSetPath})}let eD=ew(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),eE=ew(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),ek=ew(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),eO=ew(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),eL=ew(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),eM=ew(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),ex=ew(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),eC=ew(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5);async function eR(e,t,r,i,n=eD,a,o){let s=K.fromTimeoutMs(n),l=await eT(e,t,s.remainingMs()),d=null,u=Math.max(1,Math.ceil(n/ek));try{return await X(async({deadline:s})=>{if(s?.isExpired())throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await em({session:a,port:t,logPath:i});for(let i of("device"===e.kind&&(l=await eT(e,t,s?.remainingMs())),l))try{let e=s?.remainingMs()??n;if(e<=0)throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await eP(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)},Math.min(eM,e),o)}catch(e){if(o?.aborted||ed(e))throw el();d=e}throw new I("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:l,lastError:d?String(d):void 0})},{maxAttempts:u,baseDelayMs:eO,maxDelayMs:eL,jitter:.2,shouldRetry:ep},{deadline:s,phase:"ios_runner_connect",signal:o})}catch(e){if(o?.aborted||ed(e))throw el();d||(d=e)}if(o?.aborted)throw el();if("simulator"===e.kind){let n=s.remainingMs();if(n<=0)throw ef({port:t,endpoints:l,logPath:i,lastError:d});let a=await eF(e,t,r,n);return new Response(a.body,{status:a.status})}throw ef({port:t,endpoints:l,logPath:i,lastError:d})}async function eT(e,t,r){let i=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return i;let n=await e$(e.id,r);return n&&i.unshift(`http://[${n}]:${t}/command`),i}async function eP(e,t,r,i){let n,a=new AbortController,o=setTimeout(()=>a.abort(),r);i&&(i.aborted?(clearTimeout(o),a.abort()):(n=()=>a.abort(),i.addEventListener("abort",n,{once:!0})));try{return await fetch(e,{...t,signal:a.signal})}finally{clearTimeout(o),n&&i&&i.removeEventListener("abort",n)}}async function e$(e,t){if("number"==typeof t&&t<=0)return null;let r="number"==typeof t?Math.max(1,Math.min(ex,t)):ex,i=n.join(V.tmpdir(),`agent-device-devicectl-info-${process.pid}-${Date.now()}.json`);try{let t=Math.max(1,Math.ceil(r/1e3)),n=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",i,"--timeout",String(t)],{allowFailure:!0,timeoutMs:r});if(0!==n.exitCode||!$.existsSync(i))return null;let a=JSON.parse($.readFileSync(i,"utf8"));if(a.info?.outcome&&"success"!==a.info.outcome)return null;let o=(a.result?.connectionProperties?.tunnelIPAddress??a.result?.device?.connectionProperties?.tunnelIPAddress)?.trim();return o&&o.length>0?o:null}catch{return null}finally{eG(i)}}async function eF(e,t,r,i){let n=JSON.stringify(r),a=e_(e,["spawn",e.id,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`]),o=await p("xcrun",a,{allowFailure:!0,timeoutMs:i}),s=o.stdout;if(0!==o.exitCode){let e=eu({message:"Runner did not accept connection (simctl spawn)",stdout:o.stdout,stderr:o.stderr,context:{platform:"ios",phase:"connect"}});throw new I("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode,reason:e,hint:ec(e)})}return{status:200,body:s}}async function eV(){return await new Promise((e,t)=>{let r=U.createServer();r.listen(0,"127.0.0.1",()=>{let i=r.address();r.close(),"object"==typeof i&&i?.port?e(i.port):t(new I("COMMAND_FAILED","Failed to allocate port"))}),r.on("error",t)})}function eU(e,t,r,i){t&&$.appendFileSync(t,e),r&&$.appendFileSync(r,e),i&&process.stderr.write(e)}function eG(e){try{$.existsSync(e)&&$.unlinkSync(e)}catch{}}async function eB(e,t,r){let i=(e.get(t)??Promise.resolve()).catch(()=>{}).then(r);return e.set(t,i),i.finally(()=>{e.get(t)===i&&e.delete(t)})}function ej(e){return"apple"===e?"ios":e}async function eq(e,i,n={}){let a=e,o=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(i.platform&&(a=a.filter(e=>e.platform===i.platform)),i.target&&(a=a.filter(e=>(e.target??"mobile")===i.target)),i.udid){let e=a.find(e=>e.id===i.udid&&"ios"===e.platform);if(!e)throw new I("DEVICE_NOT_FOUND",`No iOS device with UDID ${i.udid}`);return e}if(i.serial){let e=a.find(e=>e.id===i.serial&&"android"===e.platform);if(!e)throw new I("DEVICE_NOT_FOUND",`No Android device with serial ${i.serial}`);return e}if(i.deviceName){let e=o(i.deviceName),t=a.find(t=>o(t.name)===e);if(!t)throw new I("DEVICE_NOT_FOUND",`No device named ${i.deviceName}`);return t}if(1===a.length)return a[0];if(0===a.length){let e=n.simulatorSetPath;if(e&&(!i.platform||"ios"===i.platform))throw new I("DEVICE_NOT_FOUND","No devices found in the scoped simulator set",{simulatorSetPath:e,hint:`The simulator set at "${e}" appears to be empty. Create a simulator first:
|
|
5
|
-
xcrun simctl --set "${e}" create "iPhone 16" com.apple.CoreSimulator.SimDeviceType.iPhone-16 com.apple.CoreSimulator.SimRuntime.iOS-18-0`,selector:i});throw new I("DEVICE_NOT_FOUND","No devices found",{selector:i})}let s=a.filter(e=>e.booted);if(1===
|
|
5
|
+
xcrun simctl --set "${e}" create "iPhone 16" com.apple.CoreSimulator.SimDeviceType.iPhone-16 com.apple.CoreSimulator.SimRuntime.iOS-18-0`,selector:i});throw new I("DEVICE_NOT_FOUND","No devices found",{selector:i})}let s=a.filter(e=>"device"!==e.kind);s.length>0&&(a=s);let l=a.filter(e=>e.booted);if(1===l.length)return l[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await r({message:"Multiple devices available. Choose a device to continue:",options:(l.length>0?l:a).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(t(e))throw new I("INVALID_ARGS","Device selection cancelled");if(e){let t=a.find(t=>t.id===e);if(t)return t}}return l[0]??a[0]}let eH=n.join(V.homedir(),".agent-device","ios-runner"),eW=new Map,eJ=new Set;function ez(e){return e?.trim()??""}function eK(e=process.env){return ez(e.AGENT_DEVICE_IOS_BUNDLE_ID)||ez(e.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID)||"com.callstack.agentdevice.runner"}function eX(e=process.env){let t=ez(e.AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID);return t||`${eK(e)}.uitests`}let eY=function(e=process.env){let t=eK(e),r=eX(e);return Array.from(new Set([ez(e.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID),`${r}.xctrunner`,t].filter(e=>e.length>0)))}(process.env);async function eZ(e,t){var r;let i,a=(r=e.kind,(i=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?n.resolve(i):"simulator"===r?n.join(eH,"derived"):n.join(eH,"derived",r));return await eB(eW,a,async()=>{if(H(process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)){!function(e,t=process.env){if(t.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim()&&!function(e=process.env){return H(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new I("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(a);try{$.rmSync(a,{recursive:!0,force:!0})}catch{}}let r=eQ(a);if(r)return r;let i=function(){let e=n.dirname(b(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if($.existsSync(e))return t;t=n.dirname(t)}return e}(),o=n.join(i,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!$.existsSync(o))throw new I("COMMAND_FAILED","iOS runner project not found",{projectPath:o});let s=function(e=process.env){let t=eK(e),r=eX(e);return[`AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID=${t}`,`AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID=${r}`]}(process.env),l=function(e=process.env,t=!1){if(!t)return[];let r=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||"",i=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||"",n=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||"",a=["CODE_SIGN_STYLE=Automatic"];return r&&a.push(`DEVELOPMENT_TEAM=${r}`),i&&a.push(`CODE_SIGN_IDENTITY=${i}`),n&&a.push(`PROVISIONING_PROFILE_SPECIFIER=${n}`),a}(process.env,"device"===e.kind),d="device"===e.kind?["-allowProvisioningUpdates"]:[];try{var u;let r;await N("xcodebuild",["build-for-testing","-project",o,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",e2(e),"1","-destination",(u=e,r=e1(u),"simulator"===u.kind?`platform=${r} Simulator,id=${u.id}`:`generic/platform=${r}`),"-derivedDataPath",a,"COMPILER_INDEX_STORE_ENABLE=NO",...s,...d,...l],{detached:!0,onSpawn:e=>{eJ.add(e),e.on("close",()=>{eJ.delete(e)})},onStdoutChunk:e=>{eU(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{eU(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(a){let e,r,i=a instanceof I?a:new I("COMMAND_FAILED",String(a)),n=(e=i.details?JSON.stringify(i.details):"",(r=`${i.message}
|
|
6
6
|
${e}`.toLowerCase()).includes("failed registering bundle identifier")||r.includes("app identifier")&&r.includes("not available")?"Set AGENT_DEVICE_IOS_BUNDLE_ID to a unique reverse-DNS value (for example, com.yourname.agentdevice.runner), then retry.":r.includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new I("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:i.message,details:i.details,logPath:t.logPath,hint:n})}let c=eQ(a);if(!c)throw new I("COMMAND_FAILED","Failed to locate .xctestrun after build");return c})}function eQ(e){if(!$.existsSync(e))return null;let t=[],r=[e];for(;r.length>0;){let e=r.pop();for(let i of $.readdirSync(e,{withFileTypes:!0})){let a=n.join(e,i.name);if(i.isDirectory()){r.push(a);continue}if(i.isFile()&&i.name.endsWith(".xctestrun"))try{let e=$.statSync(a);t.push({path:a,mtimeMs:e.mtimeMs})}catch{}}}return 0===t.length?null:(t.sort((e,t)=>t.mtimeMs-e.mtimeMs),t[0]?.path??null)}async function e0(e,t,r){let i,a=n.dirname(e),o=r.replace(/[^a-zA-Z0-9._-]/g,"_"),s=n.join(a,`AgentDeviceRunner.env.${o}.json`),l=n.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),d=await p("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==d.exitCode||!d.stdout.trim())throw new I("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:d.stderr});try{i=JSON.parse(d.stdout)}catch(t){throw new I("COMMAND_FAILED","Failed to parse xctestrun JSON",{xctestrunPath:e,error:String(t)})}let u=e=>{e.EnvironmentVariables={...e.EnvironmentVariables??{},...t},e.UITestEnvironmentVariables={...e.UITestEnvironmentVariables??{},...t},e.UITargetAppEnvironmentVariables={...e.UITargetAppEnvironmentVariables??{},...t},e.TestingEnvironmentVariables={...e.TestingEnvironmentVariables??{},...t}},c=i.TestConfigurations;if(Array.isArray(c))for(let e of c){if(!e||"object"!=typeof e)continue;let t=e.TestTargets;if(Array.isArray(t))for(let e of t)e&&"object"==typeof e&&u(e)}for(let[e,t]of Object.entries(i))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),i[e]=t);$.writeFileSync(s,JSON.stringify(i,null,2));let f=await p("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==f.exitCode)throw new I("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:f.stderr});return{xctestrunPath:l,jsonPath:s}}function e1(e){if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"tv"===e.target?"tvOS":"iOS"}function e2(e){return"device"===e.kind?"-maximum-concurrent-test-device-destinations":"-maximum-concurrent-test-simulator-destinations"}let e3=new Map,e4=new Map;async function e8(e,t){return await eB(e4,e.id,async()=>{var r,i;let n,a=e3.get(e.id);if(a){if((r=a.child.pid)&&R(r))return a;await e6(e.id,a)}await ("simulator"!==(i=e).kind?Promise.resolve():tr(i));let o=await eZ(e,t),s=await eV(),{xctestrunPath:l,jsonPath:u}=await e0(o,{AGENT_DEVICE_RUNNER_PORT:String(s)},`session-${e.id}-${s}`),{child:c,wait:p}=d("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-collect-test-diagnostics","never",e2(e),"1","-destination-timeout",String(eC),"-xctestrun",l,"-destination",(n=e1(e),"simulator"===e.kind?`platform=${n} Simulator,id=${e.id}`:`platform=${n},id=${e.id}`)],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(s)},detached:!0});c.stdout?.on("data",e=>{eU(e,t.logPath,t.traceLogPath,t.verbose)}),c.stderr?.on("data",e=>{eU(e,t.logPath,t.traceLogPath,t.verbose)});let f={device:e,deviceId:e.id,port:s,xctestrunPath:l,jsonPath:u,testPromise:p,child:c,ready:!1};return e3.set(e.id,f),f})}async function e5(e){await eB(e4,e.deviceId,async()=>{await e6(e.deviceId,e)})}async function e6(e,t){let r=t??e3.get(e);if(r){try{await eR(r.device,r.port,{command:"shutdown"},void 0,15e3)}catch{await tt(r.child.pid,"SIGTERM")}try{await Promise.race([r.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await tt(r.child.pid,"SIGKILL"),eG(r.xctestrunPath),eG(r.jsonPath),e3.get(e)===r&&e3.delete(e)}}async function e9(e){await eB(e4,e,async()=>{await e6(e)})}async function e7(){let e=Array.from(e3.values()),t=Array.from(eJ);await Promise.allSettled(e.map(async e=>{await tt(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await tt(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await tt(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await tt(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await tt(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await tt(e.pid,"SIGKILL"),eJ.delete(e)}))}async function te(){await e7();let e=Array.from(e3.keys());await Promise.allSettled(e.map(async e=>{await e9(e)}));let t=Array.from(eJ);await Promise.allSettled(t.map(async e=>{try{await tt(e.pid,"SIGTERM"),await tt(e.pid,"SIGKILL")}finally{eJ.delete(e)}}))}async function tt(e,t){if(!e||e<=0)return;try{process.kill(-e,t)}catch{}try{process.kill(e,t)}catch{}let r="SIGINT"===t?"INT":"SIGTERM"===t?"TERM":"KILL";try{await p("pkill",[`-${r}`,"-P",String(e)],{allowFailure:!0})}catch{}}async function tr(e){await p("xcrun",e_(e,["bootstatus",e.id,"-b"]),{timeoutMs:eD})}async function ti(e,t,r,i,n,a){let o=await eR(e,t.port,r,i,n,t,a);return await tn(o,t,i)}async function tn(e,t,r){let i=await e.text(),n={};try{n=JSON.parse(i)}catch{throw new I("COMMAND_FAILED","Invalid runner response",{text:i})}if(!n.ok)throw new I("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:r});return t.ready=!0,n.data??{}}async function ta(e,t,r={}){var i;if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`);return(eh(r.requestId),"snapshot"===(i=t.command)||"screenshot"===i||"findText"===i||"alert"===i)?Y(()=>(eh(r.requestId),to(e,t,r)),{shouldRetry:e=>{eh(r.requestId);if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!(t.includes("xcodebuild exited early")||t.includes("device is busy")&&t.includes("connecting"))&&!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}}):to(e,t,r)}async function to(e,t,r={}){let i;eh(r.requestId);let n=function(e){if(e)return ee.get(e)?.signal}(r.requestId);try{let a=(i=await e8(e,r)).ready?eE:eD;return await ti(e,i,t,r.logPath,a,n)}catch(o){let a=o instanceof I?o:new I("COMMAND_FAILED",String(o));if("COMMAND_FAILED"===a.code&&"string"==typeof a.message&&a.message.includes("Runner did not accept connection")&&ep(a)&&i?.ready){eh(r.requestId),i?await e5(i):await e9(e.id),i=await e8(e,r);let a=await eR(i.device,i.port,t,r.logPath,eD,void 0,n);return await tn(a,i,r.logPath)}throw o}}function ts(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function tl(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let td=/^-?\d+(\.\d+)?$/,tu=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),tc=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function tp(e){return"click"===e||"press"===e}function tf(e){let t=e.trim();return t.startsWith("@")||td.test(t)?t:JSON.stringify(t)}function tm(e,t){let r=t.flags??{};if(tp(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function th(e,t){let r=[],i={},n=tp(e)?tu:"swipe"===e?tc:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(tp(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class tw{sessions=new Map;runtimeHints=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.runtimeHints.delete(e),this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}getRuntimeHints(e){return this.runtimeHints.get(e)}setRuntimeHints(e,t){this.runtimeHints.set(e,t)}clearRuntimeHints(e){return this.runtimeHints.delete(e)}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=tw.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}}(t.flags),result:t.result}),M({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=n.dirname(t);$.existsSync(r)||$.mkdirSync(r,{recursive:!0});let i=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(tp(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(tf(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(tf(i)),tm(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(tf(r)),tm(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(tf(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(tf(i)),n&&t.push(tf(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(tf(r)),t.push(tf(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(tf(r))}return t.join(" ")}}if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",tf(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(tf(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(tf(r));return tm(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
7
7
|
`}(e,this.buildOptimizedActions(e));$.writeFileSync(t,i)}catch{}}defaultTracePath(e){let t=tw.safeSessionName(e.name),r=new Date().toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${r}.trace.log`)}resolveAppLogPath(e){return n.join(this.sessionsDir,tw.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return n.join(this.sessionsDir,tw.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?n.join(V.homedir(),e.slice(2)):t&&!n.isAbsolute(e)?n.resolve(t,e):n.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return tw.expandHome(e.saveScriptPath);$.existsSync(this.sessionsDir)||$.mkdirSync(this.sessionsDir,{recursive:!0});let t=tw.safeSessionName(e.name),r=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${r}.ad`)}buildOptimizedActions(e){let t=[];for(let r of e.actions){if("snapshot"===r.command)continue;let i=Array.isArray(r.result?.selectorChain)&&r.result?.selectorChain.every(e=>"string"==typeof e)?r.result.selectorChain:[];if(i.length>0&&(tp(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(tp(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=ts(r);if(i.length>0){t.push({...r,positionals:[e,i]});continue}}if("get"===r.command){let i=r.positionals?.[0];if("text"===i||"attrs"===i){t.push({...r,positionals:[i,e]});continue}}}if(tp(r.command)||"fill"===r.command||"get"===r.command){let i=r.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push({ts:r.ts,command:"snapshot",positionals:[],flags:{platform:e.device.platform,snapshotInteractiveOnly:!0,snapshotCompact:!0,snapshotScope:i.trim()},result:{scope:i.trim()}})}t.push(r)}return t}}function tg(e,t){if(!e)return;let r=n.dirname(e);$.existsSync(r)||$.mkdirSync(r,{recursive:!0});let i={pid:t,startTime:T(t)??void 0,command:a(t)??void 0};$.writeFileSync(e,`${JSON.stringify(i)}
|
|
8
8
|
`)}function tI(e){if(e&&$.existsSync(e))try{$.unlinkSync(e)}catch{}}async function tv(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function tA(e){await new Promise(t=>setTimeout(t,e))}function ty(e,t){let r=t.includeTokens?.filter(e=>e.length>0)??[],i="",n=i=>{(!(r.length>0)||r.some(e=>i.includes(e)))&&e.write(function(e,t){if(0===t.length)return e;let r=e;for(let e of t)r=r.replace(e,"[REDACTED]");return r}(i,t.redactionPatterns))};return{onChunk:e=>{let t=`${i}${e}`.split("\n");for(let e of(i=t.pop()??"",t))n(`${e}
|