agent-device 0.16.2 → 0.16.5

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.
Files changed (32) hide show
  1. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.2.apk → agent-device-android-multitouch-helper-0.16.5.apk} +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.16.5.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.2.manifest.json → agent-device-android-multitouch-helper-0.16.5.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.5.apk +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.5.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.16.2.manifest.json → agent-device-android-snapshot-helper-0.16.5.manifest.json} +6 -6
  7. package/dist/src/1393.js +1 -0
  8. package/dist/src/1769.js +7 -7
  9. package/dist/src/221.js +6 -4
  10. package/dist/src/6277.js +2 -2
  11. package/dist/src/7519.js +1 -1
  12. package/dist/src/7599.js +3 -0
  13. package/dist/src/9542.js +1 -1
  14. package/dist/src/9639.js +1 -1
  15. package/dist/src/android-adb.js +1 -1
  16. package/dist/src/android-snapshot-helper.d.ts +10 -1
  17. package/dist/src/android-snapshot-helper.js +1 -1
  18. package/dist/src/cli.js +15 -13
  19. package/dist/src/index.d.ts +2 -0
  20. package/dist/src/internal/daemon.js +51 -51
  21. package/ios-runner/AgentDeviceRunner/AgentDeviceRunner/Assets.xcassets/AppIcon.appiconset/logo.jpg +0 -0
  22. package/ios-runner/AgentDeviceRunner/AgentDeviceRunner/Assets.xcassets/Logo.imageset/logo.jpg +0 -0
  23. package/ios-runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +0 -4
  24. package/package.json +1 -1
  25. package/server.json +2 -2
  26. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.16.2.apk.sha256 +0 -1
  27. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.2.apk +0 -0
  28. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.2.apk.sha256 +0 -1
  29. package/dist/src/3622.js +0 -3
  30. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -14
  31. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/AppIcon.appiconset/logo-tinted.jpg +0 -0
  32. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/Contents.json +0 -6
@@ -0,0 +1 @@
1
+ e92fcfc48e860b6237b4679165baea3e78cc58c2c5c8fd67af29c3d86e9b859d agent-device-android-multitouch-helper-0.16.5.apk
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "android-multitouch-helper",
3
- "version": "0.16.2",
4
- "assetName": "agent-device-android-multitouch-helper-0.16.2.apk",
5
- "sha256": "cead74caf53852ac79126f54f30a1769a5c938544c5871c3961a28effc7e1861",
3
+ "version": "0.16.5",
4
+ "assetName": "agent-device-android-multitouch-helper-0.16.5.apk",
5
+ "sha256": "e92fcfc48e860b6237b4679165baea3e78cc58c2c5c8fd67af29c3d86e9b859d",
6
6
  "packageName": "com.callstack.agentdevice.multitouchhelper",
7
- "versionCode": 16002,
7
+ "versionCode": 16005,
8
8
  "instrumentationRunner": "com.callstack.agentdevice.multitouchhelper/.MultiTouchInstrumentation",
9
9
  "statusProtocol": "android-multitouch-helper-v1"
10
10
  }
@@ -0,0 +1 @@
1
+ fc48a158031664b8bcf6cf301484433fc9ccd2a5494d4565571d7399bd63ab23 agent-device-android-snapshot-helper-0.16.5.apk
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "android-snapshot-helper",
3
- "version": "0.16.2",
4
- "releaseTag": "v0.16.2",
5
- "assetName": "agent-device-android-snapshot-helper-0.16.2.apk",
3
+ "version": "0.16.5",
4
+ "releaseTag": "v0.16.5",
5
+ "assetName": "agent-device-android-snapshot-helper-0.16.5.apk",
6
6
  "apkUrl": null,
7
- "sha256": "f353f255a4e15c64d2534bf78edc834ce9bc52a6a74ae6c46d95f43d644426a8",
8
- "checksumName": "agent-device-android-snapshot-helper-0.16.2.apk.sha256",
7
+ "sha256": "fc48a158031664b8bcf6cf301484433fc9ccd2a5494d4565571d7399bd63ab23",
8
+ "checksumName": "agent-device-android-snapshot-helper-0.16.5.apk.sha256",
9
9
  "packageName": "com.callstack.agentdevice.snapshothelper",
10
- "versionCode": 16002,
10
+ "versionCode": 16005,
11
11
  "instrumentationRunner": "com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",
12
12
  "minSdk": 23,
13
13
  "targetSdk": 36,
@@ -0,0 +1 @@
1
+ import{AppError as e}from"./9152.js";let r="user-installed";function t(e){return e??r}function o(r){if(void 0===r)throw new e("INVALID_ARGS","appsFilter must be resolved before executing the apps command");return r}export{r as DEFAULT_APPS_FILTER,o as assertResolvedAppsFilter,t as resolveAppsFilter};
package/dist/src/1769.js CHANGED
@@ -1,7 +1,7 @@
1
- import{promises as e}from"node:fs";import t from"node:os";import a from"node:path";import{asAppError as n,AppError as i}from"./9152.js";import{emitDiagnostic as r}from"./3622.js";import{runCmd as o,resolveFileOverridePath as s,whichCmd as l,runCmdDetached as d}from"./9818.js";import{ensureAndroidSdkPathConfigured as u,resolveAndroidArchivePackageName as c}from"./7651.js";import{sleep as p}from"./4829.js";import{createAndroidPortReverseManager as f,resolveAndroidAdbProvider as m,installAndroidAdbPackage as w,resolveAndroidAdbExecutor as h}from"./9639.js";import{materializeInstallablePath as A,isTrustedInstallSourceUrl as y}from"./989.js";let g=["mCurrentFocus=Window{","mFocusedApp=AppWindowToken{","mResumedActivity:","ResumedActivity:"],v=/\bApplication Not Responding:\s*([A-Za-z0-9_.]+)/i,b=/([^{}]*\bis(?:n't| not)\s+responding[^{}]*)/i,M=/\b([A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+)\b/;function _(e){let t=new Set;for(let a of e.split("\n")){let e=a.trim();if(!e)continue;let n=e.split(/\s+/)[0]??"";if(!n.includes("/"))continue;let i=n.split("/")[0]??"";i.includes(".")&&i&&t.add(i)}return Array.from(t)}function I(e){return e.split("\n").map(e=>{let t=e.trim();return t.startsWith("package:")?t.slice(8):t}).filter(Boolean)}function O(e){return N(e,e=>(function(e){for(let t of e.trim().split(/\s+/)){let e=t.indexOf("/");if(e<=0)continue;let a=C(t.slice(0,e),!1),n=C(t.slice(e+1),!0);if(a&&n&&a.length===e)return{package:a,activity:n}}return null})(e))}function N(e,t){let a=e.split("\n");for(let e of g)for(let n of a){let a=n.indexOf(e);if(-1===a)continue;let i=n.trim(),r=t(n.slice(a+e.length),i);if(r)return r}return null}function C(e,t){let a=0;for(;a<e.length&&function(e,t){if(!e)return!1;let a=e.charCodeAt(0);return a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122||"_"===e||"."===e||t&&"$"===e}(e[a],t);)a+=1;return e.slice(0,a)}function D(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let a=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!a)return!1;let n=a[1]?.toLowerCase(),i=a[2]??"";return"http"!==n&&"https"!==n&&"ws"!==n&&"wss"!==n&&"ftp"!==n&&"ftps"!==n||i.startsWith("//")}function k(e,t){let a,n=e?.trim();return n?n:"http"===(a=t.trim().split(":")[0]?.toLowerCase())||"https"===a?"com.apple.mobilesafari":void 0}function T(e={}){let t=e.ttlMs??3e4,a=e.nowMs??Date.now,n=new Map,i=e=>{var t;let a=[(t=e).platform,t.deviceId,""].join("\0");for(let e of n.keys())e.startsWith(a)&&n.delete(e)};return{get(e,t){let i=E(e,t),r=n.get(i);if(r)return r.expiresAtMs<=a()?void n.delete(i):r.value},set:(e,i,r)=>(n.set(E(e,i),{value:r,expiresAtMs:a()+t}),r),clear(e){i(e)},async invalidateWhile(e,t){i(e);try{return await t()}finally{i(e)}}}}function E(e,t){return[e.platform,e.deviceId,e.variant??"",t.trim().toLowerCase()].join("\0")}function L(e){return["1","true","yes","on"].includes((e??"").trim().toLowerCase())}class x{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new x(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function S(e,t={},a={}){let n,r={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=r.maxAttempts;t+=1){if(a.signal?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"});if(a.deadline?.isExpired()&&t>1)break;try{let n=await e({attempt:t,maxAttempts:r.maxAttempts,deadline:a.deadline});return a.onEvent?.({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),P({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),n}catch(d){n=d;let e=a.classifyReason?.(d),i={phase:a.phase,event:"attempt_failed",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};if(a.onEvent?.(i),P(i),t>=r.maxAttempts||r.shouldRetry&&!r.shouldRetry(d,t))break;let o=function(e,t,a,n){let i=Math.min(t,e*2**(n-1));return Math.max(0,i+i*a*(2*Math.random()-1))}(r.baseDelayMs,r.maxDelayMs,r.jitter,t),s=a.deadline?Math.min(o,a.deadline.remainingMs()):o;if(s<=0)break;let l={phase:a.phase,event:"retry_scheduled",attempt:t,maxAttempts:r.maxAttempts,delayMs:s,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};a.onEvent?.(l),P(l),await function(e,t){return new Promise(a=>{if(t?.aborted)return void a();let n=!1,i=()=>{n||(n=!0,t&&t.removeEventListener("abort",o),a())},r=setTimeout(i,e);function o(){clearTimeout(r),i()}t&&t.addEventListener("abort",o,{once:!0})})}(s,a.signal)}}let o={phase:a.phase,event:"exhausted",attempt:r.maxAttempts,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:a.classifyReason?.(n)};if(a.onEvent?.(o),P(o),n)throw n;throw new i("COMMAND_FAILED","retry failed")}async function R(e,t={}){return S(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function P(e){r({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}})}function U(e){return e?.trim()||void 0}function F(e){return U(e)}function B(e){return new Set(e.split(/[\s,]+/).map(e=>e.trim()).filter(Boolean))}function $(e,t=process.env){let a=U(e)??U(t.AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST);if(a)return B(a)}let W=new Set(["IOS_BOOT_TIMEOUT","IOS_RUNNER_CONNECT_TIMEOUT","IOS_TOOL_MISSING","ANDROID_BOOT_TIMEOUT","ADB_TRANSPORT_UNAVAILABLE","CI_RESOURCE_STARVATION_SUSPECTED"]);function V(e){return W.has(e.toUpperCase())}function G(e){let t=e.error?n(e.error):null,a=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===a?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let r=t?.details??{},o="string"==typeof r.message?r.message:void 0,s="string"==typeof r.stdout?r.stdout:void 0,l="string"==typeof r.stderr?r.stderr:void 0,d=r.boot&&"object"==typeof r.boot?r.boot:null,u=r.bootstatus&&"object"==typeof r.bootstatus?r.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,o,s,l,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0,"string"==typeof u?.stdout?u.stdout:void 0,"string"==typeof u?.stderr?u.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===a&&(c.includes("runner did not accept connection")||"connect"===i&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===a&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function j(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI reduce parallel jobs or use a larger runner.";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."}}let K=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];async function H(e,t,a){let n=Array(e.length),i=0,r=Math.min(t,e.length);return await Promise.all(Array.from({length:r},async()=>{for(;i<e.length;){let t=i;i+=1,n[t]=await a(e[t])}})),n}function z(e){return`${e.stdout}
2
- ${e.stderr}`}function q(e,t){return["-s",e,...t]}function Z(e){return e.startsWith("emulator-")}function J(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function X(e,t=1e4){return o("adb",q(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function Q(e,t){let a=t.replace(/_/g," ").trim();if(!Z(e))return a||e;let n=await ee(e);return n?n.replace(/_/g," "):a||e}async function Y(e,t,a){try{return await a("adb",q(e,t),{allowFailure:!0,timeoutMs:1e4})}catch(e){var i;if("COMMAND_FAILED"===(i=n(e)).code&&"number"==typeof i.details?.timeoutMs)return;throw e}}async function ee(e,t=o){for(let a of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let n=await Y(e,["shell","getprop",a],t);if(!n)continue;let i=n.stdout.trim();if(0===n.exitCode&&i.length>0)return i}let a=await Y(e,["emu","avd","name"],t);if(!a)return;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0);if(0!==t.length)return"OK"===t.at(-1)&&t.pop(),t.join("\n").trim()||void 0}(a.stdout);if(0===a.exitCode&&n)return n}async function et(e,t){let a=z(await o("adb",q(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase();return!!a.includes("true")||!a.includes("false")&&null}async function ea(e){return(await H(K,2,async t=>await et(e,t))).some(e=>!0===e)}async function en(e){var t;let a;return"tv"===((a=z(await o("adb",q(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase()).includes("tv")||a.includes("leanback")?"tv":null)||await ea(e)?"tv":(t=z(await o("adb",q(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:1e4})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function ei(e={}){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??$(void 0),a=(await er()).filter(e=>!t||t.has(e.serial));return await H(a,3,async({serial:e,rawModel:t})=>{let[a,n,i]=await Promise.all([Q(e,t),ed(e),en(e)]);return{platform:"android",id:e,name:a,kind:Z(e)?"emulator":"device",target:i,booted:n}})}async function er(){return(await o("adb",["devices","-l"],{timeoutMs:1e4})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).flatMap(e=>{let t=e[0];return void 0===t||"device"!==e[1]?[]:[{serial:t,rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}]})}async function eo(){let e=await o("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:1e4});if(0!==e.exitCode)throw new i("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function es(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await el(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await p(1e3)}throw new i("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function el(e,t){let a=J(e);for(let e of(await er()).filter(e=>(!t||e.serial===t)&&Z(e.serial)))if(J(e.rawModel)===a||J(await Q(e.serial,e.rawModel))===a)return e.serial}async function ed(e){try{let t=await X(e);return"1"===t.stdout.trim()}catch{return!1}}async function eu(e){var t,a;let n;await u();let r=e.avdName.trim();if(!r)throw new i("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let o=e.timeoutMs??12e4;if(!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");if(!await l("emulator"))throw new i("TOOL_MISSING","emulator not found in PATH");let s=await eo(),c=function(e,t){let a=e.find(e=>e===t);if(a)return a;let n=J(t);return e.find(e=>J(e)===n)}(s,r);if(!c)throw new i("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:r,availableAvds:s,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let p=Date.now(),f=(t=await ei(),a=e.serial,n=J(c),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!a||e.id===a)&&J(e.name)===n));if(!f){let t=["-avd",c];e.headless&&t.push("-no-window","-no-audio"),d("emulator",t)}let m=f??await es({avdName:c,serial:e.serial,timeoutMs:o}),w=Math.max(1e3,o-(Date.now()-p));await ec(m.id,w);let h=(await ei()).find(e=>e.id===m.id);return h?{...h,name:c,booted:!0}:{...m,name:c,booted:!0}}async function ec(e,t=6e4){let a,r=x.fromTimeoutMs(t),o=Math.max(1,Math.ceil(t/1e3)),s=!1;try{await S(async({deadline:n})=>{if(n?.isExpired())throw s=!0,new i("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),l=await X(e,Math.min(o,1e4));if(a=l,"1"!==l.stdout.trim())throw new i("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:l.stdout,stderr:l.stderr,exitCode:l.exitCode})},{maxAttempts:o,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=G({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:r,phase:"boot",classifyReason:e=>G({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}})})}catch(f){let o=n(f),l=a?.stdout,d=a?.stderr,u=a?.exitCode,c=G({error:f,stdout:l,stderr:d,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===c&&"Android device is still booting"===o.message&&(c="ANDROID_BOOT_TIMEOUT");let p={serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),reason:c,hint:j(c),stdout:l,stderr:d,exitCode:u};if(s||"ANDROID_BOOT_TIMEOUT"===c)throw new i("COMMAND_FAILED","Android device did not finish booting in time",p);if("TOOL_MISSING"===o.code)throw new i("TOOL_MISSING",o.message,{...p,...o.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===c)throw new i("COMMAND_FAILED",o.message,{...p,...o.details??{}});throw new i(o.code,o.message,{...p,...o.details??{}},o.cause)}}async function ep(e,t,a){return await h(e)(t,a)}function ef(e){return{platform:"android",id:e,name:e,kind:e.startsWith("emulator-")?"emulator":"device",booted:!0}}async function em(){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH")}let ew=/\.(?:apk|aab)$/i,eh=/^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$/;function eA(e){var t,a;let n=e.trim();return 0===n.length?"other":ew.test(n)?n.includes("/")||n.includes("\\")||n.startsWith(".")||n.startsWith("~")||(t=n,!eh.test(t))?"binary":"package":(a=n,eh.test(a))?"package":"other"}function ey(e){return`Android runtime hints require an installed package name, not "${e}". Install or reinstall the app first, then relaunch by package.`}async function eg(e,t){let n="url"===e.kind&&y(e.url),i=await A({source:e,isInstallablePath:(e,t)=>{var n;let i;return t.isFile()&&(n=e,".apk"===(i=a.extname(n).toLowerCase())||".aab"===i)},installableLabel:"Android installable (.apk or .aab)",allowArchiveExtraction:"url"!==e.kind||n,signal:t?.signal});try{let e=t?.resolveIdentity===!1?{}:await ev(i.installablePath);return{archivePath:i.archivePath,installablePath:i.installablePath,packageName:e.packageName,cleanup:i.cleanup}}catch(e){throw await i.cleanup(),e}}async function ev(e){let t=a.extname(e).toLowerCase();return".apk"!==t&&".aab"!==t?{}:{packageName:await c(e)}}let eb={settings:{type:"intent",value:"android.settings.SETTINGS"}},eM="android.intent.category.LAUNCHER",e_="android.intent.category.LEANBACK_LAUNCHER",eI="android.intent.category.DEFAULT",eO="Run agent-device apps --platform android to discover the installed package name, then retry open with that exact package.",eN=new Set(["localhost","127.0.0.1","::1","[::1]"]),eC=T();function eD(e){return{platform:"android",deviceId:e.id,variant:e.target??""}}async function ek(e,t){let a=t.trim();if("package"===eA(a))return{type:"package",value:a};let n=eb[a.toLowerCase()];if(n)return n;let r=eD(e),o=eC.get(r,a);if(o)return o;let s=(await ep(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(a.toLowerCase())),l=s[0];if(void 0!==l&&1===s.length)return eC.set(r,a,{type:"package",value:l});if(s.length>1)throw new i("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:s,hint:"Run agent-device apps --platform android to see the exact installed package names before retrying open."});throw new i("APP_NOT_INSTALLED",`No package found matching "${t}"`,{hint:eO})}async function eT(e,t){let a=await eE(e);return("user-installed"===t?(await ex(e)).filter(e=>a.has(e)):Array.from(a)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:eS(e)}))}async function eE(e){let t=new Set;for(let a of eL(e,{includeFallbackWhenUnknown:!0})){let n=await ep(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",a],{allowFailure:!0});if(0===n.exitCode&&0!==n.stdout.trim().length)for(let e of _(n.stdout))t.add(e)}return t}function eL(e,t={}){return"tv"===e.target?[e_]:"mobile"===e.target?[eM]:t.includeFallbackWhenUnknown?[eM,e_]:[eM]}async function ex(e){return I((await ep(e,["shell","pm","list","packages","-3"])).stdout)}function eS(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),a=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),n=a[a.length-1]??e;for(let e=a.length-1;e>=0;e-=1){let i=a[e];if(i&&!t.has(i)){n=i;break}}return n.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function eR(e){let t=await eU(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let a=await eU(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return a||{}}async function eP(e){return await eF(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]])}async function eU(e,t){for(let a of t){let t=O((await ep(e,a,{allowFailure:!0})).stdout??"");if(t)return t}return null}async function eF(e,t){for(let a of t){let t=N((await ep(e,a,{allowFailure:!0})).stdout??"",(e,t)=>(function(e,t){let a=e.split("}")[0]?.trim()??e.trim(),n=v.exec(a);if(n){let e=n[1];return{package:e,focusedWindow:`Application Not Responding: ${e}`,raw:t}}let i=b.exec(a);if(!i)return null;let r=i[1];if(void 0===r)return null;let o=r.trim().replace(/\s+/g," "),s=M.exec(o)?.[1];return{...s?{package:s}:{},focusedWindow:o,raw:t}})(e,t));if(t)return t}return null}async function eB(e,t){let a=function(e){let t;try{t=new URL(e)}catch{return null}let a=t.hostname.toLowerCase();if(!eN.has(a)||!t.port)return null;let n=Number(t.port);return Number.isInteger(n)?`tcp:${n}`:null}(t);if(!a)return;let n=f(m(e));try{await n.ensure({local:a,remote:a})}catch(t){let e={localPort:a.replace("tcp:",""),operation:`adb reverse ${a} ${a}`};throw t instanceof i&&Object.assign(e,{hint:t.details?.hint,diagnosticId:t.details?.diagnosticId,logPath:t.details?.logPath}),new i("COMMAND_FAILED",`Failed to ensure Android port reverse ${a} before opening localhost URL`,e,t)}}async function e$(e,t,a){var n;e.booted||await ec(e.id);let i="string"==typeof(n=a)?{activity:n}:n??{},r=i.activity,o=t.trim();if(D(o))return void await eW(e,o,i);if(void 0!==i.url)return void await eV(e,t,i);let s=await ek(e,t),l=eL(e)[0]??eM;"intent"===s.type?await eG(e,s.value,r):r?await ej(e,s.value,r,l):await eK(e,s.value,l)}async function eW(e,t,a){var n;let r;if(a.activity)throw new i("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await eB(e,t),await ep(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",t,...(n=a.appBundleId,(r=n?.trim())?["-p",r]:[])])}async function eV(e,t,a){if(a.activity)throw new i("INVALID_ARGS","Activity override is not supported when opening an app-bound deep link URL");let n=a.url?.trim()??"";if(!D(n))throw new i("INVALID_ARGS","Android app-bound open requires a valid URL target");let r=await ez(e,t,"app-bound open");await ep(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",n,"-p",r])}async function eG(e,t,a){if(a)throw new i("INVALID_ARGS","Activity override requires a package name, not an intent");await ep(e,["shell","am","start","-W","-a",t])}async function ej(e,t,a,n){let i=a.includes("/")?a:`${t}/${a.startsWith(".")?a:`.${a}`}`;try{await ep(e,eH(i,n))}catch(a){throw await eJ(e,t,a),a}}async function eK(e,t,a){let n=await ep(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eI,"-c",a,"-p",t],{allowFailure:!0});if(0===n.exitCode&&!eY(n.stdout,n.stderr))return;let r=await eQ(e,t);if(!r){if(!await eZ(e,t))throw eq(t);throw new i("COMMAND_FAILED",`Failed to launch ${t}`,{stdout:n.stdout,stderr:n.stderr})}await ep(e,eH(r,a))}function eH(e,t){return["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eI,"-c",t,"-n",e]}async function ez(e,t,a){let n=await ek(e,t);if("intent"===n.type)throw new i("INVALID_ARGS",`Android ${a} requires a package name, not an intent`);return n.value}function eq(e){return new i("APP_NOT_INSTALLED",`No package found matching "${e}"`,{package:e,hint:eO})}async function eZ(e,t){let a=await ep(e,["shell","pm","path",t],{allowFailure:!0}),n=`${a.stdout}
3
- ${a.stderr}`;return!!(0===a.exitCode&&/\bpackage:/i.test(n))||(eX(n),!1)}async function eJ(e,t,a){if(eX(a instanceof i?`${String(a.details?.stdout??"")}
4
- ${String(a.details?.stderr??"")}`:"")||!await eZ(e,t))throw eq(t)}function eX(e){return/\bunknown package\b/i.test(e)||/\bpackage .* (?:was|is) not found\b/i.test(e)||/\bpackage .* does not exist\b/i.test(e)||/\bcould not find package\b/i.test(e)}async function eQ(e,t){for(let a of Array.from(new Set(eL(e,{includeFallbackWhenUnknown:!0})))){let n=await ep(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",a,t],{allowFailure:!0});if(0!==n.exitCode)continue;let i=e0(n.stdout);if(i)return i}return null}function eY(e,t){let a=`${e}
5
- ${t}`;return/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)}function e0(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let a=t[e];if(void 0===a||!a.includes("/"))continue;let n=a.split(/\s+/)[0];if(void 0!==n)return n}return null}async function e1(e){e.booted||await ec(e.id)}async function e2(e,t){if("settings"===t.trim().toLowerCase())return void await ep(e,["shell","am","force-stop","com.android.settings"]);let a=await ek(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","Close requires a package name, not an intent");await ep(e,["shell","am","force-stop",a.value])}async function e9(e,t){let a=await ek(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","App uninstall requires a package name, not an intent");let n=await ep(e,["uninstall",a.value],{allowFailure:!0});if(0!==n.exitCode){let e=`${n.stdout}
6
- ${n.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new i("COMMAND_FAILED",`adb uninstall failed for ${a.value}`,{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})}return{package:a.value}}let e4=null;async function e3(){let e=`${process.env.PATH??""}::${process.env.AGENT_DEVICE_BUNDLETOOL_JAR??""}`;if(e4?.key===e)return e4.invocation;if(await l("bundletool")){let t={cmd:"bundletool",prefixArgs:[]};return e4={key:e,invocation:t},t}let t=await s(process.env.AGENT_DEVICE_BUNDLETOOL_JAR,"AGENT_DEVICE_BUNDLETOOL_JAR");if(!t)throw new i("TOOL_MISSING","bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR to a bundletool-all.jar path.");let a={cmd:"java",prefixArgs:["-jar",t]};return e4={key:e,invocation:a},a}async function e8(e){let t=await e3();await o(t.cmd,[...t.prefixArgs,...e])}async function e6(n,i){let r=m(n),o="universal";if(r.installBundle)return void await r.installBundle(i,{mode:o});let s=await e.mkdtemp(a.join(t.tmpdir(),"agent-device-aab-")),l=a.join(s,"bundle.apks");try{await e8(["build-apks","--bundle",i,"--output",l,"--mode",o]),await e8(["install-apks","--apks",l,"--device-id",n.id])}finally{await e.rm(s,{recursive:!0,force:!0})}}async function e5(e,t){".aab"===a.extname(t).toLowerCase()?await e6(e,t):await w(t,{device:e,replace:!0})}async function e7(e){return new Set((await ep(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean))}async function te(e,t){let a=Array.from(await e7(e)).filter(e=>!t.has(e));if(1===a.length)return a[0]}async function tt(e,t){await eC.invalidateWhile(eD(e),async()=>{e.booted||await ec(e.id),await e5(e,t)})}async function ta(e,t,a){let n=a?void 0:await e7(e);return await tt(e,t),a??(n?await te(e,n):void 0)}async function tn(e,t){e.booted||await ec(e.id);let a=await eg({kind:"path",path:t});try{let t=await ta(e,a.installablePath,a.packageName),n=t?eS(t):void 0;return{archivePath:a.archivePath,installablePath:a.installablePath,packageName:t,appName:n,launchTarget:t}}finally{await a.cleanup()}}async function ti(e,t,a){return await eC.invalidateWhile(eD(e),async()=>{e.booted||await ec(e.id);let{package:n}=await e9(e,t),i=await eg({kind:"path",path:a},{resolveIdentity:!1});try{await tt(e,i.installablePath)}finally{await i.cleanup()}return{package:n}})}async function tr(e,t={}){let a=["logcat","-d","-v","time"];void 0!==t.lines&&a.push("-t",String(Math.max(1,Math.floor(t.lines))));let n=await e(a,{allowFailure:!0,timeoutMs:t.timeoutMs,signal:t.signal});if(0!==n.exitCode)throw new i("COMMAND_FAILED","Failed to capture Android logcat",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode});return n.stdout}function to(e,t={}){if(!e.spawn)throw new i("UNSUPPORTED_OPERATION","Android ADB provider does not support streams",{capability:"adb.spawn"});let a=["logcat","-v","time"];t.pid&&a.push("--pid",t.pid);let n=e.spawn(a,{stdio:["ignore","pipe","pipe"],signal:t.signal});return t.output&&n.stdout&&n.stdout.pipe(t.output,{end:!1}),n}let ts=new Set(["com.google.android.inputmethod.latin","com.samsung.android.honeyboard","com.touchtype.swiftkey","com.microsoft.swiftkey"]);function tl(e){let t=tu(e.packageName),a=(e.resourceId??"").toLowerCase(),n=tu(e.activeInputMethodPackage);if(t&&n&&t===n)return{inputMethodOwned:!0,source:"active-input-method"};if(n&&a.startsWith(`${n}:id/`))return{inputMethodOwned:!0,source:"active-input-method-resource"};if(t&&ts.has(t))return{inputMethodOwned:!0,source:"known-ime-package"};for(let e of ts)if(a.startsWith(`${e}:id/`))return{inputMethodOwned:!0,source:"known-ime-resource"};return{inputMethodOwned:!1,source:"app"}}function td(e){return tl(e).inputMethodOwned}function tu(e){return(e??"").trim().toLowerCase()||void 0}async function tc(e){return await tp(h(e))}async function tp(e){let t=await e(["shell","dumpsys","input_method"],{allowFailure:!0});if(0!==t.exitCode)throw new i("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t,a=function(e){let t=new Map;for(let a of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=a[1],n=a[2]?.toLowerCase();e&&("true"===n||"false"===n)&&t.set(e,"true"===n)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),n=a??!1;if(null===a){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(n=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),o=i.length>0?i[i.length-1]?.[1]:void 0,s=o?`0x${o.toLowerCase()}`:void 0,l=tw(e,/\bpackageName=([A-Za-z0-9_.]+)\b/g),d=tw(e,/\b(?:resourceId|resource-id)=([^\s,}]+)/g),u=function(e){for(let t of[/\bmCurMethodId=([^\s]+)/i,/\bmCurId=([^\s]+)/i,/\bmCurrentInputMethodId=([^\s]+)/i,/\bcurMethodId=([^\s]+)/i]){let a=e.match(t),n=function(e){let t=(e??"").trim();if(!t)return;let a=(t.split("/")[0]??"").match(/[a-zA-Z0-9_.]+/);return tu(a?.[0])}(a?.[1]);if(n)return n}}(e),c=function(e,t,a){return e||t?tl({packageName:e,resourceId:t,activeInputMethodPackage:a}).inputMethodOwned?"ime":"app":"unknown"}(l,d,u);return!u&&((t=tu(l))&&ts.has(t)||function(e){let t=(e??"").toLowerCase();for(let e of ts)if(t.startsWith(`${e}:id/`))return!0;return!1}(d))&&r({level:"warn",phase:"android_input_ownership_fallback",data:{focusedPackage:l,focusedResourceId:d}}),{visible:n,inputType:s,type:s?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let a=15&t;if(2===a)return"number";if(3===a)return"phone";if(4===a)return"datetime";if(1!==a)return"unknown";let n=4080&t;return 32===n||208===n?"email":128===n||224===n||144===n?"password":"text"}(s):void 0,inputMethodPackage:u,focusedPackage:l,focusedResourceId:d,inputOwner:c}}(t.stdout)}async function tf(e){return await tm(h(e))}async function tm(e){let t=await tp(e),a=t,n=0;for(;a.visible&&n<2;)await e(["shell","input","keyevent","111"]),n+=1,await p(120),a=await tp(e);if(t.visible&&a.visible)throw new i("UNSUPPORTED_OPERATION","Android keyboard dismiss is unavailable for the current IME without back navigation.",{attempts:n,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner});return{attempts:n,wasVisible:t.visible,dismissed:t.visible&&!a.visible,visible:a.visible,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner}}function tw(e,t){let a;for(let n of e.matchAll(t))a=n[1];return a}async function th(e){return await tA(h(e))}async function tA(e){let t,a;return(a=(t=(await tv(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?a[1]??"":"null"===t.trim().toLowerCase()?"":t}async function ty(e,t){await tg(h(e),t)}async function tg(e,t){await tv(e,["shell","cmd","clipboard","set","text",t],"write")}async function tv(e,t,a){var n,r;let o,s=await e(t,{allowFailure:!0});if(n=s.stdout,r=s.stderr,(o=`${n}
7
- ${r}`.toLowerCase()).includes("no shell command implementation")||o.includes("unknown command"))throw new i("UNSUPPORTED_OPERATION",`Android shell clipboard ${a} is not supported on this device.`);if(0!==s.exitCode)throw new i("COMMAND_FAILED",`Failed to ${a} Android clipboard text`,{stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode});return s.stdout}export{x as Deadline,ef as androidDeviceForSerial,j as bootFailureHint,tr as captureAndroidLogcatWithAdb,eA as classifyAndroidAppTarget,G as classifyBootFailure,e2 as closeAndroidApp,T as createAppResolutionCache,tf as dismissAndroidKeyboard,tm as dismissAndroidKeyboardWithAdb,em as ensureAdb,eu as ensureAndroidEmulatorBooted,ey as formatAndroidInstalledPackageRequiredMessage,eR as getAndroidAppState,eP as getAndroidBlockingDialogFocus,tc as getAndroidKeyboardState,tp as getAndroidKeyboardStatusWithAdb,eS as inferAndroidAppName,tn as installAndroidApp,ta as installAndroidInstallablePathAndResolvePackageName,eY as isAmStartError,td as isAndroidInputMethodOwnedNode,D as isDeepLinkTarget,L as isEnvTruthy,V as isInfrastructureBootFailureReason,eT as listAndroidApps,ei as listAndroidDevices,e$ as openAndroidApp,e1 as openAndroidDevice,O as parseAndroidForegroundApp,e0 as parseAndroidLaunchComponent,_ as parseAndroidLaunchablePackages,I as parseAndroidUserInstalledPackages,B as parseSerialAllowlist,eg as prepareAndroidInstallArtifact,th as readAndroidClipboardText,tA as readAndroidClipboardWithAdb,ti as reinstallAndroidApp,ek as resolveAndroidApp,$ as resolveAndroidSerialAllowlist,k as resolveIosDeviceDeepLinkBundleId,F as resolveIosSimulatorDeviceSetPath,S as retryWithPolicy,ep as runAndroidAdb,to as streamAndroidLogcatWithAdb,ec as waitForAndroidBoot,R as withRetry,ty as writeAndroidClipboardText,tg as writeAndroidClipboardWithAdb};
1
+ import{promises as e}from"node:fs";import t from"node:os";import a from"node:path";import{asAppError as n,AppError as i}from"./9152.js";import{emitDiagnostic as r}from"./7599.js";import{runCmd as o,resolveFileOverridePath as s,whichCmd as l,runCmdDetached as d}from"./9818.js";import{ensureAndroidSdkPathConfigured as u,resolveAndroidArchivePackageName as c}from"./7651.js";import{sleep as p}from"./4829.js";import{createAndroidPortReverseManager as f,resolveAndroidAdbProvider as m,installAndroidAdbPackage as w,resolveAndroidAdbExecutor as h}from"./9639.js";import{materializeInstallablePath as A,isTrustedInstallSourceUrl as y}from"./989.js";let g=["mCurrentFocus=Window{","mFocusedApp=AppWindowToken{","mResumedActivity:","ResumedActivity:"],b=/\bApplication Not Responding:\s*([A-Za-z0-9_.]+)/i,v=/([^{}]*\bis(?:n't| not)\s+responding[^{}]*)/i,M=/\b([A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+)\b/;function _(e){let t=new Set;for(let a of e.split("\n")){let e=a.trim();if(!e)continue;let n=e.split(/\s+/)[0]??"";if(!n.includes("/"))continue;let i=n.split("/")[0]??"";i.includes(".")&&i&&t.add(i)}return Array.from(t)}function I(e){return e.split("\n").map(e=>{let t=e.trim();return t.startsWith("package:")?t.slice(8):t}).filter(Boolean)}function O(e){return N(e,e=>(function(e){for(let t of e.trim().split(/\s+/)){let e=t.indexOf("/");if(e<=0)continue;let a=C(t.slice(0,e),!1),n=C(t.slice(e+1),!0);if(a&&n&&a.length===e)return{package:a,activity:n}}return null})(e))}function N(e,t){let a=e.split("\n");for(let e of g)for(let n of a){let a=n.indexOf(e);if(-1===a)continue;let i=n.trim(),r=t(n.slice(a+e.length),i);if(r)return r}return null}function C(e,t){let a=0;for(;a<e.length&&function(e,t){if(!e)return!1;let a=e.charCodeAt(0);return a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122||"_"===e||"."===e||t&&"$"===e}(e[a],t);)a+=1;return e.slice(0,a)}function D(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let a=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!a)return!1;let n=a[1]?.toLowerCase(),i=a[2]??"";return"http"!==n&&"https"!==n&&"ws"!==n&&"wss"!==n&&"ftp"!==n&&"ftps"!==n||i.startsWith("//")}function k(e){let t=e.trim().split(":")[0]?.toLowerCase();return"http"===t||"https"===t}function T(e,t){let a=e?.trim();return a||(k(t)?"com.apple.mobilesafari":void 0)}function E(e={}){let t=e.ttlMs??3e4,a=e.nowMs??Date.now,n=new Map,i=e=>{var t;let a=[(t=e).platform,t.deviceId,""].join("\0");for(let e of n.keys())e.startsWith(a)&&n.delete(e)};return{get(e,t){let i=S(e,t),r=n.get(i);if(r)return r.expiresAtMs<=a()?void n.delete(i):r.value},set:(e,i,r)=>(n.set(S(e,i),{value:r,expiresAtMs:a()+t}),r),clear(e){i(e)},async invalidateWhile(e,t){i(e);try{return await t()}finally{i(e)}}}}function S(e,t){return[e.platform,e.deviceId,e.variant??"",t.trim().toLowerCase()].join("\0")}function L(e){return["1","true","yes","on"].includes((e??"").trim().toLowerCase())}class x{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new x(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function R(e,t={},a={}){let n,r={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=r.maxAttempts;t+=1){if(a.signal?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"});if(a.deadline?.isExpired()&&t>1)break;try{let n=await e({attempt:t,maxAttempts:r.maxAttempts,deadline:a.deadline});return a.onEvent?.({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),U({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),n}catch(d){n=d;let e=a.classifyReason?.(d),i={phase:a.phase,event:"attempt_failed",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};if(a.onEvent?.(i),U(i),t>=r.maxAttempts||r.shouldRetry&&!r.shouldRetry(d,t))break;let o=function(e,t,a,n){let i=Math.min(t,e*2**(n-1));return Math.max(0,i+i*a*(2*Math.random()-1))}(r.baseDelayMs,r.maxDelayMs,r.jitter,t),s=a.deadline?Math.min(o,a.deadline.remainingMs()):o;if(s<=0)break;let l={phase:a.phase,event:"retry_scheduled",attempt:t,maxAttempts:r.maxAttempts,delayMs:s,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};a.onEvent?.(l),U(l),await function(e,t){return new Promise(a=>{if(t?.aborted)return void a();let n=!1,i=()=>{n||(n=!0,t&&t.removeEventListener("abort",o),a())},r=setTimeout(i,e);function o(){clearTimeout(r),i()}t&&t.addEventListener("abort",o,{once:!0})})}(s,a.signal)}}let o={phase:a.phase,event:"exhausted",attempt:r.maxAttempts,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:a.classifyReason?.(n)};if(a.onEvent?.(o),U(o),n)throw n;throw new i("COMMAND_FAILED","retry failed")}async function P(e,t={}){return R(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function U(e){r({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}})}function F(e){return e?.trim()||void 0}function B(e){return F(e)}function V(e){return new Set(e.split(/[\s,]+/).map(e=>e.trim()).filter(Boolean))}function W(e,t=process.env){let a=F(e)??F(t.AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST);if(a)return V(a)}let $=new Set(["IOS_BOOT_TIMEOUT","IOS_RUNNER_CONNECT_TIMEOUT","IOS_TOOL_MISSING","ANDROID_BOOT_TIMEOUT","ADB_TRANSPORT_UNAVAILABLE","CI_RESOURCE_STARVATION_SUSPECTED"]);function G(e){return $.has(e.toUpperCase())}function j(e){let t=e.error?n(e.error):null,a=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===a?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let r=t?.details??{},o="string"==typeof r.message?r.message:void 0,s="string"==typeof r.stdout?r.stdout:void 0,l="string"==typeof r.stderr?r.stderr:void 0,d=r.boot&&"object"==typeof r.boot?r.boot:null,u=r.bootstatus&&"object"==typeof r.bootstatus?r.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,o,s,l,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0,"string"==typeof u?.stdout?u.stdout:void 0,"string"==typeof u?.stderr?u.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===a&&(c.includes("runner did not accept connection")||"connect"===i&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===a&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function K(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI reduce parallel jobs or use a larger runner.";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."}}let H=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];async function z(e,t,a){let n=Array(e.length),i=0,r=Math.min(t,e.length);return await Promise.all(Array.from({length:r},async()=>{for(;i<e.length;){let t=i;i+=1,n[t]=await a(e[t])}})),n}function q(e){return`${e.stdout}
2
+ ${e.stderr}`}function Z(e,t){return["-s",e,...t]}function J(e){return e.startsWith("emulator-")}function X(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function Q(e,t=1e4){return o("adb",Z(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function Y(e,t){let a=t.replace(/_/g," ").trim();if(!J(e))return a||e;let n=await et(e);return n?n.replace(/_/g," "):a||e}async function ee(e,t,a){try{return await a("adb",Z(e,t),{allowFailure:!0,timeoutMs:1e4})}catch(e){var i;if("COMMAND_FAILED"===(i=n(e)).code&&"number"==typeof i.details?.timeoutMs)return;throw e}}async function et(e,t=o){for(let a of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let n=await ee(e,["shell","getprop",a],t);if(!n)continue;let i=n.stdout.trim();if(0===n.exitCode&&i.length>0)return i}let a=await ee(e,["emu","avd","name"],t);if(!a)return;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0);if(0!==t.length)return"OK"===t.at(-1)&&t.pop(),t.join("\n").trim()||void 0}(a.stdout);if(0===a.exitCode&&n)return n}async function ea(e,t){let a=q(await o("adb",Z(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase();return!!a.includes("true")||!a.includes("false")&&null}async function en(e){return(await z(H,2,async t=>await ea(e,t))).some(e=>!0===e)}async function ei(e){var t;let a;return"tv"===((a=q(await o("adb",Z(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase()).includes("tv")||a.includes("leanback")?"tv":null)||await en(e)?"tv":(t=q(await o("adb",Z(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:1e4})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function er(e={}){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??W(void 0),a=(await eo()).filter(e=>!t||t.has(e.serial));return await z(a,3,async({serial:e,rawModel:t})=>{let[a,n,i]=await Promise.all([Y(e,t),eu(e),ei(e)]);return{platform:"android",id:e,name:a,kind:J(e)?"emulator":"device",target:i,booted:n}})}async function eo(){return(await o("adb",["devices","-l"],{timeoutMs:1e4})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).flatMap(e=>{let t=e[0];return void 0===t||"device"!==e[1]?[]:[{serial:t,rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}]})}async function es(){let e=await o("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:1e4});if(0!==e.exitCode)throw new i("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function el(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await ed(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await p(1e3)}throw new i("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function ed(e,t){let a=X(e);for(let e of(await eo()).filter(e=>(!t||e.serial===t)&&J(e.serial)))if(X(e.rawModel)===a||X(await Y(e.serial,e.rawModel))===a)return e.serial}async function eu(e){try{let t=await Q(e);return"1"===t.stdout.trim()}catch{return!1}}async function ec(e){var t,a;let n;await u();let r=e.avdName.trim();if(!r)throw new i("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let o=e.timeoutMs??12e4;if(!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");if(!await l("emulator"))throw new i("TOOL_MISSING","emulator not found in PATH");let s=await es(),c=function(e,t){let a=e.find(e=>e===t);if(a)return a;let n=X(t);return e.find(e=>X(e)===n)}(s,r);if(!c)throw new i("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:r,availableAvds:s,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let p=Date.now(),f=(t=await er(),a=e.serial,n=X(c),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!a||e.id===a)&&X(e.name)===n));if(!f){let t=["-avd",c];e.headless&&t.push("-no-window","-no-audio"),d("emulator",t)}let m=f??await el({avdName:c,serial:e.serial,timeoutMs:o}),w=Math.max(1e3,o-(Date.now()-p));await ep(m.id,w);let h=(await er()).find(e=>e.id===m.id);return h?{...h,name:c,booted:!0}:{...m,name:c,booted:!0}}async function ep(e,t=6e4){let a,r=x.fromTimeoutMs(t),o=Math.max(1,Math.ceil(t/1e3)),s=!1;try{await R(async({deadline:n})=>{if(n?.isExpired())throw s=!0,new i("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),l=await Q(e,Math.min(o,1e4));if(a=l,"1"!==l.stdout.trim())throw new i("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:l.stdout,stderr:l.stderr,exitCode:l.exitCode})},{maxAttempts:o,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=j({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:r,phase:"boot",classifyReason:e=>j({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}})})}catch(f){let o=n(f),l=a?.stdout,d=a?.stderr,u=a?.exitCode,c=j({error:f,stdout:l,stderr:d,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===c&&"Android device is still booting"===o.message&&(c="ANDROID_BOOT_TIMEOUT");let p={serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),reason:c,hint:K(c),stdout:l,stderr:d,exitCode:u};if(s||"ANDROID_BOOT_TIMEOUT"===c)throw new i("COMMAND_FAILED","Android device did not finish booting in time",p);if("TOOL_MISSING"===o.code)throw new i("TOOL_MISSING",o.message,{...p,...o.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===c)throw new i("COMMAND_FAILED",o.message,{...p,...o.details??{}});throw new i(o.code,o.message,{...p,...o.details??{}},o.cause)}}async function ef(e,t,a){return await h(e)(t,a)}function em(e){return{platform:"android",id:e,name:e,kind:e.startsWith("emulator-")?"emulator":"device",booted:!0}}async function ew(){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH")}let eh=/\.(?:apk|aab)$/i,eA=/^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$/;function ey(e){var t,a;let n=e.trim();return 0===n.length?"other":eh.test(n)?n.includes("/")||n.includes("\\")||n.startsWith(".")||n.startsWith("~")||(t=n,!eA.test(t))?"binary":"package":(a=n,eA.test(a))?"package":"other"}function eg(e){return`Android runtime hints require an installed package name, not "${e}". Install or reinstall the app first, then relaunch by package.`}async function eb(e,t){let n="url"===e.kind&&y(e.url),i=await A({source:e,isInstallablePath:(e,t)=>{var n;let i;return t.isFile()&&(n=e,".apk"===(i=a.extname(n).toLowerCase())||".aab"===i)},installableLabel:"Android installable (.apk or .aab)",allowArchiveExtraction:"url"!==e.kind||n,signal:t?.signal});try{let e=t?.resolveIdentity===!1?{}:await ev(i.installablePath);return{archivePath:i.archivePath,installablePath:i.installablePath,packageName:e.packageName,cleanup:i.cleanup}}catch(e){throw await i.cleanup(),e}}async function ev(e){let t=a.extname(e).toLowerCase();return".apk"!==t&&".aab"!==t?{}:{packageName:await c(e)}}let eM={settings:{type:"intent",value:"android.settings.SETTINGS"}},e_="android.intent.category.LAUNCHER",eI="android.intent.category.LEANBACK_LAUNCHER",eO="android.intent.category.DEFAULT",eN="Run agent-device apps --platform android to discover the installed package name, then retry open with that exact package.",eC=new Set(["localhost","127.0.0.1","::1","[::1]"]),eD=E();function ek(e){return{platform:"android",deviceId:e.id,variant:e.target??""}}async function eT(e,t){let a=t.trim();if("package"===ey(a))return{type:"package",value:a};let n=eM[a.toLowerCase()];if(n)return n;let r=ek(e),o=eD.get(r,a);if(o)return o;let s=(await ef(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(a.toLowerCase())),l=s[0];if(void 0!==l&&1===s.length)return eD.set(r,a,{type:"package",value:l});if(s.length>1)throw new i("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:s,hint:"Run agent-device apps --platform android to see the exact installed package names before retrying open."});throw new i("APP_NOT_INSTALLED",`No package found matching "${t}"`,{hint:eN})}async function eE(e,t){let a=await eS(e);return("user-installed"===t?(await ex(e)).filter(e=>a.has(e)):Array.from(a)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:eR(e)}))}async function eS(e){let t=new Set;for(let a of eL(e,{includeFallbackWhenUnknown:!0})){let n=await ef(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",a],{allowFailure:!0});if(0===n.exitCode&&0!==n.stdout.trim().length)for(let e of _(n.stdout))t.add(e)}return t}function eL(e,t={}){return"tv"===e.target?[eI]:"mobile"===e.target?[e_]:t.includeFallbackWhenUnknown?[e_,eI]:[e_]}async function ex(e){return I((await ef(e,["shell","pm","list","packages","-3"])).stdout)}function eR(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),a=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),n=a[a.length-1]??e;for(let e=a.length-1;e>=0;e-=1){let i=a[e];if(i&&!t.has(i)){n=i;break}}return n.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function eP(e){let t=await eF(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let a=await eF(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return a||{}}async function eU(e){return await eB(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]])}async function eF(e,t){for(let a of t){let t=O((await ef(e,a,{allowFailure:!0})).stdout??"");if(t)return t}return null}async function eB(e,t){for(let a of t){let t=N((await ef(e,a,{allowFailure:!0})).stdout??"",(e,t)=>(function(e,t){let a=e.split("}")[0]?.trim()??e.trim(),n=b.exec(a);if(n){let e=n[1];return{package:e,focusedWindow:`Application Not Responding: ${e}`,raw:t}}let i=v.exec(a);if(!i)return null;let r=i[1];if(void 0===r)return null;let o=r.trim().replace(/\s+/g," "),s=M.exec(o)?.[1];return{...s?{package:s}:{},focusedWindow:o,raw:t}})(e,t));if(t)return t}return null}async function eV(e,t){let a=function(e){let t;try{t=new URL(e)}catch{return null}let a=t.hostname.toLowerCase();if(!eC.has(a)||!t.port)return null;let n=Number(t.port);return Number.isInteger(n)?`tcp:${n}`:null}(t);if(!a)return;let n=f(m(e));try{await n.ensure({local:a,remote:a})}catch(t){let e={localPort:a.replace("tcp:",""),operation:`adb reverse ${a} ${a}`};throw t instanceof i&&Object.assign(e,{hint:t.details?.hint,diagnosticId:t.details?.diagnosticId,logPath:t.details?.logPath}),new i("COMMAND_FAILED",`Failed to ensure Android port reverse ${a} before opening localhost URL`,e,t)}}async function eW(e,t,a){var n;e.booted||await ep(e.id);let i="string"==typeof(n=a)?{activity:n}:n??{},r=i.activity,o=t.trim();if(D(o))return void await e$(e,o,i);if(void 0!==i.url)return void await eG(e,t,i);let s=await eT(e,t),l=eL(e)[0]??e_;"intent"===s.type?await ej(e,s.value,r):r?await eK(e,s.value,r,l):await eH(e,s.value,l)}async function e$(e,t,a){var n;let r;if(a.activity)throw new i("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await eV(e,t),await ef(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",t,...(n=a.appBundleId,(r=n?.trim())?["-p",r]:[])])}async function eG(e,t,a){if(a.activity)throw new i("INVALID_ARGS","Activity override is not supported when opening an app-bound deep link URL");let n=a.url?.trim()??"";if(!D(n))throw new i("INVALID_ARGS","Android app-bound open requires a valid URL target");let r=await eq(e,t,"app-bound open");await ef(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",n,"-p",r])}async function ej(e,t,a){if(a)throw new i("INVALID_ARGS","Activity override requires a package name, not an intent");await ef(e,["shell","am","start","-W","-a",t])}async function eK(e,t,a,n){let i=a.includes("/")?a:`${t}/${a.startsWith(".")?a:`.${a}`}`;try{await ef(e,ez(i,n))}catch(a){throw await eX(e,t,a),a}}async function eH(e,t,a){let n=await ef(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eO,"-c",a,"-p",t],{allowFailure:!0});if(0===n.exitCode&&!e0(n.stdout,n.stderr))return;let r=await eY(e,t);if(!r){if(!await eJ(e,t))throw eZ(t);throw new i("COMMAND_FAILED",`Failed to launch ${t}`,{stdout:n.stdout,stderr:n.stderr})}await ef(e,ez(r,a))}function ez(e,t){return["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eO,"-c",t,"-n",e]}async function eq(e,t,a){let n=await eT(e,t);if("intent"===n.type)throw new i("INVALID_ARGS",`Android ${a} requires a package name, not an intent`);return n.value}function eZ(e){return new i("APP_NOT_INSTALLED",`No package found matching "${e}"`,{package:e,hint:eN})}async function eJ(e,t){let a=await ef(e,["shell","pm","path",t],{allowFailure:!0}),n=`${a.stdout}
3
+ ${a.stderr}`;return!!(0===a.exitCode&&/\bpackage:/i.test(n))||(eQ(n),!1)}async function eX(e,t,a){if(eQ(a instanceof i?`${String(a.details?.stdout??"")}
4
+ ${String(a.details?.stderr??"")}`:"")||!await eJ(e,t))throw eZ(t)}function eQ(e){return/\bunknown package\b/i.test(e)||/\bpackage .* (?:was|is) not found\b/i.test(e)||/\bpackage .* does not exist\b/i.test(e)||/\bcould not find package\b/i.test(e)}async function eY(e,t){for(let a of Array.from(new Set(eL(e,{includeFallbackWhenUnknown:!0})))){let n=await ef(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",a,t],{allowFailure:!0});if(0!==n.exitCode)continue;let i=e1(n.stdout);if(i)return i}return null}function e0(e,t){let a=`${e}
5
+ ${t}`;return/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)}function e1(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let a=t[e];if(void 0===a||!a.includes("/"))continue;let n=a.split(/\s+/)[0];if(void 0!==n)return n}return null}async function e2(e){e.booted||await ep(e.id)}async function e9(e,t){if("settings"===t.trim().toLowerCase())return void await ef(e,["shell","am","force-stop","com.android.settings"]);let a=await eT(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","Close requires a package name, not an intent");await ef(e,["shell","am","force-stop",a.value])}async function e4(e,t){let a=await eT(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","App uninstall requires a package name, not an intent");let n=await ef(e,["uninstall",a.value],{allowFailure:!0});if(0!==n.exitCode){let e=`${n.stdout}
6
+ ${n.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new i("COMMAND_FAILED",`adb uninstall failed for ${a.value}`,{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})}return{package:a.value}}let e3=null;async function e8(){let e=`${process.env.PATH??""}::${process.env.AGENT_DEVICE_BUNDLETOOL_JAR??""}`;if(e3?.key===e)return e3.invocation;if(await l("bundletool")){let t={cmd:"bundletool",prefixArgs:[]};return e3={key:e,invocation:t},t}let t=await s(process.env.AGENT_DEVICE_BUNDLETOOL_JAR,"AGENT_DEVICE_BUNDLETOOL_JAR");if(!t)throw new i("TOOL_MISSING","bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR to a bundletool-all.jar path.");let a={cmd:"java",prefixArgs:["-jar",t]};return e3={key:e,invocation:a},a}async function e5(e){let t=await e8();await o(t.cmd,[...t.prefixArgs,...e])}async function e6(n,i){let r=m(n),o="universal";if(r.installBundle)return void await r.installBundle(i,{mode:o});let s=await e.mkdtemp(a.join(t.tmpdir(),"agent-device-aab-")),l=a.join(s,"bundle.apks");try{await e5(["build-apks","--bundle",i,"--output",l,"--mode",o]),await e5(["install-apks","--apks",l,"--device-id",n.id])}finally{await e.rm(s,{recursive:!0,force:!0})}}async function e7(e,t){".aab"===a.extname(t).toLowerCase()?await e6(e,t):await w(t,{device:e,replace:!0})}async function te(e){return new Set((await ef(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean))}async function tt(e,t){let a=Array.from(await te(e)).filter(e=>!t.has(e));if(1===a.length)return a[0]}async function ta(e,t){await eD.invalidateWhile(ek(e),async()=>{e.booted||await ep(e.id),await e7(e,t)})}async function tn(e,t,a){let n=a?void 0:await te(e);return await ta(e,t),a??(n?await tt(e,n):void 0)}async function ti(e,t){e.booted||await ep(e.id);let a=await eb({kind:"path",path:t});try{let t=await tn(e,a.installablePath,a.packageName),n=t?eR(t):void 0;return{archivePath:a.archivePath,installablePath:a.installablePath,packageName:t,appName:n,launchTarget:t}}finally{await a.cleanup()}}async function tr(e,t,a){return await eD.invalidateWhile(ek(e),async()=>{e.booted||await ep(e.id);let{package:n}=await e4(e,t),i=await eb({kind:"path",path:a},{resolveIdentity:!1});try{await ta(e,i.installablePath)}finally{await i.cleanup()}return{package:n}})}async function to(e,t={}){let a=["logcat","-d","-v","time"];void 0!==t.lines&&a.push("-t",String(Math.max(1,Math.floor(t.lines))));let n=await e(a,{allowFailure:!0,timeoutMs:t.timeoutMs,signal:t.signal});if(0!==n.exitCode)throw new i("COMMAND_FAILED","Failed to capture Android logcat",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode});return n.stdout}function ts(e,t={}){if(!e.spawn)throw new i("UNSUPPORTED_OPERATION","Android ADB provider does not support streams",{capability:"adb.spawn"});let a=["logcat","-v","time"];t.pid&&a.push("--pid",t.pid);let n=e.spawn(a,{stdio:["ignore","pipe","pipe"],signal:t.signal});return t.output&&n.stdout&&n.stdout.pipe(t.output,{end:!1}),n}let tl=new Set(["com.google.android.inputmethod.latin","com.samsung.android.honeyboard","com.touchtype.swiftkey","com.microsoft.swiftkey"]);function td(e){let t=tc(e.packageName),a=(e.resourceId??"").toLowerCase(),n=tc(e.activeInputMethodPackage);if(t&&n&&t===n)return{inputMethodOwned:!0,source:"active-input-method"};if(n&&a.startsWith(`${n}:id/`))return{inputMethodOwned:!0,source:"active-input-method-resource"};if(t&&tl.has(t))return{inputMethodOwned:!0,source:"known-ime-package"};for(let e of tl)if(a.startsWith(`${e}:id/`))return{inputMethodOwned:!0,source:"known-ime-resource"};return{inputMethodOwned:!1,source:"app"}}function tu(e){return td(e).inputMethodOwned}function tc(e){return(e??"").trim().toLowerCase()||void 0}let tp=["mInputShown","mIsInputViewShown","isInputViewShown","mDecorViewVisible","mWindowVisible","mInShowWindow"],tf=new Map([[2,"number"],[3,"phone"],[4,"datetime"]]),tm=new Set([32,208]),tw=new Set([128,224,144]);async function th(e){return await tA(h(e))}async function tA(e){var t,a,n;let o,s,l,d,u,c,p,f,m=await e(["shell","dumpsys","input_method"],{allowFailure:!0});if(0!==m.exitCode)throw new i("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:m.stdout,stderr:m.stderr,exitCode:m.exitCode});return s=function(e){var t=function(e,t){let a=new Map,n=RegExp(`\\b(${t.join("|")})=([a-zA-Z]+)\\b`,"g");for(let t of e.matchAll(n)){let e=t[1],n=t[2]?.toLowerCase();e&&("true"===n||"false"===n)&&a.set(e,"true"===n)}return a}(e,tp);if(0===t.size)return null;let a=tv(t,["mWindowVisible","mDecorViewVisible","mInShowWindow"]);if(void 0!==a)return a;let n=t.get("mInputShown");return void 0!==n?n:tv(t,["mIsInputViewShown","isInputViewShown"])??null}(t=m.stdout)??function(e){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/),a=t?.[1];if(!a)return null;let n=Number.parseInt(a,16);return Number.isNaN(n)?null:(1&n)!=0}(t),l=(o=tb(t,/\binputType=0x([0-9a-fA-F]+)\b/gi))?`0x${o.toLowerCase()}`:void 0,d=tb(t,/\bpackageName=([A-Za-z0-9_.]+)\b/g),u=tb(t,/\b(?:resourceId|resource-id)=([^\s,}]+)/g),p=function(e,t,a){return e||t?td({packageName:e,resourceId:t,activeInputMethodPackage:a}).inputMethodOwned?"ime":"app":"unknown"}(d,u,c=function(e){for(let t of[/\bmCurMethodId=([^\s]+)/i,/\bmCurId=([^\s]+)/i,/\bmCurrentInputMethodId=([^\s]+)/i,/\bcurMethodId=([^\s]+)/i]){let a=e.match(t),n=function(e){let t=(e??"").trim();if(!t)return;let a=(t.split("/")[0]??"").match(/[a-zA-Z0-9_.]+/);return tc(a?.[0])}(a?.[1]);if(n)return n}}(t)),a=d,n=u,!c&&((f=tc(a))&&tl.has(f)||function(e){let t=(e??"").toLowerCase();for(let e of tl)if(t.startsWith(`${e}:id/`))return!0;return!1}(n))&&r({level:"warn",phase:"android_input_ownership_fallback",data:{focusedPackage:a,focusedResourceId:n}}),{visible:s??!1,inputType:l,type:l?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let a=15&t,n=tf.get(a);if(n)return n;if(1!==a)return"unknown";let i=4080&t;return tm.has(i)?"email":tw.has(i)?"password":"text"}(l):void 0,inputMethodPackage:c,focusedPackage:d,focusedResourceId:u,inputOwner:p}}async function ty(e){return await tg(h(e))}async function tg(e){let t=await tA(e),a=t,n=0;for(;a.visible&&n<2;)await e(["shell","input","keyevent","111"]),n+=1,await p(120),a=await tA(e);if(t.visible&&a.visible)throw new i("UNSUPPORTED_OPERATION","Android keyboard dismiss is unavailable for the current IME without back navigation.",{attempts:n,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner});return{attempts:n,wasVisible:t.visible,dismissed:t.visible&&!a.visible,visible:a.visible,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner}}function tb(e,t){let a;for(let n of e.matchAll(t))a=n[1];return a}function tv(e,t){for(let a of t){let t=e.get(a);if(void 0!==t)return t}}async function tM(e){return await t_(h(e))}async function t_(e){let t,a;return(a=(t=(await tN(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?a[1]??"":"null"===t.trim().toLowerCase()?"":t}async function tI(e,t){await tO(h(e),t)}async function tO(e,t){await tN(e,["shell","cmd","clipboard","set","text",t],"write")}async function tN(e,t,a){var n,r;let o,s=await e(t,{allowFailure:!0});if(n=s.stdout,r=s.stderr,(o=`${n}
7
+ ${r}`.toLowerCase()).includes("no shell command implementation")||o.includes("unknown command"))throw new i("UNSUPPORTED_OPERATION",`Android shell clipboard ${a} is not supported on this device.`);if(0!==s.exitCode)throw new i("COMMAND_FAILED",`Failed to ${a} Android clipboard text`,{stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode});return s.stdout}export{x as Deadline,em as androidDeviceForSerial,K as bootFailureHint,to as captureAndroidLogcatWithAdb,ey as classifyAndroidAppTarget,j as classifyBootFailure,e9 as closeAndroidApp,E as createAppResolutionCache,ty as dismissAndroidKeyboard,tg as dismissAndroidKeyboardWithAdb,ew as ensureAdb,ec as ensureAndroidEmulatorBooted,eg as formatAndroidInstalledPackageRequiredMessage,eP as getAndroidAppState,eU as getAndroidBlockingDialogFocus,th as getAndroidKeyboardState,tA as getAndroidKeyboardStatusWithAdb,eR as inferAndroidAppName,ti as installAndroidApp,tn as installAndroidInstallablePathAndResolvePackageName,e0 as isAmStartError,tu as isAndroidInputMethodOwnedNode,D as isDeepLinkTarget,L as isEnvTruthy,G as isInfrastructureBootFailureReason,k as isWebUrl,eE as listAndroidApps,er as listAndroidDevices,eW as openAndroidApp,e2 as openAndroidDevice,O as parseAndroidForegroundApp,e1 as parseAndroidLaunchComponent,_ as parseAndroidLaunchablePackages,I as parseAndroidUserInstalledPackages,V as parseSerialAllowlist,eb as prepareAndroidInstallArtifact,tM as readAndroidClipboardText,t_ as readAndroidClipboardWithAdb,tr as reinstallAndroidApp,eT as resolveAndroidApp,W as resolveAndroidSerialAllowlist,T as resolveIosDeviceDeepLinkBundleId,B as resolveIosSimulatorDeviceSetPath,R as retryWithPolicy,ef as runAndroidAdb,ts as streamAndroidLogcatWithAdb,ep as waitForAndroidBoot,P as withRetry,tI as writeAndroidClipboardText,tO as writeAndroidClipboardWithAdb};
package/dist/src/221.js CHANGED
@@ -1,4 +1,6 @@
1
- import e from"node:crypto";import t from"node:fs";import n from"node:fs/promises";import r from"node:os";import i from"node:path";import{AppError as a}from"./9152.js";import{isScrollableType as o}from"./2842.js";import{installAndroidAdbPackage as s}from"./9639.js";let u="android-snapshot-helper",l="com.callstack.agentdevice.snapshothelper",d="com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",c="android-snapshot-helper-v1",h="uiautomator-xml",f={"-r":"replace","-t":"allowTestPackages","-d":"allowDowngrade","-g":"grantPermissions"};async function p(e){let t=await M(e.apkPath);if(t!==e.manifest.sha256)throw new a("COMMAND_FAILED","Android snapshot helper APK checksum mismatch",{apkPath:e.apkPath,expectedSha256:e.manifest.sha256,actualSha256:t})}async function m(e){let t=e.fetch??fetch,o=await t(e.manifestUrl);if(!o.ok)throw new a("COMMAND_FAILED","Failed to download Android snapshot helper manifest",{manifestUrl:e.manifestUrl,status:o.status,statusText:o.statusText});let s=w(JSON.parse((await A(o,65536,"Android snapshot helper manifest")).toString("utf8")));if(!s.apkUrl)throw new a("COMMAND_FAILED","Android snapshot helper manifest does not include apkUrl",{manifestUrl:e.manifestUrl});let u=e.cacheDir??i.join(r.tmpdir(),`agent-device-android-snapshot-helper-${s.version}`),l=!e.cacheDir;await n.mkdir(u,{recursive:!0});let d=s.assetName??`agent-device-android-snapshot-helper-${s.version}.apk`,c=i.join(u,d),h=await t(s.apkUrl);if(!h.ok)throw new a("COMMAND_FAILED","Failed to download Android snapshot helper APK",{apkUrl:s.apkUrl,status:h.status,statusText:h.statusText});await n.writeFile(c,await A(h,0x1400000,"Android snapshot helper APK"));let f={apkPath:c,manifest:s};return await p(f),{...f,cleanup:async()=>{await n.rm(l?u:c,{recursive:l,force:!0})}}}function w(e){var t,n;if(!e||"object"!=typeof e||Array.isArray(e))throw new a("INVALID_ARGS","Android snapshot helper manifest must be an object.");return{name:v(e.name,"name",u),version:N(e.version,"version"),releaseTag:I(e.releaseTag),assetName:I(e.assetName),apkUrl:(t=e.apkUrl,n="apkUrl",null===t?null:N(t,n)),sha256:function(e){let t=N(e,"sha256").trim().toLowerCase();if(64!==t.length||!function(e){for(let t of e){let e=t.charCodeAt(0),n=e>=48&&e<=57,r=e>=97&&e<=102;if(!n&&!r)return!1}return!0}(t))throw new a("INVALID_ARGS","Android snapshot helper manifest sha256 must be a 64-character hex string.");return t}(e.sha256),checksumName:I(e.checksumName),packageName:N(e.packageName,"packageName"),versionCode:x(e.versionCode,"versionCode"),instrumentationRunner:N(e.instrumentationRunner,"instrumentationRunner"),minSdk:x(e.minSdk,"minSdk"),targetSdk:void 0===e.targetSdk?void 0:x(e.targetSdk,"targetSdk"),outputFormat:v(e.outputFormat,"outputFormat",h),statusProtocol:v(e.statusProtocol,"statusProtocol",c),installArgs:g(e.installArgs)}}async function A(e,t,n){let r=e.headers.get("content-length");if(null!==r){let e=Number(r);if(Number.isFinite(e)&&e>t)throw new a("COMMAND_FAILED",`${n} download exceeds size limit`,{contentLength:e,maxBytes:t})}if(!e.body){let r=Buffer.from(await e.arrayBuffer());if(r.length>t)throw new a("COMMAND_FAILED",`${n} download exceeds size limit`,{contentLength:r.length,maxBytes:t});return r}let i=e.body.getReader(),o=[],s=0;try{for(;;){let{done:e,value:r}=await i.read();if(e)break;if((s+=r.byteLength)>t)throw new a("COMMAND_FAILED",`${n} download exceeds size limit`,{contentLength:s,maxBytes:t});o.push(Buffer.from(r))}}finally{i.releaseLock()}return Buffer.concat(o,s)}function g(e){let t=function(e,t){if(!Array.isArray(e)||!e.every(e=>"string"==typeof e))throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be a string array.`);return e}(e,"installArgs");if("install"!==t[0])throw new a("INVALID_ARGS",'Android snapshot helper manifest installArgs must start with "install".');if(t.some(e=>e.includes("\0")))throw new a("INVALID_ARGS","Android snapshot helper manifest installArgs must not contain null bytes.");let n=t.slice(1).find(e=>void 0===D(e));if(n)throw new a("INVALID_ARGS",`Android snapshot helper manifest installArgs contains unsupported install flag "${n}".`);return t}async function M(n){return await new Promise((r,i)=>{let a=e.createHash("sha256"),o=t.createReadStream(n);o.on("error",i),o.on("data",e=>a.update(e)),o.on("end",()=>r(a.digest("hex")))})}function N(e,t){if("string"!=typeof e||0===e.trim().length)throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} is required.`);return e}function I(e){return"string"==typeof e&&e.trim().length>0?e:void 0}function x(e,t){if("number"!=typeof e||!Number.isInteger(e))throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be an integer.`);return e}function v(e,t,n){if(e!==n)throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be "${n}".`);return n}function D(e){if(Object.hasOwn(f,e))return f[e]}function*b(e){let t=/<node\b[^>]*>/g,n=t.exec(e);for(;n;)yield C(n[0]),n=t.exec(e)}function C(e){let t,n,r=(t=function(e){let t=new Map,n=e.indexOf(" "),r=e.lastIndexOf(">");if(n<0||r<=n)return t;let i=n;for(;i<r&&!((i=_(e,i,r))>=r);){var a;let n=e[i];if("/"===n||">"===n)break;let o=i;for(;i<r&&!("="===(a=e[i]??"")||"/"===a||">"===a||y(a));)i+=1;let s=e.slice(o,i);if(i=_(e,i,r),!s||"="!==e[i])break;i=_(e,i+1,r);let u=e[i];if('"'!==u&&"'"!==u)break;let l=i+=1;for(;i<r&&e[i]!==u;)i+=1;if(i>=r)break;t.set(s,function(e){let t="",n=0;for(;n<e.length;){let r=e.indexOf("&",n);if(r<0){t+=e.slice(n);break}t+=e.slice(n,r);let i=e.indexOf(";",r+1);if(i<0){t+=e.slice(r);break}t+=function(e){switch(e){case"amp":return"&";case"lt":return"<";case"gt":return">";case"quot":return'"';case"apos":return"'";default:return function(e){if(!e.startsWith("#"))return;let t=e[1]?.toLowerCase()==="x"?16:10,n=16===t?e.slice(2):e.slice(1);if(!n||!function(e,t){for(let n of e){let e=n.charCodeAt(0),r=e>=48&&e<=57;if(10===t){if(!r)return!1;continue}let i=e>=65&&e<=70,a=e>=97&&e<=102;if(!r&&!i&&!a)return!1}return!0}(n,t))return;let r=Number.parseInt(n,t);if(Number.isFinite(r))try{return String.fromCodePoint(r)}catch{return}}(e)}}(e.slice(r+1,i))??e.slice(r,i+1),n=i+1}return t}(e.slice(l,i))),i+=1}return t}(e),n=e=>{let n=L(t,e);if(null!==n)return"true"===n},{text:L(t,"text"),desc:L(t,"content-desc"),resourceId:L(t,"resource-id"),packageName:L(t,"package"),className:L(t,"class"),bounds:L(t,"bounds"),clickable:n("clickable"),enabled:n("enabled"),focusable:n("focusable"),focused:n("focused"),password:n("password")}),i=function(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let n=Number(t[1]),r=Number(t[2]);return{x:n,y:r,width:Math.max(0,Number(t[3])-n),height:Math.max(0,Number(t[4])-r)}}(r.bounds);return{...r,...i?{rect:i}:{}}}function S(e,t,n){let{sourceNodes:r,...i}=k(F(e),t,n);return i}function k(e,t,n){let r={nodes:[],sourceNodes:[],maxNodes:t,maxDepth:n.depth??1/0,options:n,analysis:function(e){let t=0,n=0,r=[...e.children];for(;r.length>0;){let e=r.pop();t+=1,n=Math.max(n,e.depth),r.push(...e.children)}return{rawNodeCount:t,maxDepth:n}}(e),interactiveDescendantMemo:new Map,truncated:!1},i=n.scope?function(e,t){let n=t.toLowerCase(),r=[...e.children],i=0;for(;i<r.length;){let e=r[i++],t=e.label?.toLowerCase()??"",a=e.value?.toLowerCase()??"",o=e.identifier?.toLowerCase()??"";if(t.includes(n)||a.includes(n)||o.includes(n))return e;r.push(...e.children)}return null}(e,n.scope):null;for(let t of i?[i]:e.children)if(function e(t,n,r,i,a=!1,s=!1){if(t.nodes.length>=t.maxNodes){t.truncated=!0;return}if(r>t.maxDepth)return;let u=t.options.raw||function(e,t,n,r,i){var a,s,u;let l=function(e){let t=T(e.type),n=!!(e.label&&e.label.trim().length>0),r=!!(e.identifier&&e.identifier.trim().length>0);return{type:t,hasMeaningfulText:n&&!O(e.label??""),hasMeaningfulId:r&&!O(e.identifier??""),isStructural:function(e){let t=e.split(".").pop()??e;return t.includes("layout")||"viewgroup"===t||"view"===t}(t),isVisual:"imageview"===t||"imagebutton"===t}}(e);return t.interactiveOnly?function(e,t,n,r,i){var a,s,u,l;return!!(e.hittable||o(t.type)&&r)||(a=t,s=n,u=r,l=i,(!!a.hasMeaningfulText||!!a.hasMeaningfulId)&&!a.isVisual&&(!a.isStructural||!!l)&&(s||u||l))}(e,l,n,r,i):t.compact?l.hasMeaningfulText||l.hasMeaningfulId||!!e.hittable:!l.isStructural&&!l.isVisual||(a=e,s=l,u=r,!!a.hittable||!!s.hasMeaningfulText||!!s.hasMeaningfulId&&!!u||u)}(n,t.options,a,function e(t,n){let r=t.interactiveDescendantMemo.get(n);if(void 0!==r)return r;for(let r of n.children)if(r.hittable||e(t,r))return t.interactiveDescendantMemo.set(n,!0),!0;return t.interactiveDescendantMemo.set(n,!1),!1}(t,n),s)?function(e,t,n,r){let i=e.nodes.length;return e.sourceNodes.push(t),e.nodes.push({index:i,type:t.type??void 0,label:t.label??void 0,value:t.value??void 0,identifier:t.identifier??void 0,bundleId:t.packageName??void 0,rect:t.rect,enabled:t.enabled,hittable:t.hittable,depth:n,parentIndex:r,...t.hiddenContentAbove?{hiddenContentAbove:!0}:{},...t.hiddenContentBelow?{hiddenContentBelow:!0}:{}}),i}(t,n,r,i):i,l=a||!!n.hittable,d=s||function(e){if(!e)return!1;let t=T(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(n.type);for(let i of n.children)if(e(t,i,r+1,u,l,d),t.truncated)return}(r,t,0),r.truncated)break;let a={nodes:r.nodes,sourceNodes:r.sourceNodes,analysis:r.analysis};return r.truncated?{...a,truncated:!0}:a}function _(e,t,n){for(;t<n&&y(e[t]??"");)t+=1;return t}function y(e){return" "===e||"\n"===e||"\r"===e||" "===e}function L(e,t){return e.get(t)??null}function F(e){let t={type:null,label:null,value:null,identifier:null,packageName:null,depth:-1,children:[]},n=[t],r=/<node\b[^>]*>|<\/node>/g,i=r.exec(e);for(;i;){let t=i[0];if(t.startsWith("</node")){n.length>1&&n.pop(),i=r.exec(e);continue}let a=C(t),o=n[n.length-1],s={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,packageName:a.packageName,rect:a.rect,enabled:a.enabled,hittable:a.clickable??a.focusable,depth:o.depth+1,parentIndex:void 0,children:[]};o.children.push(s),t.endsWith("/>")||n.push(s),i=r.exec(e)}return t}function T(e){return e?e.toLowerCase():""}function O(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}async function P(e){var t,n;let r,i,o=(r=E((t=e).timeoutMs,8e3),i=E(t.packageName,l),{waitForIdleTimeoutMs:E(t.waitForIdleTimeoutMs,500),waitForIdleQuietMs:E(t.waitForIdleQuietMs,100),timeoutMs:r,commandTimeoutMs:E(t.commandTimeoutMs,r+5e3),maxDepth:E(t.maxDepth,128),maxNodes:E(t.maxNodes,5e3),packageName:i,runner:E(t.instrumentationRunner,`${i}/.SnapshotInstrumentation`),...t.outputPath?{outputPath:t.outputPath}:{}}),s=await e.adb(["shell","am","instrument","-w","-e","waitForIdleTimeoutMs",String((n=o).waitForIdleTimeoutMs),"-e","waitForIdleQuietMs",String(n.waitForIdleQuietMs),"-e","timeoutMs",String(n.timeoutMs),"-e","maxDepth",String(n.maxDepth),"-e","maxNodes",String(n.maxNodes),...n.outputPath?["-e","outputPath",n.outputPath]:[],n.runner],{allowFailure:!0,timeoutMs:o.commandTimeoutMs}),u=await R(e,o,s);if(o.outputPath&&await H(e.adb,o.outputPath),0!==s.exitCode)throw new a("COMMAND_FAILED","Android snapshot helper failed",{stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode,helper:u.metadata});return u}function E(e,t){return void 0===e?t:e}async function R(e,t,n){try{return V(`${n.stdout}
2
- ${n.stderr}`)}catch(r){return await U(e,t,n,r)}}async function U(e,t,n,r){if(t.outputPath){let n=await $(e.adb,t.outputPath,{waitForIdleTimeoutMs:t.waitForIdleTimeoutMs,waitForIdleQuietMs:t.waitForIdleQuietMs,timeoutMs:t.timeoutMs,maxDepth:t.maxDepth,maxNodes:t.maxNodes});if(n)return n}if(r instanceof a&&0!==n.exitCode&&r.details?.helper)throw r;throw new a("COMMAND_FAILED",0===n.exitCode?"Android snapshot helper output could not be parsed":"Android snapshot helper failed before returning parseable output",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode},r)}async function $(e,t,n){let r=await e(["shell","cat",t],{allowFailure:!0,timeoutMs:5e3});if(await H(e,t),0!==r.exitCode)return;let i=r.stdout.trim();if(i.includes("<hierarchy")&&i.includes("</hierarchy>"))return{xml:i,metadata:{...n,outputFormat:h}}}async function H(e,t){await e(["shell","rm","-f",t],{allowFailure:!0,timeoutMs:5e3})}function V(e){var t,n;let r=function(e){var t;let n={status:[],results:[],currentStatus:null,currentResult:null};for(let t of e.split(/\r?\n/))!function(e,t){if(e.startsWith("INSTRUMENTATION_STATUS: ")){t.currentStatus??={},W(e.slice(24),t.currentStatus);return}if(e.startsWith("INSTRUMENTATION_STATUS_CODE: "))return K(t);if(e.startsWith("INSTRUMENTATION_RESULT: ")){t.currentResult??={},W(e.slice(24),t.currentResult);return}e.startsWith("INSTRUMENTATION_CODE: ")&&G(t)}(t,n);return K(t=n),G(t),{status:n.status,results:n.results}}(e),i=function(e){let t=e.find(e=>e.agentDeviceProtocol===c);if(!t)throw new a("COMMAND_FAILED","Android snapshot helper did not return a final result");if("true"!==t.ok){var n;throw new a("COMMAND_FAILED",(n=t).message&&"null"!==n.message?n.message:n.errorType||"Android snapshot helper returned an error",{errorType:t.errorType,helper:t})}return t}(r.results);return{xml:function(e,t){if(0===e.length)throw new a("COMMAND_FAILED","Android snapshot helper did not return XML chunks",{helper:t});let n=function(e){let t=e[0]?.count??e.length;if(t<1||e.length!==t||e.some(e=>e.count!==t))throw new a("COMMAND_FAILED","Android snapshot helper returned incomplete XML chunks",{expectedChunks:t,actualChunks:e.length});return t}(e),r=Buffer.concat(function(e,t){let n=[];for(let r=0;r<t;r+=1){let i=e.get(r);if(void 0===i)throw new a("COMMAND_FAILED","Android snapshot helper returned incomplete XML chunks",{missingChunkIndex:r,expectedChunks:t});n.push(Buffer.from(i,"base64"))}return n}(function(e,t){let n=new Map;for(let r of e){if(void 0===r.index||r.index<0||r.index>=t)throw new a("COMMAND_FAILED","Android snapshot helper returned invalid chunk index",{chunkIndex:r.index,expectedChunks:t});if(n.has(r.index))throw new a("COMMAND_FAILED","Android snapshot helper returned duplicate XML chunks",{chunkIndex:r.index});n.set(r.index,r.payloadBase64)}return n}(e,n),n)).toString("utf8");if(!r.includes("<hierarchy")||!r.includes("</hierarchy>"))throw new a("COMMAND_FAILED","Android snapshot helper output did not contain XML",{xml:r});return r}(function(e){let t=[];for(let n of e){if(n.agentDeviceProtocol!==c||n.outputFormat!==h)continue;let{payloadBase64:e}=n;void 0!==e&&t.push({index:Q(n.chunkIndex),count:Q(n.chunkCount),payloadBase64:e})}return t}(r.status),i),metadata:{helperApiVersion:(t=i).helperApiVersion,outputFormat:h,waitForIdleTimeoutMs:Q(t.waitForIdleTimeoutMs),waitForIdleQuietMs:Q(t.waitForIdleQuietMs),timeoutMs:Q(t.timeoutMs),maxDepth:Q(t.maxDepth),maxNodes:Q(t.maxNodes),rootPresent:j(t.rootPresent),captureMode:"interactive-windows"===(n=t.captureMode)||"active-window"===n?n:void 0,windowCount:Q(t.windowCount),nodeCount:Q(t.nodeCount),truncated:j(t.truncated),elapsedMs:Q(t.elapsedMs)}}}function B(e,t={outputFormat:h},n={},r=800){return{...S(e,r,n),metadata:t}}function K(e){e.currentStatus&&(e.status.push(e.currentStatus),e.currentStatus=null)}function G(e){e.currentResult&&(e.results.push(e.currentResult),e.currentResult=null)}function W(e,t){let n=e.indexOf("=");n<0||(t[e.slice(0,n)]=e.slice(n+1))}function Q(e){if(void 0===e)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function j(e){return"true"===e||"false"!==e&&void 0}let X=new Map;function z(e){J(q(e.deviceKey,e.packageName,e.versionCode))}function q(e,t,n){return e?`${e}\0${t}\0${n}`:void 0}function J(e){e&&X.delete(e)}async function Y(e){var t,n,r;let{adb:i,artifact:o}=e,s=e.installPolicy??"missing-or-outdated",u=o.manifest.packageName,l=o.manifest.versionCode;if("never"===s)return{packageName:u,versionCode:l,installed:!1,reason:"skipped"};let d=q(e.deviceKey,u,l),c=d?X.get(d):void 0;if(d&&"always"!==s&&void 0!==c)return{packageName:u,versionCode:l,installedVersionCode:c,installed:!1,reason:"current"};let h=await Z(i,u,e.timeoutMs),f=(t=s,n=h,r=l,"never"===t?"skipped":"always"===t?"forced":void 0===n?"missing":n<r?"outdated":"current");if("current"===f){if(void 0===h)throw Error("Expected installed versionCode for current Android snapshot helper");return d&&X.set(d,h),{packageName:u,versionCode:l,installedVersionCode:h,installed:!1,reason:f}}await p(o);let m=await ee(i,e.adbProvider??i,o.apkPath,function(e){let t={};for(let n of e.slice(1)){let e=D(n);if(!e)throw new a("INVALID_ARGS",`Android snapshot helper manifest installArgs contains unsupported install flag "${n}".`);t[e]=!0}return t}(g(o.manifest.installArgs)),{packageName:u,timeoutMs:e.timeoutMs});if(0!==m.exitCode)throw J(d),new a("COMMAND_FAILED","Failed to install Android snapshot helper",{packageName:u,versionCode:l,stdout:m.stdout,stderr:m.stderr,exitCode:m.exitCode});return d&&X.set(d,l),{packageName:u,versionCode:l,installedVersionCode:h,installed:!0,reason:f}}async function Z(e,t,n){let r=await e(["shell","cmd","package","list","packages","--show-versioncode",t],{allowFailure:!0,timeoutMs:n});if(0===r.exitCode){var i=`${r.stdout}
3
- ${r.stderr}`,a=t;let e=`package:${a}`;for(let t of i.split(/\r?\n/)){if(!t.startsWith(e)||t.length>e.length&&!/\s/.test(t[e.length]??""))continue;let n=/(?:^|\s)versionCode:(\d+)(?:\s|$)/.exec(t);if(n)return Number(n[1])}return}}async function ee(e,t,n,r,i){var a;let o=async()=>await s(n,{allowFailure:!0,provider:t,...r,timeoutMs:i.timeoutMs}),u=await o();if(0===u.exitCode||(a=u,!`${a.stdout}
4
- ${a.stderr}`.includes("INSTALL_FAILED_UPDATE_INCOMPATIBLE")))return u;let l=await e(["uninstall",i.packageName],{allowFailure:!0,timeoutMs:i.timeoutMs}),d=await o();return 0===d.exitCode?d:{...d,stderr:[d.stderr,l.stderr?`Previous uninstall stderr after INSTALL_FAILED_UPDATE_INCOMPATIBLE: ${l.stderr}`:""].filter(Boolean).join("\n")}}export{u as ANDROID_SNAPSHOT_HELPER_NAME,h as ANDROID_SNAPSHOT_HELPER_OUTPUT_FORMAT,l as ANDROID_SNAPSHOT_HELPER_PACKAGE,c as ANDROID_SNAPSHOT_HELPER_PROTOCOL,d as ANDROID_SNAPSHOT_HELPER_RUNNER,b as androidUiNodes,k as buildUiHierarchySnapshot,P as captureAndroidSnapshotWithHelper,Y as ensureAndroidSnapshotHelper,z as forgetAndroidSnapshotHelperInstall,w as parseAndroidSnapshotHelperManifest,V as parseAndroidSnapshotHelperOutput,B as parseAndroidSnapshotHelperXml,S as parseUiHierarchy,F as parseUiHierarchyTree,m as prepareAndroidSnapshotHelperArtifactFromManifestUrl,p as verifyAndroidSnapshotHelperArtifact};
1
+ import e from"node:crypto";import t from"node:fs";import r from"node:fs/promises";import n from"node:os";import o from"node:path";import i from"node:net";import{AppError as a}from"./9152.js";import{isScrollableType as s}from"./2842.js";import{emitDiagnostic as u}from"./7599.js";import{installAndroidAdbPackage as l}from"./9639.js";let d="android-snapshot-helper",c="com.callstack.agentdevice.snapshothelper",h="com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",p="android-snapshot-helper-v1",f="uiautomator-xml",m={"-r":"replace","-t":"allowTestPackages","-d":"allowDowngrade","-g":"grantPermissions"};async function w(e){let t=await v(e.apkPath);if(t!==e.manifest.sha256)throw new a("COMMAND_FAILED","Android snapshot helper APK checksum mismatch",{apkPath:e.apkPath,expectedSha256:e.manifest.sha256,actualSha256:t})}async function A(e){let t=e.fetch??fetch,i=await t(e.manifestUrl);if(!i.ok)throw new a("COMMAND_FAILED","Failed to download Android snapshot helper manifest",{manifestUrl:e.manifestUrl,status:i.status,statusText:i.statusText});let s=M(JSON.parse((await g(i,65536,"Android snapshot helper manifest")).toString("utf8")));if(!s.apkUrl)throw new a("COMMAND_FAILED","Android snapshot helper manifest does not include apkUrl",{manifestUrl:e.manifestUrl});let u=e.cacheDir??o.join(n.tmpdir(),`agent-device-android-snapshot-helper-${s.version}`),l=!e.cacheDir;await r.mkdir(u,{recursive:!0});let d=s.assetName??`agent-device-android-snapshot-helper-${s.version}.apk`,c=o.join(u,d),h=await t(s.apkUrl);if(!h.ok)throw new a("COMMAND_FAILED","Failed to download Android snapshot helper APK",{apkUrl:s.apkUrl,status:h.status,statusText:h.statusText});await r.writeFile(c,await g(h,0x1400000,"Android snapshot helper APK"));let p={apkPath:c,manifest:s};return await w(p),{...p,cleanup:async()=>{await r.rm(l?u:c,{recursive:l,force:!0})}}}function M(e){var t,r;if(!e||"object"!=typeof e||Array.isArray(e))throw new a("INVALID_ARGS","Android snapshot helper manifest must be an object.");return{name:C(e.name,"name",d),version:I(e.version,"version"),releaseTag:D(e.releaseTag),assetName:D(e.assetName),apkUrl:(t=e.apkUrl,r="apkUrl",null===t?null:I(t,r)),sha256:function(e){let t=I(e,"sha256").trim().toLowerCase();if(64!==t.length||!function(e){for(let t of e){let e=t.charCodeAt(0),r=e>=48&&e<=57,n=e>=97&&e<=102;if(!r&&!n)return!1}return!0}(t))throw new a("INVALID_ARGS","Android snapshot helper manifest sha256 must be a 64-character hex string.");return t}(e.sha256),checksumName:D(e.checksumName),packageName:I(e.packageName,"packageName"),versionCode:x(e.versionCode,"versionCode"),instrumentationRunner:I(e.instrumentationRunner,"instrumentationRunner"),minSdk:x(e.minSdk,"minSdk"),targetSdk:void 0===e.targetSdk?void 0:x(e.targetSdk,"targetSdk"),outputFormat:C(e.outputFormat,"outputFormat",f),statusProtocol:C(e.statusProtocol,"statusProtocol",p),installArgs:N(e.installArgs)}}async function g(e,t,r){let n=e.headers.get("content-length");if(null!==n){let e=Number(n);if(Number.isFinite(e)&&e>t)throw new a("COMMAND_FAILED",`${r} download exceeds size limit`,{contentLength:e,maxBytes:t})}if(!e.body){let n=Buffer.from(await e.arrayBuffer());if(n.length>t)throw new a("COMMAND_FAILED",`${r} download exceeds size limit`,{contentLength:n.length,maxBytes:t});return n}let o=e.body.getReader(),i=[],s=0;try{for(;;){let{done:e,value:n}=await o.read();if(e)break;if((s+=n.byteLength)>t)throw new a("COMMAND_FAILED",`${r} download exceeds size limit`,{contentLength:s,maxBytes:t});i.push(Buffer.from(n))}}finally{o.releaseLock()}return Buffer.concat(i,s)}function N(e){let t=function(e,t){if(!Array.isArray(e)||!e.every(e=>"string"==typeof e))throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be a string array.`);return e}(e,"installArgs");if("install"!==t[0])throw new a("INVALID_ARGS",'Android snapshot helper manifest installArgs must start with "install".');if(t.some(e=>e.includes("\0")))throw new a("INVALID_ARGS","Android snapshot helper manifest installArgs must not contain null bytes.");let r=t.slice(1).find(e=>void 0===y(e));if(r)throw new a("INVALID_ARGS",`Android snapshot helper manifest installArgs contains unsupported install flag "${r}".`);return t}async function v(r){return await new Promise((n,o)=>{let i=e.createHash("sha256"),a=t.createReadStream(r);a.on("error",o),a.on("data",e=>i.update(e)),a.on("end",()=>n(i.digest("hex")))})}function I(e,t){if("string"!=typeof e||0===e.trim().length)throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} is required.`);return e}function D(e){return"string"==typeof e&&e.trim().length>0?e:void 0}function x(e,t){if("number"!=typeof e||!Number.isInteger(e))throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be an integer.`);return e}function C(e,t,r){if(e!==r)throw new a("INVALID_ARGS",`Android snapshot helper manifest ${t} must be "${r}".`);return r}function y(e){if(Object.hasOwn(m,e))return m[e]}function*S(e){let t=/<node\b[^>]*>/g,r=t.exec(e);for(;r;)yield _(r[0]),r=t.exec(e)}function _(e){let t,r,n,o=(t=function(e){let t=new Map,r=e.indexOf(" "),n=e.lastIndexOf(">");if(r<0||n<=r)return t;let o=r;for(;o<n&&!((o=F(e,o,n))>=n);){var i;let r=e[o];if("/"===r||">"===r)break;let a=o;for(;o<n&&!("="===(i=e[o]??"")||"/"===i||">"===i||L(i));)o+=1;let s=e.slice(a,o);if(o=F(e,o,n),!s||"="!==e[o])break;o=F(e,o+1,n);let u=e[o];if('"'!==u&&"'"!==u)break;let l=o+=1;for(;o<n&&e[o]!==u;)o+=1;if(o>=n)break;t.set(s,function(e){let t="",r=0;for(;r<e.length;){let n=e.indexOf("&",r);if(n<0){t+=e.slice(r);break}t+=e.slice(r,n);let o=e.indexOf(";",n+1);if(o<0){t+=e.slice(n);break}t+=function(e){switch(e){case"amp":return"&";case"lt":return"<";case"gt":return">";case"quot":return'"';case"apos":return"'";default:return function(e){if(!e.startsWith("#"))return;let t=e[1]?.toLowerCase()==="x"?16:10,r=16===t?e.slice(2):e.slice(1);if(!r||!function(e,t){for(let r of e){let e=r.charCodeAt(0),n=e>=48&&e<=57;if(10===t){if(!n)return!1;continue}let o=e>=65&&e<=70,i=e>=97&&e<=102;if(!n&&!o&&!i)return!1}return!0}(r,t))return;let n=Number.parseInt(r,t);if(Number.isFinite(n))try{return String.fromCodePoint(n)}catch{return}}(e)}}(e.slice(n+1,o))??e.slice(n,o+1),r=o+1}return t}(e.slice(l,o))),o+=1}return t}(e),r=e=>{let r=T(t,e);if(null!==r)return"true"===r},n=(e,t)=>{let n=r(t);return void 0===n?{}:{[e]:n}},{text:T(t,"text"),desc:T(t,"content-desc"),resourceId:T(t,"resource-id"),packageName:T(t,"package"),className:T(t,"class"),bounds:T(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused"),password:r("password"),...n("scrollable","scrollable"),...n("canScrollForward","can-scroll-forward"),...n("canScrollBackward","can-scroll-backward")}),i=function(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let r=Number(t[1]),n=Number(t[2]);return{x:r,y:n,width:Math.max(0,Number(t[3])-r),height:Math.max(0,Number(t[4])-n)}}(o.bounds);return{...o,...i?{rect:i}:{}}}function b(e,t,r){let{sourceNodes:n,...o}=k(E(e),t,r);return o}function k(e,t,r){let n={nodes:[],sourceNodes:[],maxNodes:t,maxDepth:r.depth??1/0,options:r,analysis:function(e){let t=0,r=0,n=[...e.children];for(;n.length>0;){let e=n.pop();t+=1,r=Math.max(r,e.depth),n.push(...e.children)}return{rawNodeCount:t,maxDepth:r}}(e),interactiveDescendantMemo:new Map,truncated:!1},o=r.scope?function(e,t){let r=t.toLowerCase(),n=[...e.children],o=0;for(;o<n.length;){let e=n[o++],t=e.label?.toLowerCase()??"",i=e.value?.toLowerCase()??"",a=e.identifier?.toLowerCase()??"";if(t.includes(r)||i.includes(r)||a.includes(r))return e;n.push(...e.children)}return null}(e,r.scope):null;for(let t of o?[o]:e.children)if(function e(t,r,n,o,i=!1,a=!1){if(t.nodes.length>=t.maxNodes){t.truncated=!0;return}if(n>t.maxDepth)return;let u=t.options.raw||function(e,t,r,n,o){var i,a,u;let l=function(e){let t=O(e.type),r=!!(e.label&&e.label.trim().length>0),n=!!(e.identifier&&e.identifier.trim().length>0);return{type:t,hasMeaningfulText:r&&!P(e.label??""),hasMeaningfulId:n&&!P(e.identifier??""),isStructural:function(e){let t=e.split(".").pop()??e;return t.includes("layout")||"viewgroup"===t||"view"===t}(t),isVisual:"imageview"===t||"imagebutton"===t}}(e);return t.interactiveOnly?function(e,t,r,n,o){var i,a,u,l,d;return!((i=e).rect&&(i.rect.width<=0||i.rect.height<=0))&&(!!(e.hittable||s(t.type)&&n)||(a=t,u=r,l=n,d=o,(!!a.hasMeaningfulText||!!a.hasMeaningfulId)&&!a.isVisual&&(!a.isStructural||!!d)&&(u||l||d)))}(e,l,r,n,o):t.compact?l.hasMeaningfulText||l.hasMeaningfulId||!!e.hittable:!l.isStructural&&!l.isVisual||(i=e,a=l,u=n,!!i.hittable||!!a.hasMeaningfulText||!!a.hasMeaningfulId&&!!u||u)}(r,t.options,i,function e(t,r){let n=t.interactiveDescendantMemo.get(r);if(void 0!==n)return n;for(let n of r.children)if(n.hittable||e(t,n))return t.interactiveDescendantMemo.set(r,!0),!0;return t.interactiveDescendantMemo.set(r,!1),!1}(t,r),a)?function(e,t,r,n){let o=e.nodes.length;return e.sourceNodes.push(t),e.nodes.push({index:o,type:t.type??void 0,label:t.label??void 0,value:t.value??void 0,identifier:t.identifier??void 0,bundleId:t.packageName??void 0,rect:t.rect,enabled:t.enabled,hittable:t.hittable,depth:r,parentIndex:n,...t.hiddenContentAbove?{hiddenContentAbove:!0}:{},...t.hiddenContentBelow?{hiddenContentBelow:!0}:{}}),o}(t,r,n,o):o,l=i||!!r.hittable,d=a||function(e){if(!e)return!1;let t=O(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(r.type);for(let o of r.children)if(e(t,o,n+1,u,l,d),t.truncated)return}(n,t,0),n.truncated)break;let i={nodes:n.nodes,sourceNodes:n.sourceNodes,analysis:n.analysis};return n.truncated?{...i,truncated:!0}:i}function F(e,t,r){for(;t<r&&L(e[t]??"");)t+=1;return t}function L(e){return" "===e||"\n"===e||"\r"===e||" "===e}function T(e,t){return e.get(t)??null}function E(e){let t={type:null,label:null,value:null,identifier:null,packageName:null,depth:-1,children:[]},r=[t],n=/<node\b[^>]*>|<\/node>/g,o=n.exec(e);for(;o;){let t=o[0];if(t.startsWith("</node")){r.length>1&&r.pop(),o=n.exec(e);continue}let i=_(t),a=r[r.length-1],s={type:i.className,label:i.text||i.desc,value:i.text,identifier:i.resourceId,packageName:i.packageName,rect:i.rect,enabled:i.enabled,hittable:i.clickable??i.focusable,scrollable:i.scrollable,canScrollForward:i.canScrollForward,canScrollBackward:i.canScrollBackward,depth:a.depth+1,parentIndex:void 0,children:[]};a.children.push(s),t.endsWith("/>")||r.push(s),o=n.exec(e)}return function(e){let t=[...e.children];for(;t.length>0;){let e=t.pop();t.push(...e.children),function(e){if(!e.scrollable||!s(e.type)||`${e.type??""}`.toLowerCase().includes("horizontalscrollview"))return!1;let t=function(e){if(!e.rect||0===e.children.length)return null;let t=e.children.map(e=>e.rect).filter(e=>void 0!==e);if(0===t.length)return null;let r=Math.min(...t.map(e=>e.x)),n=Math.max(...t.map(e=>e.x+e.width)),o=Math.min(...t.map(e=>e.y)),i=Math.max(...t.map(e=>e.y+e.height));return{horizontal:Math.max(0,n-r-e.rect.width),vertical:Math.max(0,i-o-e.rect.height)}}(e);return!t||!(t.horizontal>t.vertical)||!(t.horizontal>16)}(e)&&(e.canScrollBackward&&(e.hiddenContentAbove=!0),e.canScrollForward&&(e.hiddenContentBelow=!0))}}(t),t}function O(e){return e?e.toLowerCase():""}function P(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}async function R(e){let t=$(e),r=await e.adb(H(t),{allowFailure:!0,timeoutMs:t.commandTimeoutMs}),{output:n,cleanupDone:o}=await V(e,t,r);if(t.outputPath&&!o&&await Q(e.adb,t.outputPath),0!==r.exitCode)throw new a("COMMAND_FAILED","Android snapshot helper failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,helper:n.metadata});return n}function $(e){let t=U(e.timeoutMs,8e3),r=U(e.packageName,c);return{waitForIdleTimeoutMs:U(e.waitForIdleTimeoutMs,25),waitForIdleQuietMs:U(e.waitForIdleQuietMs,25),timeoutMs:t,commandTimeoutMs:U(e.commandTimeoutMs,t+5e3),maxDepth:U(e.maxDepth,128),maxNodes:U(e.maxNodes,5e3),packageName:r,runner:U(e.instrumentationRunner,`${r}/.SnapshotInstrumentation`),...e.outputPath?{outputPath:e.outputPath}:{},...void 0!==e.emitChunks?{emitChunks:e.emitChunks}:{}}}function U(e,t){return void 0===e?t:e}function H(e){return["shell","am","instrument","-w","-e","waitForIdleTimeoutMs",String(e.waitForIdleTimeoutMs),"-e","waitForIdleQuietMs",String(e.waitForIdleQuietMs),"-e","timeoutMs",String(e.timeoutMs),"-e","maxDepth",String(e.maxDepth),"-e","maxNodes",String(e.maxNodes),...e.outputPath?["-e","outputPath",e.outputPath]:[],...void 0!==e.emitChunks?["-e","emitChunks",String(e.emitChunks)]:[],e.runner]}async function V(e,t,r){try{return{output:W(`${r.stdout}
2
+ ${r.stderr}`),cleanupDone:!1}}catch(n){return await B(e,t,r,n)}}async function B(e,t,r,n){if(n instanceof a&&0!==r.exitCode&&n.details?.helper)throw n;let o=await K(e,t,r);if(o)return{output:o,cleanupDone:!0};throw new a("COMMAND_FAILED",0===r.exitCode?"Android snapshot helper output could not be parsed":"Android snapshot helper failed before returning parseable output",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode},n)}async function K(e,t,r){if(0===r.exitCode&&t.outputPath){var n;return await G(e.adb,t.outputPath,function(e){try{let t=q(e);return j(z(t.results))}catch{return null}}(`${r.stdout}
3
+ ${r.stderr}`)??{outputFormat:f,waitForIdleTimeoutMs:(n=t).waitForIdleTimeoutMs,waitForIdleQuietMs:n.waitForIdleQuietMs,timeoutMs:n.timeoutMs,maxDepth:n.maxDepth,maxNodes:n.maxNodes,transport:"instrumentation"})}}async function G(e,t,r){let n;try{var o;n=await e((o=t,["shell","sh","-c",'cat "$1"; status=$?; rm -f "$1"; exit "$status"',"agent-device-snapshot-helper-output",o]),{allowFailure:!0,timeoutMs:5e3})}catch{return}if(0!==n.exitCode)return;let i=n.stdout.trim();if(i.includes("<hierarchy")&&i.includes("</hierarchy>"))return{xml:i,metadata:r}}async function Q(e,t){try{await e(["shell","rm","-f",t],{allowFailure:!0,timeoutMs:5e3})}catch{}}function W(e){let t=q(e),r=z(t.results);return{xml:function(e,t){if(0===e.length)throw new a("COMMAND_FAILED","Android snapshot helper did not return XML chunks",{helper:t});let r=function(e){let t=e[0]?.count??e.length;if(t<1||e.length!==t||e.some(e=>e.count!==t))throw new a("COMMAND_FAILED","Android snapshot helper returned incomplete XML chunks",{expectedChunks:t,actualChunks:e.length});return t}(e),n=Buffer.concat(function(e,t){let r=[];for(let n=0;n<t;n+=1){let o=e.get(n);if(void 0===o)throw new a("COMMAND_FAILED","Android snapshot helper returned incomplete XML chunks",{missingChunkIndex:n,expectedChunks:t});r.push(Buffer.from(o,"base64"))}return r}(function(e,t){let r=new Map;for(let n of e){if(void 0===n.index||n.index<0||n.index>=t)throw new a("COMMAND_FAILED","Android snapshot helper returned invalid chunk index",{chunkIndex:n.index,expectedChunks:t});if(r.has(n.index))throw new a("COMMAND_FAILED","Android snapshot helper returned duplicate XML chunks",{chunkIndex:n.index});r.set(n.index,n.payloadBase64)}return r}(e,r),r)).toString("utf8");if(!n.includes("<hierarchy")||!n.includes("</hierarchy>"))throw new a("COMMAND_FAILED","Android snapshot helper output did not contain XML",{xml:n});return n}(function(e){let t=[];for(let r of e){if(r.agentDeviceProtocol!==p||r.outputFormat!==f)continue;let{payloadBase64:e}=r;void 0!==e&&t.push({index:er(r.chunkIndex),count:er(r.chunkCount),payloadBase64:e})}return t}(t.status),r),metadata:{...j(r),transport:"instrumentation"}}}function X(e,t={outputFormat:f},r={},n=800){return{...b(e,n,r),metadata:t}}function z(e){let t=e.find(e=>e.agentDeviceProtocol===p);if(!t)throw new a("COMMAND_FAILED","Android snapshot helper did not return a final result");if("true"!==t.ok){var r;throw new a("COMMAND_FAILED",(r=t).message&&"null"!==r.message?r.message:r.errorType||"Android snapshot helper returned an error",{errorType:t.errorType,helper:t})}return t}function j(e){var t;return{helperApiVersion:e.helperApiVersion,outputFormat:f,waitForIdleTimeoutMs:er(e.waitForIdleTimeoutMs),waitForIdleQuietMs:er(e.waitForIdleQuietMs),timeoutMs:er(e.timeoutMs),maxDepth:er(e.maxDepth),maxNodes:er(e.maxNodes),rootPresent:en(e.rootPresent),captureMode:"interactive-windows"===(t=e.captureMode)||"active-window"===t?t:void 0,windowCount:er(e.windowCount),nodeCount:er(e.nodeCount),truncated:en(e.truncated),elapsedMs:er(e.elapsedMs)}}function q(e){var t;let r={status:[],results:[],currentStatus:null,currentResult:null};for(let t of e.split(/\r?\n/))!function(e,t){if(e.startsWith("INSTRUMENTATION_STATUS: ")){t.currentStatus??={},Z(e.slice(24),t.currentStatus);return}if(e.startsWith("INSTRUMENTATION_STATUS_CODE: "))return J(t);if(e.startsWith("INSTRUMENTATION_RESULT: ")){t.currentResult??={},Z(e.slice(24),t.currentResult);return}e.startsWith("INSTRUMENTATION_CODE: ")&&Y(t)}(t,r);return J(t=r),Y(t),{status:r.status,results:r.results}}function J(e){e.currentStatus&&(e.status.push(e.currentStatus),e.currentStatus=null)}function Y(e){e.currentResult&&(e.results.push(e.currentResult),e.currentResult=null)}function Z(e,t){let r=e.indexOf("=");r<0||(t[e.slice(0,r)]=e.slice(r+1))}function ee(e){if(void 0===e)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function et(e){return"true"===e||"false"!==e&&void 0}let er=ee,en=et,eo=new Map;async function ei(e){var t,r,n;let o;if(!(void 0===(o=process.env.AGENT_DEVICE_ANDROID_SNAPSHOT_HELPER_SESSION)||!/^(0|false|no|off)$/i.test(o))||!e.adbProvider?.spawn)return;let i=$(e),a=e.deviceKey??"android:default",s=(t=a,r=i,n=e,JSON.stringify({deviceKey:t,packageName:r.packageName,runner:r.runner,helperVersion:n.helperVersion,helperVersionCode:n.helperVersionCode,waitForIdleTimeoutMs:r.waitForIdleTimeoutMs,waitForIdleQuietMs:r.waitForIdleQuietMs,timeoutMs:r.timeoutMs,maxDepth:r.maxDepth,maxNodes:r.maxNodes})),u=eo.get(a);u&&u.identity!==s&&(await ea(a),u=void 0),u||(u=await es({deviceKey:a,identity:s,options:e,resolved:i}));try{let e=u.capturedCount>0,t=await eu(u,i);return u.capturedCount+=1,{xml:t.xml,metadata:{...t.metadata,transport:"persistent-session",sessionReused:e}}}catch(e){throw await ea(a),e}}async function ea(e){let t=eo.get(e);if(t){eo.delete(e);try{await el(t,`quit ${Date.now()}`,1e3)}catch{}try{await t.process.kill("SIGTERM")}catch{}try{await ed(t)}catch{}u({phase:"android_snapshot_helper_session_stop",data:{deviceKey:e,port:t.port,capturedCount:t.capturedCount,lifetimeMs:Date.now()-t.startedAtMs}})}}async function es(e){let t=await new Promise((e,t)=>{let r=i.createServer();r.unref(),r.on("error",t),r.listen(0,"127.0.0.1",()=>{let n=r.address();if(!n||"string"==typeof n)return void r.close(()=>t(Error("Failed to allocate a local TCP port")));let o=n.port;r.close(()=>e(o))})});await e.options.adb(["forward",`tcp:${t}`,`tcp:${t}`],{allowFailure:!1,timeoutMs:5e3});let r=H({...e.resolved,outputPath:void 0,emitChunks:!1}),n=r[r.length-1];if(!n)throw new a("INVALID_ARGS","Android snapshot helper runner was not resolved");let o=[...r.slice(0,-1),"-e","sessionPort",String(t),n],s=e.options.adbProvider.spawn(o,{allowFailure:!0,captureOutput:!1}),l={identity:e.identity,deviceKey:e.deviceKey,port:t,adb:e.options.adb,process:s,startedAtMs:Date.now(),capturedCount:0};try{var d;return await (d=s,new Promise((e,t)=>{let r="",n=setTimeout(()=>{t(new a("COMMAND_FAILED","Android snapshot helper session did not become ready",{output:r,timeoutMs:1e4}))},1e4),o=t=>{(r+=t.toString()).includes(`agentDeviceProtocol=${p}`)&&r.includes("sessionReady=true")&&(clearTimeout(n),e())};d.stdout?.on("data",o),d.stderr?.on("data",o),d.once("exit",(e,o)=>{clearTimeout(n),t(new a("COMMAND_FAILED","Android snapshot helper session exited before ready",{output:r,exitCode:e,signal:o}))}),d.on("error",e=>{clearTimeout(n),t(e)})})),eo.set(e.deviceKey,l),u({phase:"android_snapshot_helper_session_ready",data:{deviceKey:e.deviceKey,port:t,packageName:e.resolved.packageName,runner:e.resolved.runner}}),l}catch(e){await ed(l);try{s.kill("SIGTERM")}catch{}throw e}}async function eu(e,t){let r=`snapshot-${Date.now()}-${Math.random().toString(16).slice(2)}`,n=Math.max(t.timeoutMs+2e3,3e3);return function(e,t){var r;let{headers:n,xml:o}=function(e){let t=e.indexOf("\n\n");if(t<0)throw new a("COMMAND_FAILED","Android snapshot helper session returned malformed output",{response:e});return{headers:function(e){let t={};for(let r of e.split(/\r?\n/)){let e=r.indexOf("=");e<0||(t[r.slice(0,e)]=r.slice(e+1))}return t}(e.slice(0,t)),xml:e.slice(t+2)}}(e);return function(e,t){if(e.agentDeviceProtocol!==p)throw new a("COMMAND_FAILED","Android snapshot helper session returned wrong protocol",{headers:e});if(e.outputFormat!==f)throw new a("COMMAND_FAILED","Android snapshot helper session returned wrong output format",{headers:e});if(e.requestId!==t)throw new a("COMMAND_FAILED","Android snapshot helper session returned stale output",{headers:e,requestId:t});if("true"!==e.ok)throw new a("COMMAND_FAILED",e.message||e.errorType||"Android snapshot helper session returned an error",{helper:e})}(n,t),function(e,t){let r=ee(e.byteLength);if(void 0!==r&&Buffer.byteLength(t,"utf8")!==r)throw new a("COMMAND_FAILED","Android snapshot helper session returned truncated XML",{headers:e,actualByteLength:Buffer.byteLength(t,"utf8")});if(!t.includes("<hierarchy")||!t.includes("</hierarchy>"))throw new a("COMMAND_FAILED","Android snapshot helper session did not return XML",{headers:e,xml:t})}(n,o),{xml:o,metadata:{helperApiVersion:(r=n).helperApiVersion,outputFormat:f,waitForIdleTimeoutMs:ee(r.waitForIdleTimeoutMs),waitForIdleQuietMs:ee(r.waitForIdleQuietMs),timeoutMs:ee(r.timeoutMs),maxDepth:ee(r.maxDepth),maxNodes:ee(r.maxNodes),rootPresent:et(r.rootPresent),captureMode:"interactive-windows"===r.captureMode||"active-window"===r.captureMode?r.captureMode:void 0,windowCount:ee(r.windowCount),nodeCount:ee(r.nodeCount),truncated:et(r.truncated),elapsedMs:ee(r.elapsedMs)}}}(await el(e,`snapshot ${r}`,n),r)}function el(e,t,r){return new Promise((n,o)=>{let s=i.connect({host:"127.0.0.1",port:e.port}),u=[],l=setTimeout(()=>{s.destroy(),o(new a("COMMAND_FAILED","Android snapshot helper session request timed out",{command:t,timeoutMs:r,port:e.port}))},r);s.on("connect",()=>{s.write(`${t}
4
+ `)}),s.on("data",e=>{u.push(Buffer.from(e))}),s.on("error",e=>{clearTimeout(l),o(e)}),s.on("close",()=>{clearTimeout(l),n(Buffer.concat(u).toString("utf8"))})})}async function ed(e){await e.process.stdin?.end(),await e.process.stdout?.destroy(),await e.process.stderr?.destroy(),await ec(e)}async function ec(e){await e.adb(["forward","--remove",`tcp:${e.port}`],{allowFailure:!0,timeoutMs:5e3})}let eh=new Map;function ep(e){em(ef(e.deviceKey,e.packageName,e.versionCode))}function ef(e,t,r){return e?`${e}\0${t}\0${r}`:void 0}function em(e){e&&eh.delete(e)}async function ew(e){var t,r,n;let{adb:o,artifact:i}=e,s=e.installPolicy??"missing-or-outdated",u=i.manifest.packageName,l=i.manifest.versionCode;if("never"===s)return{packageName:u,versionCode:l,installed:!1,reason:"skipped"};let d=ef(e.deviceKey,u,l),c=d?eh.get(d):void 0;if(d&&"always"!==s&&void 0!==c)return{packageName:u,versionCode:l,installedVersionCode:c,installed:!1,reason:"current"};let h=await eA(o,u,e.timeoutMs),p=(t=s,r=h,n=l,"never"===t?"skipped":"always"===t?"forced":void 0===r?"missing":r<n?"outdated":"current");if("current"===p){if(void 0===h)throw Error("Expected installed versionCode for current Android snapshot helper");return d&&eh.set(d,h),{packageName:u,versionCode:l,installedVersionCode:h,installed:!1,reason:p}}await w(i);let f=await eM(o,e.adbProvider??o,i.apkPath,function(e){let t={};for(let r of e.slice(1)){let e=y(r);if(!e)throw new a("INVALID_ARGS",`Android snapshot helper manifest installArgs contains unsupported install flag "${r}".`);t[e]=!0}return t}(N(i.manifest.installArgs)),{packageName:u,timeoutMs:e.timeoutMs});if(0!==f.exitCode)throw em(d),new a("COMMAND_FAILED","Failed to install Android snapshot helper",{packageName:u,versionCode:l,stdout:f.stdout,stderr:f.stderr,exitCode:f.exitCode});return d&&eh.set(d,l),{packageName:u,versionCode:l,installedVersionCode:h,installed:!0,reason:p}}async function eA(e,t,r){let n=await e(["shell","cmd","package","list","packages","--show-versioncode",t],{allowFailure:!0,timeoutMs:r});if(0===n.exitCode){var o=`${n.stdout}
5
+ ${n.stderr}`,i=t;let e=`package:${i}`;for(let t of o.split(/\r?\n/)){if(!t.startsWith(e)||t.length>e.length&&!/\s/.test(t[e.length]??""))continue;let r=/(?:^|\s)versionCode:(\d+)(?:\s|$)/.exec(t);if(r)return Number(r[1])}return}}async function eM(e,t,r,n,o){var i;let a=async()=>await l(r,{allowFailure:!0,provider:t,...n,timeoutMs:o.timeoutMs}),s=await a();if(0===s.exitCode||(i=s,!`${i.stdout}
6
+ ${i.stderr}`.includes("INSTALL_FAILED_UPDATE_INCOMPATIBLE")))return s;let u=await e(["uninstall",o.packageName],{allowFailure:!0,timeoutMs:o.timeoutMs}),d=await a();return 0===d.exitCode?d:{...d,stderr:[d.stderr,u.stderr?`Previous uninstall stderr after INSTALL_FAILED_UPDATE_INCOMPATIBLE: ${u.stderr}`:""].filter(Boolean).join("\n")}}export{d as ANDROID_SNAPSHOT_HELPER_NAME,f as ANDROID_SNAPSHOT_HELPER_OUTPUT_FORMAT,c as ANDROID_SNAPSHOT_HELPER_PACKAGE,p as ANDROID_SNAPSHOT_HELPER_PROTOCOL,h as ANDROID_SNAPSHOT_HELPER_RUNNER,S as androidUiNodes,k as buildUiHierarchySnapshot,R as captureAndroidSnapshotWithHelper,ei as captureAndroidSnapshotWithHelperSession,ew as ensureAndroidSnapshotHelper,ep as forgetAndroidSnapshotHelperInstall,M as parseAndroidSnapshotHelperManifest,W as parseAndroidSnapshotHelperOutput,X as parseAndroidSnapshotHelperXml,b as parseUiHierarchy,E as parseUiHierarchyTree,A as prepareAndroidSnapshotHelperArtifactFromManifestUrl,ea as stopAndroidSnapshotHelperSession,w as verifyAndroidSnapshotHelperArtifact};