agent-device 0.15.0 → 0.15.2

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 (27) hide show
  1. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.15.0.apk → agent-device-android-snapshot-helper-0.15.2.apk} +0 -0
  2. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.15.2.apk.sha256 +1 -0
  3. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.15.0.manifest.json → agent-device-android-snapshot-helper-0.15.2.manifest.json} +6 -6
  4. package/dist/src/1393.js +1 -0
  5. package/dist/src/1769.js +7 -7
  6. package/dist/src/1974.js +2 -2
  7. package/dist/src/208.js +1 -1
  8. package/dist/src/2151.js +31 -22
  9. package/dist/src/221.js +3 -3
  10. package/dist/src/3572.js +1 -1
  11. package/dist/src/4829.js +1 -1
  12. package/dist/src/9542.js +2 -2
  13. package/dist/src/989.js +1 -1
  14. package/dist/src/android-adb.js +1 -1
  15. package/dist/src/cli.js +45 -45
  16. package/dist/src/index.d.ts +38 -5
  17. package/dist/src/internal/daemon.js +46 -45
  18. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +155 -0
  19. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +3 -25
  20. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +5 -0
  21. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +1 -14
  22. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +3 -3
  23. package/ios-runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +7 -1
  24. package/package.json +6 -1
  25. package/server.json +2 -2
  26. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.15.0.apk.sha256 +0 -1
  27. package/dist/src/840.js +0 -2
package/dist/src/2151.js CHANGED
@@ -1,4 +1,4 @@
1
- let e,t,a,n,r,i,s,o;import{promises as l}from"node:fs";import{PNG as c}from"pngjs";import d from"node:path";import{normalizeRef as p,centerOfRect as u,buildSnapshotPresentationKey as h,findNodeByRef as m}from"./4057.js";import{isScrollableNodeLike as f}from"./2842.js";import{asAppError as g,AppError as b}from"./9152.js";import{SCREENSHOT_SPECIFIC_FLAG_DEFINITIONS as w,SCREENSHOT_COMMAND_FLAG_KEYS as y,PUBLIC_COMMANDS as v,ALL_DEVICE_COMMAND_CAPABILITY as k,defineCommand as x,INTERACTION_COMMAND_SCHEMAS as A,successText as D,commandCapabilityMap as I,commandSchemaMap as R}from"./3572.js";import{resolveAppsFilter as S,DEFAULT_APPS_FILTER as M,assertResolvedAppsFilter as N}from"./840.js";import{whichCmd as O,runCmd as L}from"./9818.js";import{trimText as P,extractNodeText as E,parseSelectorChain as C,isNodeVisible as U,isNodeEditable as T,buildTextPreview as _,findNearestHittableAncestor as $,buildSelectorChainForNode as F,findSelectorChainMatch as B,resolveSelectorChain as q,findNodeByLabel as G,resolveRefLabel as j,describeTextSurface as V,extractReadableText as X,formatSelectorFailure as Y,normalizeType as K,isFillableType as z}from"./940.js";import{findBestMatchesByLocator as H}from"./7556.js";import"./7847.js";function J(e,t,a){return t>=e.x&&t<=e.x+e.width&&a>=e.y&&a<=e.y+e.height}function W(e){let t=null,a=-1;for(let n of e){let e=n.width*n.height;e>a&&(t=n,a=e)}return t}function Q(e,t,a,n){return Math.max(e,a)<=Math.min(t,n)}function Z(e){let t=new Map;for(let[a,n]of e.entries())t.set(n.index,a);let a=[],n=[];for(let[r,i]of e.entries()){let e=Math.max(0,i.depth??0);for(;n.length>0&&e<=n[n.length-1].depth;)n.pop();let s="number"==typeof i.parentIndex?t.get(i.parentIndex):void 0,o="number"==typeof s&&s<r?s:n[n.length-1]?.index;a.push({...i,index:r,depth:e,parentIndex:o}),n.push({depth:e,index:r})}return a}function ee(e){return new Map(e.map(e=>[e.index,e]))}function et(e){return e.label?.trim()||e.value?.trim()||e.identifier?.trim()||""}function ea(e){if(0===e.length)return{nodes:e,hiddenCount:0,summaryLines:[]};let{byIndex:t,visibleNodeIndexes:a,offscreenNodes:n,hintedContainers:r}=er(e),i=0===a.size?e:e.filter(e=>a.has(e.index));return{nodes:i.map(e=>(function(e,t){let a=t.get(e.index);if(!a||0===a.size)return e;let n=!!(!0===e.hiddenContentAbove||a.has("above"))||void 0,r=!!(!0===e.hiddenContentBelow||a.has("below"))||void 0;return{...e,hiddenContentAbove:n,hiddenContentBelow:r}})(e,r.directionsByContainer)),hiddenCount:0===a.size?0:e.length-i.length,summaryLines:function(e,t,a){let n=new Map;for(let r of e){let e=function(e,t,a){if(!e.rect)return null;let n=es(e,t,a);return n?eo(e.rect,n):null}(r,t,a);if(!e)continue;let i=n.get(e)??[];i.push(r),n.set(e,i)}return["above","below"].flatMap(e=>{let t=n.get(e);if(!t||0===t.length)return[];let a=(function(e){let t=new Set,a=[];for(let n of e){let e=et(n);!e||t.has(e)||(t.add(e),a.push(e))}return a})(t).slice(0,3).map(e=>`"${e}"`),r=1===t.length?"interactive item":"interactive items",i=a.length>0?`: ${a.join(", ")}`:"";return[`[off-screen ${e}] ${t.length} ${r}${i}`]})}(n.filter(e=>!r.coveredNodeIndexes.has(e.index)&&function(e){if(!0===e.hittable)return!0;let t=(e.type??"").toLowerCase();return t.includes("button")||t.includes("link")||t.includes("textfield")||t.includes("edittext")||t.includes("searchfield")||t.includes("checkbox")||t.includes("radio")||t.includes("switch")||t.includes("menuitem")||!!et(e)}(e)),e,t)}}function en(e){if(0===e.length)return new Map;let{hintedContainers:t}=er(e);var a=t.directionsByContainer;let n=new Map;for(let[e,t]of a){let a={};t.has("above")&&(a.hiddenContentAbove=!0),t.has("below")&&(a.hiddenContentBelow=!0),(a.hiddenContentAbove||a.hiddenContentBelow)&&n.set(e,a)}return n}function er(e){let t=ee(e),a=new Set,n=[];for(let r of e){if(ei(r,e,t)){!function(e,t,a){let n=e,r=new Set;for(;n&&!r.has(n.index);)r.add(n.index),t.add(n.index),n="number"==typeof n.parentIndex?a.get(n.parentIndex):void 0}(r,a,t);continue}n.push(r)}let r=function(e,t,a,n){let r=new Map,i=new Set;for(let e of t){if(!e.rect)continue;let t=el(e,a,n);if(!t?.rect)continue;let s=eo(e.rect,t.rect);if(!s)continue;let o=r.get(t.index)??new Set;o.add(s),r.set(t.index,o),i.add(e.index)}return function(e,t,a,n){for(let r of e){let e=function(e){let t=function(e,t){if(!(e?.trim().toLowerCase()??"").includes("vertical scroll bar"))return null;let a=function(e){if(!e)return null;let t=/^(\d{1,3})%$/.exec(e.trim());if(!t)return null;let a=Number(t[1]);return Number.isFinite(a)?Math.max(0,Math.min(100,a)):null}(t);return null===a?null:a<=1?{above:!1,below:!0}:a>=99?{above:!0,below:!1}:{above:!0,below:!0}}(e.label,e.value);if(!t)return null;let a=new Set;return t.above&&a.add("above"),t.below&&a.add("below"),a.size>0?a:null}(r);if(!e||0===e.size)continue;let i=el(r,t,a);if(!i)continue;let s=n.get(i.index)??new Set;for(let t of e)s.add(t);n.set(i.index,s)}}(e,a,n,r),{directionsByContainer:r,coveredNodeIndexes:i}}(e,n,a,t);return{byIndex:t,visibleNodeIndexes:a,offscreenNodes:n,hintedContainers:r}}function ei(e,t,a=ee(t)){var n;if(!e.rect)return!0;let r=es(e,t,a);return!r||(n=e.rect,Q(n.x,n.x+n.width,r.x,r.x+r.width)&&Q(n.y,n.y+n.height,r.y,r.y+r.height))}function es(e,t,a=ee(t)){let n=function(e,t){let a="number"==typeof e.parentIndex?t.get(e.parentIndex):void 0,n=new Set;for(;a&&!n.has(a.index);){if(n.add(a.index),a.rect&&f(a))return a.rect;a="number"==typeof a.parentIndex?t.get(a.parentIndex):void 0}return null}(e,a);return n||function(e,t){let a=u(t),n=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),r=n.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),i=W(r.map(e=>e.rect).filter(e=>J(e,a.x,a.y)));if(i)return i;let s=W(r.map(e=>e.rect));if(s)return s;let o=W(n.map(e=>e.rect).filter(e=>J(e,a.x,a.y)));return o||null}(t,e.rect??{x:0,y:0,width:0,height:0})}function eo(e,t){return e.y+e.height<=t.y?"above":e.y>=t.y+t.height?"below":null}function el(e,t,a){let n="number"==typeof e.parentIndex?a.get(e.parentIndex):void 0,r=new Set;for(;n&&!r.has(n.index);){if(r.add(n.index),t.has(n.index)&&f(n))return n;n="number"==typeof n.parentIndex?a.get(n.parentIndex):void 0}return null}let ec="<wifi|airplane|location> <on|off>",ed="location set <lat> <lon>",ep="animations <on|off>",eu="appearance <light|dark|toggle>",eh="faceid <match|nonmatch|enroll|unenroll>",em="touchid <match|nonmatch|enroll|unenroll>",ef="fingerprint <match|nonmatch>",eg="permission <grant|deny|reset> <camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri> [full|limited]",eb="permission <grant|reset> <accessibility|screen-recording|input-monitoring>",ew=`macOS supports only settings ${eu} and settings ${eb}. wifi|airplane|location|animations remain unsupported on macOS.`,ey=`settings ${ec} | settings ${ed} | settings ${ep} | settings ${eu} | settings ${eh} | settings ${em} | settings ${ef} | settings ${eg} | settings ${eb}`,ev=`settings requires ${ec}, ${ed}, ${ep}, ${eu}, ${eh}, ${em}, ${ef}, ${eg}, or ${eb}`;function ek(e){let t=e.trim().toLowerCase();return"appearance"===t||"permission"===t}function ex(e){return`Unsupported macOS setting: ${e}. ${ew}`}function eA(e){let t=e?.trim().split(/\s+/,1)[0];if(!t||!t.startsWith("@")||t.length<3)return null;let a=t.slice(1);return/^[A-Za-z_-]*\d[\w-]*$/i.test(a)||/^(?:ref|node|element|el)[\w-]*$/i.test(a)?t:null}function eD(e,t,a,n){if(!Number.isFinite(e)||!Number.isInteger(e)||e<a||e>n)throw new b("INVALID_ARGS",`${t} must be an integer between ${a} and ${n}`);return e}function eI(e){if(void 0===e)throw new b("INVALID_ARGS","rotate requires an orientation argument. Use portrait|portrait-upside-down|landscape-left|landscape-right.");switch(e?.trim().toLowerCase()){case"portrait":return"portrait";case"portrait-upside-down":case"upside-down":return"portrait-upside-down";case"landscape-left":case"left":return"landscape-left";case"landscape-right":case"right":return"landscape-right";default:throw new b("INVALID_ARGS",`Invalid rotation: ${e}. Use portrait|portrait-upside-down|landscape-left|landscape-right.`)}}let eR=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],eS=[x({name:v.snapshot,schema:{usageOverride:"snapshot [--diff] [-i] [-c] [-d <depth>] [-s <scope>] [--raw] [--force-full]",helpDescription:"Capture accessibility tree or diff against the previous session baseline",positionalArgs:[],allowedFlags:["snapshotDiff",...eR,"snapshotForceFull"]},capability:k}),x({name:v.diff,schema:{usageOverride:"diff snapshot | diff screenshot --baseline <path> [current.png] [--out <diff.png>] [--threshold <0-1>] [--overlay-refs]",helpDescription:"Diff accessibility snapshot or compare screenshots pixel-by-pixel",summary:"Diff snapshot or screenshot",positionalArgs:["kind","current?"],allowedFlags:[...eR,"baseline","threshold","out","overlayRefs"]},capability:k}),x({name:v.screenshot,schema:{helpDescription:"Capture screenshot (macOS app sessions default to the app window; use --fullscreen for full desktop, --max-size to downscale, --overlay-refs to annotate current refs, or --no-stabilize for low-latency Android capture loops)",positionalArgs:["path?"],allowedFlags:y},capability:k})],eM=R(eS),eN=I(eS),eO=["snapshotDepth","snapshotScope","snapshotRaw"],eL=[x({name:v.wait,schema:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",helpDescription:"Wait for duration, text, ref, or selector to appear",summary:"Wait for time, text, ref, or selector",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...eO]},capability:k}),x({name:v.get,schema:{usageOverride:"get text|attrs <@ref|selector>",helpDescription:"Return exposed element text/attributes by ref or selector; use snapshot -s @ref for truncated previews",summary:"Get exposed text or attrs by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...eO]},capability:k}),x({name:v.find,schema:{usageOverride:"find <locator|text> <action> [value] [--first|--last]",helpDescription:"Find by text/label/value/role/id and run action",summary:"Find an element and act",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw","findFirst","findLast"]},capability:k}),x({name:v.is,schema:{helpDescription:"Assert UI state (visible|hidden|exists|editable|selected|text)",summary:"Assert UI state",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...eO]},capability:k})],eP=R(eL),eE=I(eL),eC={apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{device:!0}},eU={apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{},supports:e=>"macos"!==e.platform},eT=[x({name:v.open,schema:{helpDescription:"Boot device/simulator; optionally launch app or deep link URL (macOS also supports --surface app|frontmost-app|desktop|menubar)",summary:"Open an app, deep link or URL, save replays",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","saveScript","relaunch","surface"]},capability:eC}),x({name:v.close,schema:{helpDescription:"Close app or just end session",summary:"Close app or end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},capability:eC}),x({name:v.reinstall,schema:{helpDescription:"Uninstall + install app from binary path",summary:"Reinstall app from binary path",positionalArgs:["app","path"],allowedFlags:[]},capability:eU}),x({name:v.install,schema:{helpDescription:"Install app from binary path without uninstalling first",summary:"Install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},capability:eU}),x({name:v.installFromSource,schema:{usageOverride:"install-from-source <url> | install-from-source --github-actions-artifact <owner/repo:artifact>",listUsageOverride:"install-from-source <url> | install-from-source --github-actions-artifact",helpDescription:"Install app from a URL or remote-resolved source",summary:"Install app from a source",positionalArgs:["url?"],allowedFlags:["header","githubActionsArtifact","installSource","retainPaths","retentionMs"]},capability:eU}),x({name:v.apps,schema:{helpDescription:"List user-installed apps; use --all to include system/OEM apps",summary:"List installed apps",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:M}},capability:{apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{}}})],e_=R(eT),e$=I(eT);function eF(e,t){try{return c.sync.read(e)}catch(e){throw new b("COMMAND_FAILED",`Failed to decode ${t} as PNG`,{label:t,reason:e instanceof Error?e.message:String(e)})}}async function eB(e,t){if(!Number.isInteger(t)||t<1)throw new b("INVALID_ARGS","Screenshot max size must be a positive integer");let a=eF(await l.readFile(e),"screenshot"),n=Math.max(a.width,a.height);if(n<=t)return;let r=t/n,i=Math.max(1,Math.round(a.width*r)),s=Math.max(1,Math.round(a.height*r)),o=function(e,t,a){let n=new c({width:t,height:a});for(let r=0;r<a;r+=1){let i=r*e.height/a,s=(r+1)*e.height/a;for(let a=0;a<t;a+=1){let o=a*e.width/t,l=(a+1)*e.width/t,c=0,d=0,p=0,u=0,h=0;for(let t=Math.floor(i);t<Math.ceil(s);t+=1){let a=Math.min(t+1,s)-Math.max(t,i);for(let n=Math.floor(o);n<Math.ceil(l);n+=1){let r=a*(Math.min(n+1,l)-Math.max(n,o)),i=(t*e.width+n)*4;c+=(e.data[i]??0)*r,d+=(e.data[i+1]??0)*r,p+=(e.data[i+2]??0)*r,u+=(e.data[i+3]??0)*r,h+=r}}let m=(r*n.width+a)*4;n.data[m]=Math.round(c/h),n.data[m+1]=Math.round(d/h),n.data[m+2]=Math.round(p/h),n.data[m+3]=Math.round(u/h)}}return n}(a,i,s);await l.writeFile(e,c.sync.write(o))}async function eq(e,t,a){if("path"===t.kind&&!e.policy.allowLocalInputPaths)throw new b("INVALID_ARGS",`Local ${a.field??"input"} paths are not allowed by command policy`);try{return await e.artifacts.resolveInput(t,a)}catch(e){throw g(e)}}async function eG(e,t,a){if(t?.kind==="path"&&!e.policy.allowLocalOutputPaths)throw new b("INVALID_ARGS","Local output paths are not allowed by command policy");try{return await e.artifacts.reserveOutput(t,{...a,visibility:a.visibility??"client-visible",requestedClientPath:t?.kind==="downloadableArtifact"?t.clientPath??a.requestedClientPath:a.requestedClientPath})}catch(e){throw g(e)}}async function ej(e,t){try{return await e.artifacts.createTempFile(t)}catch(e){throw g(e)}}let eV=async(e,t)=>{let a;if(!e.backend.captureScreenshot)throw new b("UNSUPPORTED_OPERATION","screenshot is not supported by this backend");let n=await eG(e,t.out,{field:"path",ext:".png"});try{await e.backend.captureScreenshot({session:t.session,requestId:t.requestId,appId:t.appId,appBundleId:t.appBundleId,signal:t.signal??e.signal,metadata:t.metadata},n.path,{fullscreen:t.fullscreen,overlayRefs:t.overlayRefs,stabilize:t.stabilize,surface:t.surface}),void 0!==t.maxSize&&await eB(n.path,t.maxSize),a=await n.publish()}catch(e){throw await n.cleanup?.(),e}return{path:n.path,...a?{artifacts:[a]}:{},...D(`Saved screenshot: ${n.path}`)}},eX=[0,187,255,255];function eY(e,t,a,n){if(t<0||t>=e.width||a<0||a>=e.height)return;let r=(a*e.width+t)*4;e.data[r]=n[0],e.data[r+1]=n[1],e.data[r+2]=n[2],e.data[r+3]=n[3]}function eK(e,t,a){return Math.min(Math.max(e,t),a)}let ez={icon:90,toggle:90,chevron:75,separator:45,visual:35,background:10},eH={leading:20,trailing:20,separator:10,unknown:0,background:-30};function eJ(e){return"background"!==e.likelyKind}function eW(e,t){return e.width>=.25*t.width||e.height>=.06*t.height}function eQ(e,t){let a,n=0;for(let r of t){let t=e5(e,r.rect);t<=n||(n=t,a=r)}return a}function eZ(e){let t=[];for(let a of[...e].sort((e,t)=>e.rect.y-t.rect.y)){let e=t.find(e=>{var t,n;return t=e.rect,e5(t,n=a.rect)>0||Math.abs(e3(t).y-e3(n).y)<=.5*Math.max(t.height,n.height)});if(!e){t.push({rect:a.rect,blocks:[a]});continue}e.blocks.push(a),e.blocks.sort((e,t)=>e.rect.x-t.rect.x),e.rect=function(e){let t=1/0,a=1/0,n=-1/0,r=-1/0;for(let i of e)t=Math.min(t,i.x),a=Math.min(a,i.y),n=Math.max(n,i.x+i.width),r=Math.max(r,i.y+i.height);return{x:t,y:a,width:n-t,height:r-a}}([e.rect,a.rect])}return t}function e0(e,t){let a,n=e3(e);for(let e of t){var r,i;let t=Math.sqrt((r=n,i=e3(e.rect),(r.x-i.x)**2+(r.y-i.y)**2));a&&t>=a.distance||(a={block:e,distance:t})}return a}function e1(e){let t=e2(e);return e.differentPixels>=24&&t.width>=3&&t.height>=3}function e2(e){return{x:e.minX,y:e.minY,width:e.maxX-e.minX+1,height:e.maxY-e.minY+1}}function e5(e,t){return Math.max(0,Math.min(e.y+e.height,t.y+t.height)-Math.max(e.y,t.y))}function e3(e){return{x:e.x+e.width/2,y:e.y+e.height/2}}function e4(e,t,a){return Math.min(Math.max(e,t),a)}async function e8(e){if(await O("tesseract"))try{let[t,a]=await Promise.all([e7(e.baselinePath),e7(e.currentPath)]);if(0!==t.exitCode||0!==a.exitCode)return;let n=e6(t.stdout,e.width,e.height),r=e6(a.stdout,e.width,e.height),i=function(e,t){let a=new Set,n=[];for(let i of e){var r;let e=ti(i.text),s=function(e,t,a,n){let r=null,i=1/0;for(let l=0;l<a.length;l+=1){var s,o;if(n.has(l))continue;let c=a[l];if(ti(c.text)!==t)continue;let d=(s=ta(e.normalizedRect),o=ta(c.normalizedRect),(s.x-o.x)**2+(s.y-o.y)**2);d>=i||(r=l,i=d)}return r}(i,e,t,a);if(null===s)continue;a.add(s);let o=function(e,t){let a={x:t.rect.x-e.rect.x,y:t.rect.y-e.rect.y,width:t.rect.width-e.rect.width,height:t.rect.height-e.rect.height},n=tl(t.rect.width/e.rect.width),r=tl(t.rect.height/e.rect.height),i=Math.abs(n-1)>=.08||Math.abs(r-1)>=.12;return{text:e.text,baselineRect:e.rect,currentRect:t.rect,delta:a,confidence:Math.round(100*Math.min(e.confidence,t.confidence))/100,possibleTextMetricMismatch:i}}(i,t[s]);r=o,(Math.abs(r.delta.x)>=2||Math.abs(r.delta.y)>=2||Math.abs(r.delta.width)>=2||Math.abs(r.delta.height)>=2||r.possibleTextMetricMismatch)&&n.push(o)}return n.sort((e,t)=>e9(t)-e9(e)).slice(0,12)}(n,r),s=function(e){let t=[];for(let a of[...e].sort((e,t)=>e.currentRect.y-t.currentRect.y)){let e=t.find(e=>32>=Math.abs(a.delta.x-ts(e.map(e=>e.delta.x))));e?e.push(a):t.push([a])}return t.filter(e=>e.length>=2).map(te).filter(e=>e.yRange.max-e.yRange.min<=60).sort((e,t)=>tt(t)-tt(e)).slice(0,4)}(i);if(0===n.length&&0===r.length)return;return{provider:"tesseract",baselineBlocks:n.length,currentBlocks:r.length,baselineBlocksRaw:n,currentBlocksRaw:r,matches:i,...s.length>0?{movementClusters:s}:{}}}catch{return}}function e6(e,t,a){let[n,...r]=e.split(/\r?\n/);if(!n)return[];let i=new Map(n.split(" ").map((e,t)=>[e,t])),s=[];for(let e of r){var o;if(!e.trim())continue;let t=e.split(" "),a=tr(t,i,"level"),n=tn(t,i,"text").trim(),r=tr(t,i,"conf");if(5!==a||(o=n,!/[\p{L}\p{N}]/u.test(o))||r<0)continue;let l=tr(t,i,"left"),c=tr(t,i,"top"),d=tr(t,i,"width"),p=tr(t,i,"height");d<=0||p<=0||s.push({key:[tn(t,i,"page_num"),tn(t,i,"block_num"),tn(t,i,"par_num"),tn(t,i,"line_num")].join(":"),text:n,confidence:r,rect:{x:l,y:c,width:d,height:p}})}let l=new Map;for(let e of s){let t=l.get(e.key);t?t.push(e):l.set(e.key,[e])}return Array.from(l.values()).flatMap(e=>(function(e){let t=[...e].sort((e,t)=>e.rect.x-t.rect.x),a=[],n=[];for(let e of t){let t=n.at(-1);if(!t){n.push(e);continue}if(e.rect.x-(t.rect.x+t.rect.width)>Math.max(48,2.5*Math.max(t.rect.height,e.rect.height))){a.push(n),n=[e];continue}n.push(e)}return n.length>0&&a.push(n),a})(e)).map(e=>(function(e,t,a){if(0===e.length)return null;let n=[...e].sort((e,t)=>e.rect.x-t.rect.x),r=function(e){let t=1/0,a=1/0,n=-1/0,r=-1/0;for(let i of e)t=Math.min(t,i.x),a=Math.min(a,i.y),n=Math.max(n,i.x+i.width),r=Math.max(r,i.y+i.height);return{x:t,y:a,width:n-t,height:r-a}}(n.map(e=>e.rect)),i=Math.round(100*ts(n.map(e=>e.confidence)))/100;return{text:n.map(e=>e.text).join(" "),confidence:i,rect:r,normalizedRect:{x:to(r.x/t),y:to(r.y/a),width:to(r.width/t),height:to(r.height/a)}}})(e,t,a)).filter(e=>null!==e)}function e7(e){return L("tesseract",[e,"stdout","-l","eng","tsv"],{allowFailure:!0,timeoutMs:1e4})}function e9(e){return Math.abs(e.delta.x)+Math.abs(e.delta.y)+Math.abs(e.delta.width)+Math.abs(e.delta.height)+25*!!e.possibleTextMetricMismatch}function te(e){let t=e.map(e=>e.delta.x),a=e.map(e=>e.delta.y);return{texts:e.map(e=>e.text),xRange:{min:Math.min(...t),max:Math.max(...t)},yRange:{min:Math.min(...a),max:Math.max(...a)}}}function tt(e){return 2*Math.abs((e.xRange.min+e.xRange.max)/2)+Math.abs((e.yRange.min+e.yRange.max)/2)}function ta(e){return{x:e.x+e.width/2,y:e.y+e.height/2}}function tn(e,t,a){let n=t.get(a);return void 0===n?"":e[n]??""}function tr(e,t,a){let n=Number(tn(e,t,a));return Number.isFinite(n)?n:0}function ti(e){return e.trim().replace(/\s+/g," ").toLowerCase()}function ts(e){return e.reduce((e,t)=>e+t,0)/e.length}function to(e){return Math.round(100*e*100)/100}function tl(e){return Math.round(1e3*e)/1e3}function tc(e,t,a,n){return{r:Math.round(e/n),g:Math.round(t/n),b:Math.round(a/n)}}function td(e){return .2126*e.r+.7152*e.g+.0722*e.b}function tp(e){return`#${tu(e.r)}${tu(e.g)}${tu(e.b)}`}function tu(e){return e.toString(16).padStart(2,"0")}function th(e){return Math.round(100*e*100)/100}let tm=255*Math.sqrt(3);async function tf(e,t,a={}){let n,r,i,s;await tg(e,"Baseline image not found"),await tg(t,"Current screenshot not found");let o=a.outputPath,[p,u]=await Promise.all([l.readFile(e),l.readFile(t)]),h=eF(p,"baseline screenshot"),m=eF(u,"current screenshot");tb(h.width,h.height,"baseline screenshot",a.maxPixels),tb(m.width,m.height,"current screenshot",a.maxPixels);let f=a.threshold??.1;if(h.width!==m.width||h.height!==m.height){let e=h.width*h.height;return await tw(a.outputPath),{match:!1,mismatchPercentage:100,totalPixels:e,differentPixels:e,dimensionMismatch:{expected:{width:h.width,height:h.height},actual:{width:m.width,height:m.height}}}}let g=h.width*h.height,b=f*tm,w=new c({width:h.width,height:h.height}),y=new Uint8Array(g),v=0;for(let e=0,t=0;e<h.data.length;e+=4,t+=1){if(Math.sqrt((h.data[e]-m.data[e])**2+(h.data[e+1]-m.data[e+1])**2+(h.data[e+2]-m.data[e+2])**2)>b){v+=1,y[t]=1;let a=ty(m,e);w.data[e]=tv(a,220,.78),w.data[e+1]=tv(a,0,.78),w.data[e+2]=tv(a,0,.78),w.data[e+3]=255;continue}let a=ty(m,e);w.data[e]=a,w.data[e+1]=a,w.data[e+2]=a,w.data[e+3]=255}let k=v>0?(A=(n=function(e){let{diffMask:t,baseline:a,current:n}=e,{width:r,height:i}=a,s=new Uint8Array(t.length),o=new Int32Array(t.length),l=[];for(let e=0;e<t.length;e+=1){if(1!==t[e]||1===s[e])continue;let c=0,d=0;o[0]=e,d+=1,s[e]=1;let p=e%r,u=Math.floor(e/r),h={minX:p,minY:u,maxX:p,maxY:u,differentPixels:0,baselineRed:0,baselineGreen:0,baselineBlue:0,currentRed:0,currentGreen:0,currentBlue:0};for(;c<d;){let e=o[c];c+=1,function(e,t,a,n,r){let i=t%a,s=Math.floor(t/a),o=4*t;e.minX=Math.min(e.minX,i),e.minY=Math.min(e.minY,s),e.maxX=Math.max(e.maxX,i),e.maxY=Math.max(e.maxY,s),e.differentPixels+=1,e.baselineRed+=n.data[o],e.baselineGreen+=n.data[o+1],e.baselineBlue+=n.data[o+2],e.currentRed+=r.data[o],e.currentGreen+=r.data[o+1],e.currentBlue+=r.data[o+2]}(h,e,r,a,n);let l=e%r,p=Math.floor(e/r);for(let e=-1;e<=1;e+=1){let a=p+e;if(!(a<0)&&!(a>=i))for(let n=-1;n<=1;n+=1){if(0===n&&0===e)continue;let i=l+n;if(i<0||i>=r)continue;let c=a*r+i;1===t[c]&&1!==s[c]&&(s[c]=1,o[d]=c,d+=1)}}}l.push(h)}return l}(x={diffMask:y,baseline:h,current:m,totalPixels:g,differentPixels:v,maxRegions:a.maxRegions})).length<=2e3?function(e){let t=[];for(let r of e.sort((e,t)=>{let a=e.minY-t.minY;return 0!==a?a:e.minX-t.minX})){var a,n;let e=t.find(e=>{var t,a,n;return t=e,a=r,n=12,t.minX-n<=a.maxX&&a.minX-n<=t.maxX&&t.minY-n<=a.maxY&&a.minY-n<=t.maxY});if(!e){t.push({...r});continue}a=e,n=r,a.minX=Math.min(a.minX,n.minX),a.minY=Math.min(a.minY,n.minY),a.maxX=Math.max(a.maxX,n.maxX),a.maxY=Math.max(a.maxY,n.maxY),a.differentPixels+=n.differentPixels,a.baselineRed+=n.baselineRed,a.baselineGreen+=n.baselineGreen,a.baselineBlue+=n.baselineBlue,a.currentRed+=n.currentRed,a.currentGreen+=n.currentGreen,a.currentBlue+=n.currentBlue}return t}(n):n,A.flatMap(e=>{var t,a,n;let r;return(t=e,a=x.baseline.width,n=x.baseline.height,r=t.maxX-t.minX+1,t.maxY-t.minY+1>=Math.max(48,Math.round(.07*n))&&r>=.35*a)?function(e,t,a){var n;let r=function(e,t){let a=[],n=null;for(let r=0;r<e.length;r+=1){if(e[r]<=t){n??=r;continue}null!==n&&(r-n>=6&&a.push([n,r-1]),n=null)}return null!==n&&e.length-n>=6&&a.push([n,e.length-1]),a}((n=function(e,t,a){let n=[];for(let r=e.minY;r<=e.maxY;r+=1){let i=0;for(let n=e.minX;n<=e.maxX;n+=1)1===t[r*a+n]&&(i+=1);n.push(i)}return n}(e,t.diffMask,t.baseline.width)).map((e,t)=>{let a=0,r=0,i=Math.max(0,t-3),s=Math.min(n.length-1,t+3);for(let e=i;e<=s;e+=1)a+=n[e],r+=1;return Math.round(a/r)}),Math.max(1,Math.round((e.maxX-e.minX+1)*.08))),i=function(e,t,a){let n=[],r=e.minY;for(let[i,s]of t){let t=e.minY+Math.round((i+s)/2);t-r+1<a||e.maxY-t<a||(n.push([r,t]),r=t+1)}return n.push([r,e.maxY]),n}(e,r,a);if(i.length<=1)return[e];let s=i.map(([a,n])=>(function(e,t,a,n){let r=null;for(let o=t;o<=a;o+=1)for(let t=e.minX;t<=e.maxX;t+=1){var i,s;let e=o*n.baseline.width+t;1===n.diffMask[e]&&function(e,t,a,n,r,i){let s=4*t;e.minX=Math.min(e.minX,a),e.minY=Math.min(e.minY,n),e.maxX=Math.max(e.maxX,a),e.maxY=Math.max(e.maxY,n),e.differentPixels+=1,e.baselineRed+=r.data[s],e.baselineGreen+=r.data[s+1],e.baselineBlue+=r.data[s+2],e.currentRed+=i.data[s],e.currentGreen+=i.data[s+1],e.currentBlue+=i.data[s+2]}(r??={minX:i=t,minY:s=o,maxX:i,maxY:s,differentPixels:0,baselineRed:0,baselineGreen:0,baselineBlue:0,currentRed:0,currentGreen:0,currentBlue:0},e,t,o,n.baseline,n.current)}return r})(e,a,n,t)).filter(e=>null!==e);return s.length>1?s:[e]}(e,x,Math.max(24,Math.round(.03*x.baseline.height))):[e]})).sort((e,t)=>{let a=t.differentPixels-e.differentPixels;if(0!==a)return a;let n=e.minY-t.minY;return 0!==n?n:e.minX-t.minX}).slice(0,Math.max(0,x.maxRegions??8)).map((e,t)=>{var a,n,r,i,s,o,l,c,d,p,u;let h,m,f,g,b,w,y,v,k,A,D,I,R,S,M,N,O;return a=e,n=t+1,r={width:x.baseline.width,height:x.baseline.height,totalPixels:x.totalPixels,differentPixels:x.differentPixels},w={x:a.minX,y:a.minY,width:a.maxX-a.minX+1,height:a.maxY-a.minY+1},y={x:Math.round(a.minX+w.width/2),y:Math.round(a.minY+w.height/2)},v=tc(a.baselineRed,a.baselineGreen,a.baselineBlue,a.differentPixels),k=tc(a.currentRed,a.currentGreen,a.currentBlue,a.differentPixels),A=w.width*w.height,D=th(a.differentPixels/A),I=Math.round(td(v)),R=Math.round(td(k)),S=(i=w,s=r.width,o=r.height,i.width>=.55*s&&i.height>=.12*o?"large-area":i.width>=2.5*i.height?"horizontal-band":i.height>=2.5*i.width?"vertical-band":"compact"),M=(h=A/r.totalPixels)>=.04?"large":h>=.01?"medium":"small",N=(l=v,c=k,m=td(l),Math.abs(f=td(c)-m)>=12?f>0?"brighter":"darker":Math.max(Math.abs(c.r-l.r),Math.abs(c.g-l.g),Math.abs(c.b-l.b))>=12?"color-shift":"mixed"),O=(d=y,p=r.width,u=r.height,g=d.x<p/3?"left":d.x>2*p/3?"right":"center",b=d.y<u/3?"top":d.y>2*u/3?"bottom":"middle","center"===g&&"middle"===b?"center":`${b}-${g}`),{index:n,rect:w,normalizedRect:{x:th(w.x/r.width),y:th(w.y/r.height),width:th(w.width/r.width),height:th(w.height/r.height)},differentPixels:a.differentPixels,shareOfDiffPercentage:th(a.differentPixels/r.differentPixels),densityPercentage:D,shape:S,size:M,location:O,averageBaselineColorHex:tp(v),averageCurrentColorHex:tp(k),baselineLuminance:I,currentLuminance:R,dominantChange:N}}):[];if(v>0&&o){var x,A,D;for(let e of k)e.rect.width<4||e.rect.height<4||function(e,t){let a=eK(t.x,0,e.width-1),n=eK(t.y,0,e.height-1),r=eK(t.x+t.width-1,0,e.width-1),i=eK(t.y+t.height-1,0,e.height-1);for(let t=0;t<2;t+=1){for(let s=a;s<=r;s+=1)eY(e,s,n+t,eX),eY(e,s,i-t,eX);for(let s=n;s<=i;s+=1)eY(e,a+t,s,eX),eY(e,r-t,s,eX)}}(w,e.rect);await l.mkdir(d.dirname(o),{recursive:!0}),await l.writeFile(o,c.sync.write(w))}else await tw(a.outputPath);let I=v>0?await e8({baselinePath:e,currentPath:t,width:h.width,height:h.height}):void 0,R=I&&(I.matches.length>0||(I.movementClusters?.length??0)>0)?{provider:I.provider,baselineBlocks:I.baselineBlocks,currentBlocks:I.currentBlocks,matches:I.matches,...I.movementClusters?{movementClusters:I.movementClusters}:{}}:void 0,S=v>0&&I?(r=function(e){let t=[];for(let a of e.sort((e,t)=>e.minY-t.minY||e.minX-t.minX)){let e=t.find(e=>{var t,n,r;return t=e,n=a,r=10,t.minX-r<=n.maxX&&n.minX-r<=t.maxX&&t.minY-r<=n.maxY&&n.minY-r<=t.maxY});if(!e){t.push({...a});continue}e.minX=Math.min(e.minX,a.minX),e.minY=Math.min(e.minY,a.minY),e.maxX=Math.max(e.maxX,a.maxX),e.maxY=Math.max(e.maxY,a.maxY),e.differentPixels+=a.differentPixels}return t}(function(e,t,a){let n=new Uint8Array(e.length),r=new Int32Array(e.length),i=[];for(let s=0;s<e.length;s+=1){if(1!==e[s]||1===n[s])continue;let o=0,l=0;r[0]=s,l+=1,n[s]=1;let c=s%t,d=Math.floor(s/t),p={minX:c,minY:d,maxX:c,maxY:d,differentPixels:0};for(;o<l;){let i=r[o];o+=1;let s=i%t,c=Math.floor(i/t);p.minX=Math.min(p.minX,s),p.minY=Math.min(p.minY,c),p.maxX=Math.max(p.maxX,s),p.maxY=Math.max(p.maxY,c),p.differentPixels+=1;for(let i=-1;i<=1;i+=1){let o=c+i;if(!(o<0)&&!(o>=a))for(let a=-1;a<=1;a+=1){if(0===a&&0===i)continue;let c=s+a;if(c<0||c>=t)continue;let d=o*t+c;1===e[d]&&1!==n[d]&&(n[d]=1,r[l]=d,l+=1)}}}i.push(p)}return i}(function(e,t,a,n){let r=new Uint8Array(e);if(!n)return r;for(let e of[...n.baselineBlocksRaw,...n.currentBlocksRaw]){var i;!function(e,t,a,n){let r=e4(Math.floor(n.x),0,t-1),i=e4(Math.floor(n.y),0,a-1),s=e4(Math.ceil(n.x+n.width),0,t),o=e4(Math.ceil(n.y+n.height),0,a);for(let a=i;a<o;a+=1)for(let n=r;n<s;n+=1)e[a*t+n]=0}(r,t,a,{x:(i=e.rect).x-8,y:i.y-8,width:i.width+16,height:i.height+16})}return r}((D={diffMask:y,width:h.width,height:h.height,regions:k,ocr:I}).diffMask,D.width,D.height,D.ocr),D.width,D.height)),i=eZ(D.ocr?.currentBlocksRaw??[]),s=eZ(D.ocr?.baselineBlocksRaw??[]),r.filter(e1).map(e=>{var t,a,n,r,o,l,c,d,p,u,h;let m,f,g,b,w,y,v,k,x,A;return t=e,a=D,n=i,r=s,b=function(e,t){let a,n=0;for(let r of t){let t=function(e,t){let a=Math.max(e.x,t.x),n=Math.max(e.y,t.y),r=Math.min(e.x+e.width,t.x+t.width),i=Math.min(e.y+e.height,t.y+t.height);return r<=a||i<=n?0:(r-a)*(i-n)}(e,r.rect);t<=n||(n=t,a=r)}return a?.index}(g=e2(t),a.regions),w=function(e,t,a){let n=eQ(e,t);if(n)return e0(e,n.blocks);let r=eQ(e,a);return r?e0(e,r.blocks):void 0}(g,n,r),y=function(e,t,a){if(e.height<=3&&e.width>=.12*a)return"separator";if(!t)return e.width>=.4*a?"background":"unknown";if(e.width>=.4*a)return"background";let n=e.x+e.width/2,r=t.x+t.width/2;return n<r-t.width/2?"leading":n>r+t.width/2?"trailing":e.width>=.35*a?"background":"unknown"}(g,w?.block.rect,a.width),v=(o=g,l=y,c=t.differentPixels,d=a,m=o.width/o.height,f=c/(o.width*o.height),"separator"===l?"separator":"background"===l?"background":"trailing"===l&&m>=1.5&&m<=3.8&&f>=.35?"toggle":"trailing"===l&&o.width<=.06*d.width&&o.height<=.04*d.height?"chevron":"leading"===l&&m>=.55&&m<=1.8?"icon":eW(o,d)?"background":"visual"),k={...b?{regionIndex:b}:{},slot:y,likelyKind:v,rect:g},{...b?{regionIndex:b}:{},slot:y,likelyKind:v,rect:g,...w?{nearestText:w.block.text.trim().replace(/^[^\p{L}\p{N}]+/u,"").replace(/^\p{L}\s+/u,"")}:{},score:(p=k,u=t.differentPixels,h=a,x=eW(p.rect,h)?-35:0,A=20*!!p.regionIndex,ez[p.likelyKind]+eH[p.slot]+A+x+Math.min(20,u/200))}}).filter(e=>e.rect.y>=.08*D.height).filter(eJ).sort((e,t)=>t.score-e.score).slice(0,Math.max(0,D.maxDeltas??12)).map((e,t)=>{var a;return a=e,{index:t+1,...a.regionIndex?{regionIndex:a.regionIndex}:{},slot:a.slot,likelyKind:a.likelyKind,rect:a.rect,...a.nearestText?{nearestText:a.nearestText}:{}}})):[],M=g>0?Math.round(v/g*1e4)/100:0;return{...v>0&&o?{diffPath:o}:{},...k.length>0?{regions:k}:{},...R?{ocr:R}:{},...S.length>0?{nonTextDeltas:S}:{},totalPixels:g,differentPixels:v,mismatchPercentage:M,match:0===v}}async function tg(e,t){try{await l.access(e)}catch{throw new b("INVALID_ARGS",`${t}: ${e}`)}}function tb(e,t,a,n){if(null==n||n<=0)return;let r=e*t;if(!(r<=n))throw new b("INVALID_ARGS",`${a} is ${r} pixels, which exceeds the configured maxImagePixels limit of ${n}`)}async function tw(e){if(e)try{await l.unlink(e)}catch(e){var t;if(!("object"==typeof(t=e)&&null!==t&&"code"in t&&"ENOENT"===t.code))throw e}}function ty(e,t){return tv(Math.round(.299*e.data[t]+.587*e.data[t+1]+.114*e.data[t+2]),255,.72)}function tv(e,t,a){return Math.round(e*(1-a)+t*a)}function tk(e){return e.width*e.height}function tx(e){return Math.round(100*e*100)/100}let tA=async(e,t)=>{let a,n,r;if(!t.baseline)throw new b("INVALID_ARGS","diff screenshot requires a baseline image");let i=function(e){if(null==e||""===e)return .1;let t=Number(e);if(Number.isNaN(t)||t<0||t>1)throw new b("INVALID_ARGS","--threshold must be a number between 0 and 1");return t}(t.threshold),s=t.current??{kind:"live"};if(t.overlayRefs&&!tO(s))throw new b("INVALID_ARGS","diff screenshot <current.png> cannot use --overlay-refs because saved-image comparisons have no live accessibility refs");let o=await eq(e,t.baseline,{usage:"diff screenshot baseline",field:"baseline"}),l=[];try{let c;c=tO(s)?(n=await tD(e,t)).path:(a=await eq(e,s,{usage:"diff screenshot current",field:"current"})).path,r=t.out?await eG(e,t.out,{field:"diffPath",ext:".png"}):void 0;let d=await tf(o.path,c,{threshold:i,outputPath:r?.path,maxPixels:e.policy.maxImagePixels});tO(s)&&(d=await tI(e,t,r?.path,d,l));let p=d.diffPath?await r?.publish():void 0;return p&&l.push(p),d.diffPath||await r?.cleanup?.(),{...d,...l.length>0?{artifacts:l}:{}}}catch(e){throw await r?.cleanup?.(),e}finally{await o.cleanup?.(),await a?.cleanup?.(),await n?.cleanup?.()}};async function tD(e,t){let a=await ej(e,{prefix:"agent-device-diff-current",ext:".png"});try{await tR(e,t,a.path,tS(t))}catch(e){throw await a.cleanup(),e}return a}async function tI(e,t,a,n,r){var i,s,o,l;if(!t.overlayRefs)return n;if(n.match||n.dimensionMismatch)return a&&await tN(a),n;let c=(i=t,s=a,i.currentOverlayOut?i.currentOverlayOut:i.out?.kind==="path"?{kind:"path",path:tM(s??i.out.path)}:i.out?.kind==="downloadableArtifact"?{kind:"downloadableArtifact",...i.out.clientPath?{clientPath:tM(i.out.clientPath)}:{},...i.out.fileName?{fileName:tM(i.out.fileName)}:{}}:void 0),d=await eG(e,c,{field:"currentOverlayPath",ext:".png"});try{let a=await tR(e,t,d.path,{overlayRefs:!0,...tS(t)}),i=await d.publish();return i&&r.push(i),{...n,currentOverlayPath:a.path??d.path,...a.overlayRefs?{currentOverlayRefCount:a.overlayRefs.length}:{},...n.regions&&a.overlayRefs?{regions:(o=n.regions,l=a.overlayRefs,o.map(e=>{var t,a;let n,r=(t=e,a=l,n=tk(t.rect),a.map(e=>{var a,r;let i,s,o,l,c=e.overlayRect,d=(a=t.rect,r=c,i=Math.max(a.x,r.x),s=Math.max(a.y,r.y),o=Math.min(a.x+a.width,r.x+r.width),l=Math.min(a.y+a.height,r.y+r.height),o<=i||l<=s?0:(o-i)*(l-s));return d<=0?null:{ref:e.ref,...e.label?{label:e.label}:{},rect:c,overlayCoveragePercentage:tx(d/tk(c)),regionCoveragePercentage:tx(d/n)}}).filter(e=>null!==e).sort((e,t)=>{let a=t.regionCoveragePercentage-e.regionCoveragePercentage;return 0!==a?a:t.overlayCoveragePercentage-e.overlayCoveragePercentage}).slice(0,3).map(e=>({ref:e.ref,...e.label?{label:e.label}:{},rect:e.rect,regionCoveragePercentage:e.regionCoveragePercentage})));return r.length>0?{...e,currentOverlayMatches:r}:e}))}:{}}}catch(e){throw await d.cleanup?.(),e}}async function tR(e,t,a,n={}){if(!e.backend.captureScreenshot)throw new b("UNSUPPORTED_OPERATION","screenshot is not supported by this backend");return await e.backend.captureScreenshot({session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata},a,n)??{}}function tS(e){return e.surface?{surface:e.surface}:{}}function tM(e){let t=d.extname(e),a=t?e.slice(0,-t.length):e;return`${a}.current-overlay${t||".png"}`}async function tN(e){try{await l.unlink(tM(e))}catch(e){var t;if(!("object"==typeof(t=e)&&null!==t&&"code"in t&&"ENOENT"===t.code))throw e}}function tO(e){return"live"===e.kind}let tL={application:"application",navigationbar:"navigation-bar",tabbar:"tab-bar",button:"button",imagebutton:"button",link:"link",cell:"cell",statictext:"text",checkedtextview:"text",textfield:"text-field",edittext:"text-field",textarea:"text-view",switch:"switch",slider:"slider",image:"image",imageview:"image",webview:"webview",framelayout:"group",linearlayout:"group",relativelayout:"group",constraintlayout:"group",viewgroup:"group",view:"group",listview:"list",recyclerview:"list",collectionview:"collection",searchfield:"search",segmentedcontrol:"segmented-control",group:"group",window:"window",checkbox:"checkbox",radio:"radio",menuitem:"menu-item",toolbar:"toolbar",scrollarea:"scroll-area",scrollview:"scroll-area",nestedscrollview:"scroll-area",table:"table"};function tP(e,t={}){let a=[],n=[];for(let r of e){let e=r.depth??0,i=r.label?.trim()||r.value?.trim()||r.identifier?.trim()||"",s=tU(r.type??"Element");if("group"===s&&!i)continue;for(;a.length>0&&e<=a[a.length-1];)a.pop();let o=a.length;a.push(e),n.push({node:r,depth:o,type:s,text:tE(r,o,!1,s,t)})}return n}function tE(e,t,a,n,r={}){var i,s,o,l,c,d,p,u;let h,m=n??tU(e.type??"Element"),f=V(e,m),g=(i=e,s=m,o=r,l=f,o.summarizeTextSurfaces&&l.shouldSummarize&&function(e,t,a){let n=P(e.label);if(n&&n!==a)return n;let r=P(e.identifier);if(r&&!t_(r)&&r!==a)return r;switch(t){case"text":case"text-view":return"Text view";case"text-field":return"Text field";case"search":return"Search field";default:return""}}(i,s,l.text)||tC(i,s)),b=" ".repeat(t),w=e.ref?`@${e.ref}`:"",y=(c=e,d=m,p=r,u=f,h=[],(!1===c.enabled&&h.push("disabled"),p.summarizeTextSurfaces)?(!0===c.selected&&h.push("selected"),!0===c.focused&&h.push("focused"),tT(d)&&h.push("editable"),function(e,t){if("scroll-area"===t)return!0;let a=(e.type??"").toLowerCase(),n=`${e.role??""} ${e.subrole??""}`.toLowerCase();return a.includes("scroll")||n.includes("scroll")}(c,d)&&h.push("scrollable"),h.push(...c.presentationHints??[]),u.shouldSummarize&&(h.push(`preview:"${_(u.text).replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`),h.push("truncated")),t$(h)):h).map(e=>` [${e}]`).join(""),v=g?` "${g}"`:"";return a?`${b}${w} [${m}]${y}`.trimEnd():`${b}${w} [${m}]${v}${y}`.trimEnd()}function tC(e,t){var a,n;let r,i=e.label?.trim();if(i&&(a=t,n=i,("scroll-area"===a||"list"===a||"collection"===a||"table"===a)&&(r=n.trim().toLowerCase())&&/^(vertical|horizontal)\s+scroll\s+bar(?:,?\s*\d+\s+pages?)?$/.test(r)))return"";let s=e.value?.trim();if(tT(t)){if(s)return s;if(i)return i}else if(i)return i;if(s)return s;let o=e.identifier?.trim();return!o||t_(o)&&("group"===t||"image"===t||"list"===t||"collection"===t)?"":o}function tU(e){var t;let a=e.replace(/XCUIElementType/gi,"").toLowerCase(),n=e.includes(".")&&(e.startsWith("android.")||e.startsWith("androidx.")||e.startsWith("com."));return(a.includes(".")&&(a=a.replace(/^android\.widget\./,"").replace(/^android\.view\./,"").replace(/^android\.webkit\./,"").replace(/^androidx\./,"").replace(/^com\.google\.android\./,"").replace(/^com\.android\./,""),n&&a.includes(".")&&(a=a.slice(a.lastIndexOf(".")+1))),"textview"===a)?n?"text":"text-view":(t=a,(Object.prototype.hasOwnProperty.call(tL,t)?tL[t]:void 0)||a||"element")}function tT(e){return"text-field"===e||"text-view"===e||"search"===e}function t_(e){return/^[\w.]+:id\/[\w.-]+$/i.test(e)}function t$(e){return[...new Set(e)]}function tF(e,t){let a=tU(e.type??"Element"),n=tC(e,a),r=!1===e.enabled?"disabled":"enabled",i=!0===e.selected?"selected":"unselected",s=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),a,n,r,i,s].join("|")}function tB(e,t){return t.flatten?e.map(e=>({text:tE(e,0,!1),comparable:tF(e,0)})):tP(e).map(e=>({text:e.text,comparable:tF(e.node,e.depth)}))}function tq(e,t){return e.get(t)??0}function tG(e){return e.map(e=>({index:e.index,depth:e.depth,parentIndex:e.parentIndex,type:e.type,role:e.role,subrole:e.subrole,label:e.label,value:e.value,identifier:e.identifier,enabled:e.enabled,selected:e.selected,focused:e.focused,hittable:e.hittable,rect:e.rect,bundleId:e.bundleId,appName:e.appName,windowTitle:e.windowTitle,surface:e.surface,hiddenContentAbove:e.hiddenContentAbove,hiddenContentBelow:e.hiddenContentBelow}))}function tj(e){return"text"===e||"label"===e||"any"===e}function tV(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}function tX(e){return e.clock?.now()??Date.now()}async function tY(e,t){e.clock?await e.clock.sleep(t):await new Promise(e=>setTimeout(e,t))}let tK=async(e,t)=>{var a;let n,r,i=await tH(e,t),s=function(e){var t,a,n,r,i;let{previous:s,current:o,options:l,identity:c}=e;if(!0===l.forceFull||!0===l.raw||!s||!1===s.comparisonSafe||!1===o.comparisonSafe||(t=s,a=o,n=c,t.backend&&a.backend&&t.backend!==a.backend||n?.previousAppBundleId&&n.currentAppBundleId&&n.previousAppBundleId!==n.currentAppBundleId)||!s.presentationKey||s.presentationKey!==o.presentationKey||(r=s,i=o,r.truncated!==i.truncated||JSON.stringify(tG(r.nodes))!==JSON.stringify(tG(i.nodes))))return;let d=l.scope?.trim();return{ageMs:Math.max(0,o.createdAt-s.createdAt),nodeCount:o.nodes.length,...!0===l.interactiveOnly?{interactiveOnly:!0}:{},...d?{scope:d}:{}}}({previous:i.session?.snapshot,current:i.snapshot,options:t,identity:{previousAppBundleId:i.session?.appBundleId,currentAppBundleId:i.result.appBundleId??i.session?.appBundleId}});return await e.sessions.set(tJ(t.session,i)),{nodes:i.snapshot.nodes,truncated:i.snapshot.truncated??!1,visibility:function(e){var t;let{nodes:a,backend:n,snapshotRaw:r}=e;if(r||"macos-helper"===(t=n)||"linux-atspi"===t)return{partial:!1,visibleNodeCount:a.length,totalNodeCount:a.length,reasons:[]};let i=ea(a),s=new Set;return i.hiddenCount>0&&s.add("offscreen-nodes"),i.nodes.some(e=>e.hiddenContentAbove)&&s.add("scroll-hidden-above"),i.nodes.some(e=>e.hiddenContentBelow)&&s.add("scroll-hidden-below"),{partial:s.size>0,visibleNodeCount:i.nodes.length,totalNodeCount:a.length,reasons:[...s]}}({nodes:i.snapshot.nodes,backend:i.snapshot.backend,snapshotRaw:t.raw}),...i.result.androidSnapshot?{androidSnapshot:i.result.androidSnapshot}:{},...i.warnings.length>0?{warnings:i.warnings}:{},...s?{unchanged:s}:{},...(n=(a=i).result.appName??a.session?.appName,r=a.result.appBundleId??a.session?.appBundleId,{...n||r?{appName:n??r}:{},...r?{appBundleId:r}:{}})}},tz=async(e,t)=>{let a=await tH(e,t),n=!0===t.interactiveOnly,r=a.session?.snapshot,i=tJ(t.session,a);if(!r){let t=function(e,t={}){return tB(e,t).length}(a.snapshot.nodes,{flatten:n});return await e.sessions.set(i),{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:t},lines:[],...a.warnings.length>0?{warnings:a.warnings}:{}}}let s=function(e,t,a={}){let n=function(e,t){let a=e.length,n=t.length,r=a+n,i=new Map,s=[];i.set(1,0);for(let o=0;o<=r;o+=1){s.push(new Map(i));for(let r=-o;r<=o;r+=2){let l=r===-o||r!==o&&tq(i,r-1)<tq(i,r+1)?tq(i,r+1):tq(i,r-1)+1,c=l-r;for(;l<a&&c<n&&e[l].comparable===t[c].comparable;)l+=1,c+=1;if(i.set(r,l),l>=a&&c>=n)return function(e,t,a,n,r){let i=[],s=n,o=r;for(let n=e.length-1;n>=0;n-=1){let r=e[n],l=s-o,c=l===-n||l!==n&&tq(r,l-1)<tq(r,l+1)?l+1:l-1,d=tq(r,c),p=d-c;for(;s>d&&o>p;)i.push({kind:"unchanged",text:a[o-1].text}),s-=1,o-=1;if(0===n)break;s===d?(i.push({kind:"added",text:a[p].text}),o=p):(i.push({kind:"removed",text:t[d].text}),s=d)}return i.reverse(),i}(s,e,t,a,n)}}return[]}(tB(e,a),tB(t,a)),r={additions:0,removals:0,unchanged:0};for(let e of n)"added"===e.kind&&(r.additions+=1),"removed"===e.kind&&(r.removals+=1),"unchanged"===e.kind&&(r.unchanged+=1);return{summary:r,lines:n}}(r.nodes,a.snapshot.nodes,{flatten:n});return await e.sessions.set(i),{mode:"snapshot",baselineInitialized:!1,summary:s.summary,lines:s.lines,...a.warnings.length>0?{warnings:a.warnings}:{}}};async function tH(e,t){var a,n,r,i,s,o;let l,c,d,p;if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let u=t.session??"default",m=await e.sessions.get(u),f=await e.backend.captureSnapshot({session:u,requestId:t.requestId,appId:m?.appId,appBundleId:m?.appBundleId,signal:t.signal??e.signal,metadata:t.metadata},{interactiveOnly:t.interactiveOnly,compact:t.compact,depth:t.depth,scope:t.scope,raw:t.raw}),g=(n=f,r=e,a=n.snapshot?n.snapshot:{nodes:n.nodes??[],truncated:n.truncated,backend:n.backend,createdAt:tX(r)},a.presentationKey?a:{...a,presentationKey:h(t)}),w=tX(e);return{snapshot:g,result:f,session:m,warnings:((l=[...(i={result:f,snapshot:g,options:t,session:m,capturedAt:g.createdAt??w,runtimeNow:w}).result.warnings??[]]).push(...function(e){let t=e.result.analysis;if("android"!==e.snapshot.backend||!0!==e.options.interactiveOnly||e.snapshot.nodes.length>0||!t||(t.rawNodeCount??0)<12)return[];let a=[`Interactive snapshot is empty after filtering ${t.rawNodeCount} raw Android nodes. Likely causes: the app content is not accessibility-visible yet, a transient route change, or depth/filter options hid the target.`];return"number"==typeof e.options.depth&&"number"==typeof t.maxDepth&&t.maxDepth>=e.options.depth+2&&a.push(`Interactive output is empty at depth ${e.options.depth}; retry without -d.`),a}(i)),(c=function(e){if(e?.backend!=="uiautomator-dump")return;let t=e.fallbackReason?` Reason: ${e.fallbackReason}`:"";return`Android snapshot helper unavailable; using stock UIAutomator dump, which can time out on busy React Native UIs.${t}`}(i.result.androidSnapshot))&&l.push(c),(d=function(e){var t,a,n,r;let i,s,o,l,c,d,p,u=(i=(t=e).map(e=>[e.label,e.value,e.identifier,e.type,e.role].filter(Boolean).join(" ")).join("\n").toLowerCase(),s=t1(t,tQ),o=t1(t,tZ),l=t1(t,t0),c=(a=i,/\b[\w.$<>/-]+\.(?:tsx?|jsx?):\d+(?::\d+)?\b/.test(a)||/\b[\w.$<>/-]+\.(?:tsx?|jsx?)\s+\(\d+:\d+\)/.test(a)),d=s.length>0||o.length>0,p=/\b(redbox|runtime error|reload js|copy stack|component stack|call stack)\b/.test(i)||c&&d,{detected:(n=i,/\b(logbox|redbox|reload js|copy stack|component stack|call stack|runtime error|open debugger to view warnings)\b/.test(n)||l.length>0||c&&d),redBox:p,dismissRefs:s,minimizeRefs:o,collapsedRefs:l});if(u.detected){return u.redBox?(r=u.minimizeRefs).length>0?`Possible React Native warning/error overlay detected. React Native RedBox stack overlay detected. Minimize before continuing: press ${t2(r)}, then snapshot -i and report the error in the final summary. Prefer Minimize over Dismiss when the error may re-render immediately.`:"Possible React Native warning/error overlay detected. React Native RedBox stack overlay detected. Do not press Dismiss if the error may re-render immediately; use screenshot --overlay-refs if visual evidence is required and report the error in the final summary.":u.dismissRefs.length>0?`Possible React Native warning/error overlay detected. Dismiss before continuing: press ${t2(u.dismissRefs)}, then snapshot -i and report the warning/error in the final summary. Use screenshot --overlay-refs only if visual evidence is required.`:u.collapsedRefs.length>0?`Possible React Native warning/error overlay detected. Warning banner detected. Press ${t2(u.collapsedRefs)} to expand or clear it; if Dismiss/Close appears, press it, then snapshot -i and report the warning/error in the final summary.`:"Possible React Native warning/error overlay detected. Dismiss visible Dismiss/Close before continuing, then snapshot -i and report the warning/error in the final summary. Use screenshot --overlay-refs only if visual evidence is required."}}(i.snapshot.nodes))&&l.push(d),(p=function(e){var t,a;let n=e.session?.snapshot,r=!!n&&[e.capturedAt,e.runtimeNow].some(e=>{let t=e-n.createdAt;return t>=0&&t<=2e3});if(!e.result.freshness&&n&&r&&(t=n.nodes.length,a=e.snapshot.nodes.length,!(t<12)&&a<=Math.floor(.2*t)))return tW}(i))&&l.push(p),l.push(...(s=i.result.freshness,o=i.snapshot.backend,s?.staleAfterRetries&&"android"===o?"stuck-route"===s.reason?[`Recent ${s.action} was followed by a nearly identical snapshot after ${s.retryCount} automatic retr${1===s.retryCount?"y":"ies"}. If you expected navigation or submit, the tree may still be stale. Use screenshot as visual truth, wait briefly, then re-snapshot once.`]:"sharp-drop"===s.reason?[tW]:[]:[])),Array.from(new Set(l)))}}function tJ(e,t){let a=t.session?.name??e??"default";return{...t.session??{name:a},name:a,snapshot:t.snapshot,appName:t.result.appName??t.session?.appName,appBundleId:t.result.appBundleId??t.session?.appBundleId}}let tW="Recent snapshots dropped sharply in node count, which suggests stale or mid-transition UI. Use screenshot as visual truth, wait briefly, then re-snapshot once.";function tQ(e){return"dismiss"===e||"close"===e}function tZ(e){return/^minimi[sz]e$/.test(e)}function t0(e){return e.includes("open debugger to view warnings")||/^!,\s+/.test(e)||/^(warn|warning|error):\s+/.test(e)||/\b(?:possible\s+)?unhandled (?:promise )?rejection\b/.test(e)||e.includes("getsnapshot should be cached to avoid an infinite loop")||e.includes('unique "key" prop')||e.includes("unique 'key' prop")||e.includes("virtualizedlists should never be nested")||e.includes("failed prop type")}function t1(e,t){let a=[];for(let n of e)n.ref&&t((n.label??"").trim().toLowerCase())&&a.push(n.ref);return a}function t2(e){return e.slice(0,3).map(e=>`@${e}`).join(", ")}function t5(e){return["visible","hidden","exists","editable","selected","text"].includes(e)}function t3(e){let{predicate:t,node:a,nodes:n,expectedText:r,platform:i}=e,s=E(a),o=T(a,i),l=!0===a.selected,c="text"===t?U(a):function(e,t){if(!0===e.hittable)return!0;if(t4(e.rect))return function(e,t){return ei(e,t)}(e,t);if(e.rect)return!1;let a=function(e,t){let a=new Map(t.map(e=>[e.index,e])),n=e,r=new Set;for(;"number"==typeof n.parentIndex&&!r.has(n.index);){r.add(n.index);let e=a.get(n.parentIndex);if(!e)break;if(function(e){let t=K(e.type??"");return!(t.includes("application")||t.includes("window")||t.includes("scrollview")||t.includes("tableview")||t.includes("collectionview"))&&"table"!==t&&"list"!==t&&"listview"!==t&&(!0===e.hittable||t4(e.rect))}(e))return e;n=e}return null}(e,t);return!!a&&(!0===a.hittable||!!t4(a.rect)&&function(e,t){return ei(e,t)}(a,t))}(a,n),d=!1;switch(t){case"visible":d=c;break;case"hidden":d=!c;break;case"editable":d=o;break;case"selected":d=l;break;case"text":d=s===(r??"")}let p="text"===t?`expected="${r??""}" actual="${s}"`:`actual=${JSON.stringify({visible:c,editable:o,selected:l})}`;return{pass:d,actualText:s,details:p}}function t4(e){return!!(e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.width)&&Number.isFinite(e.height)&&e.width>0&&e.height>0)}async function t8(e,t){let a=t??"default",n=await e.sessions.get(a);if(!n)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");if(!n.snapshot)throw new b("INVALID_ARGS","No snapshot in session. Run snapshot first.");return{sessionName:a,session:n,snapshot:n.snapshot}}async function t6(e,t,a={updateSession:!0}){if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let n=t.session??"default",r=await e.sessions.get(n),i=await e.backend.captureSnapshot(tV(e,t),{interactiveOnly:!1,compact:!1,depth:t.depth,scope:a.scope??t.scope,raw:t.raw}),s=i.snapshot??{nodes:i.nodes??[],truncated:i.truncated,backend:i.backend,createdAt:tX(e)};return a.updateSession&&r&&await e.sessions.set({...r,snapshot:s}),{sessionName:n,session:r,snapshot:s}}async function t7(e,t,a){if(e.backend.readText){let n=await e.backend.readText(tV(e,{session:t.sessionName}),a);if(n.text.trim())return n.text}return X(a)}let t9=async(e,t)=>{let a=t.locator??"any";if(!t.query)throw new b("INVALID_ARGS","find requires a value");if("wait"===t.action)return await al(e,t,a);let n=await t6(e,t,{updateSession:!0,scope:tj(a)?t.query:void 0}),r=H(n.snapshot.nodes,a,t.query,{requireRect:!1}).matches[0];if(!r)throw new b("COMMAND_FAILED","find did not match any element");if("exists"===t.action)return{kind:"found",found:!0};let i=`@${r.ref}`;return"get_attrs"===t.action?{kind:"attrs",ref:i,node:r}:{kind:"text",ref:i,text:await t7(e,n,r),node:r}},ae=async(e,t)=>{if("ref"===t.target.kind){let a=await t8(e,t.session),n=function(e,t,a){let n=p(t);if(!n)throw new b("INVALID_ARGS",a.invalidRefMessage);let r=m(e,n)??(a.fallbackLabel.length>0?G(e,a.fallbackLabel):null);if(!r)throw new b("COMMAND_FAILED",a.notFoundMessage);return{ref:n,node:r}}(a.snapshot.nodes,t.target.ref,{fallbackLabel:t.target.fallbackLabel??"",invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${t.target.ref} not found`}),r=F(n.node,e.backend.platform,{action:"get"}),i={kind:"ref",ref:`@${n.ref}`};return"attrs"===t.property?{kind:"attrs",target:i,node:n.node,selectorChain:r}:{kind:"text",target:i,text:await t7(e,a,n.node),node:n.node,selectorChain:r}}let a=await au(e,t,t.session??"default",{selector:t.target.selector,disambiguateAmbiguous:"text"===t.property}),n=F(a.node,e.backend.platform,{action:"get"});if("attrs"===t.property)return{kind:"attrs",target:{kind:"selector",selector:a.selector},node:a.node,selectorChain:n};let r=await t7(e,a.capture,a.node);return{kind:"text",target:{kind:"selector",selector:a.selector},text:r,node:a.node,selectorChain:n}},at=async(e,t)=>{let a=await ae(e,{...t,property:"text",target:t.target});if("text"!==a.kind)throw new b("COMMAND_FAILED","getText returned non-text result");return a},aa=async(e,t)=>{let a=await ae(e,{...t,property:"attrs",target:t.target});if("attrs"!==a.kind)throw new b("COMMAND_FAILED","getAttrs returned non-attrs result");return a},an=async(e,t)=>{if(!t5(t.predicate))throw new b("INVALID_ARGS","is requires predicate: visible|hidden|exists|editable|selected|text");if("text"===t.predicate&&!t.expectedText)throw new b("INVALID_ARGS","is text requires expected text value");let a=await t6(e,t,{updateSession:!0}),n=C(t.selector);if("exists"===t.predicate){let r=B(a.snapshot.nodes,n,{platform:e.backend.platform});if(!r)throw new b("COMMAND_FAILED",Y(n,[],{unique:!1}));return{predicate:t.predicate,pass:!0,selector:r.selector.raw,matches:r.matches,selectorChain:n.selectors.map(e=>e.raw)}}let r=q(a.snapshot.nodes,n,{platform:e.backend.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:!1});if(!r)throw new b("COMMAND_FAILED",Y(n,[],{unique:!0}));let i=t3({predicate:t.predicate,node:r.node,nodes:a.snapshot.nodes,expectedText:t.expectedText,platform:e.backend.platform});if(!i.pass)throw new b("COMMAND_FAILED",`is ${t.predicate} failed for selector ${r.selector.raw}: ${i.details}`);return{predicate:t.predicate,pass:!0,selector:r.selector.raw,..."text"===t.predicate?{text:i.actualText}:{},selectorChain:n.selectors.map(e=>e.raw)}},ar=async(e,t)=>await an(e,{...t,predicate:"visible",selector:t.target.selector}),ai=async(e,t)=>await an(e,{...t,predicate:"hidden",selector:t.target.selector}),as=async(e,t)=>{if("sleep"===t.target.kind)return await tY(e,t.target.durationMs),{kind:"sleep",waitedMs:t.target.durationMs};if("ref"===t.target.kind){let a=await t8(e,t.session),n=p(t.target.ref);if(!n)throw new b("INVALID_ARGS",`Invalid ref: ${t.target.ref}`);let r=m(a.snapshot.nodes,n),i=r?j(r,a.snapshot.nodes):void 0;if(!i)throw new b("COMMAND_FAILED",`Ref ${t.target.ref} not found or has no label`);return await ad(e,t,i,t.target.timeoutMs)}if("selector"===t.target.kind)return await ac(e,t,t.target.selector,t.target.timeoutMs);if(!t.target.text)throw new b("INVALID_ARGS","wait requires text");return await ad(e,t,t.target.text,t.target.timeoutMs)},ao=async(e,t)=>{let a=await as(e,{...t,target:{kind:"text",text:t.text,timeoutMs:t.timeoutMs}});if("text"!==a.kind)throw new b("COMMAND_FAILED","waitForText returned non-text result");return a};async function al(e,t,a){let n=t.timeoutMs??1e4,r=tX(e);for(;tX(e)-r<n;){if(H((await t6(e,t,{updateSession:!0,scope:tj(a)?t.query:void 0})).snapshot.nodes,a,t.query,{requireRect:!1}).matches[0])return{kind:"found",found:!0,waitedMs:tX(e)-r};await tY(e,300)}throw new b("COMMAND_FAILED","find wait timed out")}async function ac(e,t,a,n){let r=n??1e4,i=tX(e),s=C(a);for(;tX(e)-i<r;){let a=B((await t6(e,t,{updateSession:!0})).snapshot.nodes,s,{platform:e.backend.platform});if(a)return{kind:"selector",selector:a.selector.raw,waitedMs:tX(e)-i};await tY(e,300)}throw new b("COMMAND_FAILED",`wait timed out for selector: ${a}`)}async function ad(e,t,a,n){let r=n??1e4,i=tX(e);for(;tX(e)-i<r;){if(e.backend.findText?(await e.backend.findText(tV(e,t),a)).found:await ap(e,t,a))return{kind:"text",text:a,waitedMs:tX(e)-i};await tY(e,300)}throw new b("COMMAND_FAILED",`wait timed out for text: ${a}`)}async function ap(e,t,a){return!!G((await t6(e,t,{updateSession:!0})).snapshot.nodes,a)}async function au(e,t,a,n){let r=await t6(e,{...t,session:a},{updateSession:!0}),i=C(n.selector),s=q(r.snapshot.nodes,i,{platform:e.backend.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:n.disambiguateAmbiguous});if(!s)throw new b("COMMAND_FAILED",Y(i,[],{unique:!0}));return{capture:r,node:s.node,selector:s.selector.raw,ref:`@${s.node.ref}`}}function ah(e){let t=am(e);if(!t)return null;let a=u(t);return Number.isFinite(a.x)&&Number.isFinite(a.y)?a:null}function am(e){if(!e)return null;let t=Number(e.x),a=Number(e.y),n=Number(e.width),r=Number(e.height);return Number.isFinite(t)&&Number.isFinite(a)&&Number.isFinite(n)&&Number.isFinite(r)&&!(n<0)&&!(r<0)?{x:t,y:a,width:n,height:r}:null}let af=["button","link","menuitem","tabitem","textfield","searchfield","securetextfield","checkbox","radio","switch","cell"];function ag(e,t){var a;let n=function(e,t){let a=am(t.rect);if(!a)return null;let n=t,r=new Set;for(;!r.has(n.ref);){r.add(n.ref);let t=e.filter(e=>{if(e.parentIndex!==n.index||!e.hittable)return!1;let t=am(e.rect);return!!t&&aw(t,a)});if(1!==t.length)break;n=t[0]}return n===t?null:n}(e,t);if(n?.rect&&ah(n.rect))return{node:n,reason:"same-rect-descendant"};if([(a=t).type,a.role,a.subrole].map(e=>K(e??"")).some(ab)&&t.rect&&ah(t.rect))return{node:t,reason:"semantic-target"};let r=$(e,t);return r?.rect&&ah(r.rect)?!function(e,t,a){var n,r,i,s;let o,l,c,d=am(e.rect),p=am(t.rect);if(!d||!p)return!1;let h=function(e,t){let a=u(t),n=e.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}).map(e=>am(e.rect)).filter(e=>null!==e);if(0===n.length)return null;let r=n.filter(e=>J(e,a.x,a.y));return W(r.length>0?r:n)}(a,d);return!!h&&(n=p,r=h,o=(i=n,s=r,Math.max(0,Math.min(i.x+i.width,s.x+s.width)-Math.max(i.x,s.x))*Math.max(0,Math.min(i.y+i.height,s.y+s.height)-Math.max(i.y,s.y))),l=n.width*n.height,c=r.width*r.height,!(o<=0)&&!(l<=0)&&!(c<=0)&&!!(o/c>=.9)&&!!(o/l>=.8))&&!aw(d,p)}(t,r,e)?{node:r,reason:"hittable-ancestor"}:{node:t,reason:"overly-broad-ancestor"}:{node:t,reason:"original"}}function ab(e){return"tab"===e||af.some(t=>e.includes(t))}function aw(e,t){return .5>=Math.abs(e.x-t.x)&&.5>=Math.abs(e.y-t.y)&&.5>=Math.abs(e.width-t.width)&&.5>=Math.abs(e.height-t.height)}async function ay(e,t,a){if(await ak(e,t,a.action),"point"===t.target.kind)return{kind:"point",point:{x:t.target.x,y:t.target.y}};if("ref"===t.target.kind){let n=await aA(e,t,t.target),r=n.resolved,i=a.promoteToHittableAncestor?ag(n.snapshot.nodes,r.node).node:r.node;return function(e,t,a,n){let r=e.rect?es(e,t):null;if(!(!e.rect||!r||ei(e,t)))throw new b("COMMAND_FAILED",`Ref ${a} is off-screen and not safe to ${n}`,{reason:"offscreen_ref",ref:p(a),rect:e.rect,viewport:r,hint:`Use scroll with the direction from the off-screen summary, take a fresh snapshot, then retry ${n} with the new ref or a selector.`})}(i,n.snapshot.nodes,t.target.ref,a.action),{kind:"ref",point:aI(i,`Ref ${t.target.ref} not found or has invalid bounds`),target:{kind:"ref",ref:`@${r.ref}`},node:i,selectorChain:F(i,e.backend.platform,{action:"fill"===a.action?"fill":"click"}),refLabel:j(i,n.snapshot.nodes)}}let n=await av(e,t,a.requireInteractive),r=C(t.target.selector),i=q(n.snapshot.nodes,r,{platform:e.backend.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0});if(!i||!i.node.rect)throw new b("COMMAND_FAILED",Y(r,i?.diagnostics??[],{unique:!0}));let s=a.promoteToHittableAncestor?ag(n.snapshot.nodes,i.node).node:i.node;return{kind:"selector",point:aI(s,`Selector ${i.selector.raw} resolved to invalid bounds`),target:{kind:"selector",selector:i.selector.raw},node:s,selectorChain:F(s,e.backend.platform,{action:"fill"===a.action?"fill":"click"}),refLabel:j(s,n.snapshot.nodes)}}async function av(e,t,a){if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let n=t.session??"default",r=await e.sessions.get(n);if(!r)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");let i=await e.backend.captureSnapshot(tV(e,t),{interactiveOnly:a,compact:a}),s=i.snapshot??{nodes:i.nodes??[],truncated:i.truncated,backend:i.backend,createdAt:tX(e)};return await e.sessions.set({...r,snapshot:s}),{snapshot:s}}async function ak(e,t,a){if("macos"!==e.backend.platform)return;let n=await ax(e,t);if(("desktop"===n||"menubar"===n)&&("menubar"!==n||"click"!==a&&"press"!==a))throw new b("UNSUPPORTED_OPERATION",`${a} is not supported on macOS ${n} sessions yet. Open an app session to act, or use the ${n} surface to inspect.`)}async function ax(e,t){let a=await e.sessions.get(t.session??"default");return a?.metadata?.surface}async function aA(e,t,a){let n=t.session??"default",r=await e.sessions.get(n);if(!r)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");if(!r.snapshot)throw new b("INVALID_ARGS","No snapshot in session. Run snapshot first.");let i=a.fallbackLabel??"",s=aD(r.snapshot.nodes,a.ref,{fallbackLabel:i,requireRect:!0});if(s)return{snapshot:r.snapshot,resolved:s};let o=await av(e,t,!0),l=aD(o.snapshot.nodes,a.ref,{fallbackLabel:i,requireRect:!0});if(!l)throw new b("COMMAND_FAILED",`Ref ${a.ref} not found or has no bounds`);return{...o,resolved:l}}function aD(e,t,a){let n=p(t);if(!n)throw new b("INVALID_ARGS",`Invalid ref: ${t}`);let r=m(e,n);if(aR(r,a.requireRect))return{ref:n,node:r};let i=a.fallbackLabel.length>0?G(e,a.fallbackLabel):null;return aR(i,a.requireRect)?{ref:n,node:i}:null}function aI(e,t){if(!e.rect)throw new b("COMMAND_FAILED",t);let a=u(e.rect);if(!Number.isFinite(a.x)||!Number.isFinite(a.y))throw new b("COMMAND_FAILED",t);return a}function aR(e,t){if(!e)return!1;if(!t)return!0;if(!e.rect)return!1;let{x:a,y:n,width:r,height:i}=e.rect;if(!Number.isFinite(Number(a))||!Number.isFinite(Number(n))||!Number.isFinite(Number(r))||!Number.isFinite(Number(i))||0>Number(r)||0>Number(i))return!1;let s=u(e.rect);return Number.isFinite(s.x)&&Number.isFinite(s.y)}async function aS(e,t){let a=t.target??{kind:"viewport"};return"viewport"===a.kind?(await ak(e,t,"scroll"),{kind:"viewport"}):await ay(e,{...t,target:a},{action:"scroll",requireInteractive:!1,promoteToHittableAncestor:!1})}async function aM(e,t){if(t.from){var a;if("x"in(a=t.from)&&"y"in a)return await ak(e,t,"swipe"),{point:aO(t.from,"from")};let n=await ay(e,{...t,target:t.from},{action:"swipe",requireInteractive:!1,promoteToHittableAncestor:!1});return{point:n.point,target:n}}if(!t.direction)throw new b("INVALID_ARGS","swipe requires from+to or a direction");return await ak(e,t,"swipe"),{point:u(function(e){let t=e.filter(t=>ei(t,e)).map(e=>e.rect).filter(aP),a=t.length>0?t:e.map(e=>e.rect).filter(aP);if(0===a.length)throw new b("COMMAND_FAILED","Cannot infer viewport for directional swipe");let n=Math.min(...a.map(e=>e.x)),r=Math.min(...a.map(e=>e.y));return{x:n,y:r,width:Math.max(...a.map(e=>e.x+e.width))-n,height:Math.max(...a.map(e=>e.y+e.height))-r}}((await av(e,t,!1)).snapshot.nodes)),target:{kind:"viewport"}}}function aN(e,t){switch(e){case"up":case"down":case"left":case"right":return e;default:throw new b("INVALID_ARGS",`${t} must be up, down, left, or right`)}}function aO(e,t){let a=Number(e.x),n=Number(e.y);if(!Number.isFinite(a)||!Number.isFinite(n))throw new b("INVALID_ARGS",`${t} point requires finite x and y`);return{x:a,y:n}}function aL(e,t){if(!Number.isFinite(e)||e<=0)throw new b("INVALID_ARGS",`${t} must be a positive number`);return e}function aP(e){return!!(e&&e.width>0&&e.height>0)}function aE(e){return e&&"object"==typeof e?e:void 0}async function aC(e,t,a){let n=await ay(e,t,{action:a,requireInteractive:!0,promoteToHittableAncestor:!0});if(!e.backend.tap)throw new b("UNSUPPORTED_OPERATION","tap is not supported by this backend");let r=aU(await e.backend.tap(tV(e,t),n.point,{button:t.button,count:t.count,intervalMs:t.intervalMs,holdMs:t.holdMs,jitterPx:t.jitterPx,doubleTap:t.doubleTap}));return{...n,...r?{backendResult:r}:{}}}function aU(e){return e&&"object"==typeof e?e:void 0}function aT(e,t){if(void 0!==e)return a_(e,t)}function a_(e,t){let a=e?.trim();if(!a)throw new b("INVALID_ARGS",`${t} must be a non-empty string`);return a}function a$(e){return!!(e&&"object"==typeof e)}function aF(e){return e&&"object"==typeof e?e:void 0}let aB=/^[A-Za-z0-9_.:-]{1,64}$/;async function aq(e,t){if(!t||"object"!=typeof t)throw new b("INVALID_ARGS","apps.push requires an input");if("json"===t.kind)return aG(t.payload,"apps.push JSON payload",8192),{backendInput:{kind:"json",payload:t.payload},inputKind:"json"};let a=await eq(e,t,{usage:"apps.push",field:"input"});return{backendInput:{kind:"file",path:a.path},inputKind:"file",...a.cleanup?{cleanup:a.cleanup}:{}}}function aG(e,t,a){if(function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new b("INVALID_ARGS",`${t} must be a JSON object`)}(e,t),Buffer.byteLength(function(e,t){try{let a=JSON.stringify(e);if("string"!=typeof a)throw new b("INVALID_ARGS",`${t} must be JSON-serializable`);return a}catch{throw new b("INVALID_ARGS",`${t} must be JSON-serializable`)}}(e,t),"utf8")>a)throw new b("INVALID_ARGS",`${t} exceeds ${a} bytes`)}function aj(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}function aV(e){return e&&"object"==typeof e?e:void 0}async function aX(e,t,a){let n="reinstall"===a?"reinstallApp":"installApp",r=e.backend[n];if(!r)throw new b("UNSUPPORTED_OPERATION",`admin.${a} is not supported by this backend`);let i="app"in t&&void 0!==t.app?a_(t.app,"app"):void 0;if("installFromSource"!==a&&!i)throw new b("INVALID_ARGS",`admin.${a} requires app`);let s=tV(e,t),o=await aY(e,s,t.source);try{var l,c,d,p,u;let t,n,h,m,f,g,b,w,y=await r.call(e.backend,s,{...i?{app:i}:{},source:o.source});return l=a,c=i,d=o.source,p=y,t=aJ(p),n=aH(p,"appName"),h=aH(p,"appId"),m=aH(p,"bundleId"),f=aH(p,"packageName"),g=aH(p,"launchTarget"),b=aH(p,"installablePath"),w=aH(p,"archivePath"),{kind:"reinstall"===l?"appReinstalled":"installFromSource"===l?"appInstalledFromSource":"appInstalled",...c?{app:c}:{},source:d,...h?{appId:h}:{},...n?{appName:n}:{},...m?{bundleId:m}:{},...f?{packageName:f}:{},...g?{launchTarget:g}:{},...b?{installablePath:b}:{},...w?{archivePath:w}:{},...t?{backendResult:t}:{},...D(`${"reinstall"===l?"Reinstalled":"Installed"}: ${n??g??c??(u=d,"path"===u.kind?u.path:"uploadedArtifact"===u.kind?u.id:u.url)}`)}}finally{await o.cleanup?.()}}async function aY(e,t,a){let n=az(a),r=await aK(e,n);try{let a=e.backend.resolveInstallSource?await e.backend.resolveInstallSource(t,r.source):r.source;return{source:az(a),...r.cleanup?{cleanup:r.cleanup}:{}}}catch(e){if(r.cleanup)try{await r.cleanup()}catch{}throw e}}async function aK(e,t){if("url"===t.kind)return{source:t};let a=await eq(e,t,{usage:"admin.install",field:"source"});return{source:{kind:"path",path:a.path},...a.cleanup?{cleanup:a.cleanup}:{}}}function az(e){if(!e||"object"!=typeof e)throw new b("INVALID_ARGS","install source is required");if("path"===e.kind)return{kind:"path",path:a_(e.path,"source.path")};if("uploadedArtifact"===e.kind)return{kind:"uploadedArtifact",id:a_(e.id,"source.id")};if("url"===e.kind){let t=a_(e.url,"source.url");return function(e){let t;try{t=new URL(e)}catch{throw new b("INVALID_ARGS",`Invalid install source URL: ${e}`)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new b("INVALID_ARGS","Install source URL must use http or https")}(t),{kind:"url",url:t}}throw new b("INVALID_ARGS","install source kind must be path, uploadedArtifact, or url")}function aH(e,t){let a=e[t];return"string"==typeof a&&a.length>0?a:void 0}function aJ(e){return e&&"object"==typeof e?e:void 0}function aW(e,t){if("start"===e||"stop"===e)return e;throw new b("INVALID_ARGS",`${t} action must be start or stop`)}function aQ(e,t,a,n){return{kind:"start"===e?n.startKind:n.stopKind,action:e,...a?{artifact:a}:{},backendResult:t,...D("start"===e?n.startMessage:n.stopMessage)}}let aZ=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i,a0=/\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g;function a1(e){var t,a;let n=!1,r=e;return{value:(t=r=(r=(r=(r=(r=r.replaceAll(/(authorization|token|secret|password|passwd|api[-_]?key)=([^&\s]+)/gi,(e,t)=>(n=!0,`${String(t)}=[REDACTED]`))).replaceAll(/("(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)"\s*:\s*")([^"]*)(")/gi,(e,t,a,r)=>(n=!0,`${String(t)}[REDACTED]${String(r)}`))).replaceAll(/\b(Bearer\s+)([^\s",;]+)/gi,(e,t)=>(n=!0,`${String(t)}[REDACTED]`))).replaceAll(/((?:authorization|cookie|token|secret|password|passwd|api[-_]?key)\s*[:=]\s*)([^\s,;&]+)/gi,(e,t)=>(n=!0,`${String(t)}[REDACTED]`))).replaceAll(a0,()=>(n=!0,"[REDACTED]")),a=()=>{n=!0},r=/(https?:\/\/|token|secret|password|authorization|cookie|api[-_]?key)/i.test(t)?t.replaceAll(/https?:\/\/[^\s"'<>)]+/gi,e=>{let t=a2(e);return t?(t.redacted&&a(),t.value):e}):t),redacted:n}}function a2(e){try{let t=new URL(e),a=function(e){let t=!1;for(let a of Array.from(e.searchParams.keys()))aZ.test(a)&&(e.searchParams.set(a,"[REDACTED]"),t=!0);return t}(t);return(t.username||t.password)&&(t.username="REDACTED",t.password="REDACTED",a=!0),{value:t.toString(),redacted:a}}catch{return}}let a5=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i;function a3(e){if(!e)return{redacted:!1};let t=!1,a={};for(let[n,r]of Object.entries(e))if(a5.test(n))a[n]="[REDACTED]",t=!0;else{let e=a7(r,2048);a[n]=e.value??"",t||=e.redacted}return{value:a,redacted:t}}function a4(e){return void 0===e?{redacted:!1}:function(e){try{let t=JSON.parse(e),a=a6(t,a1);return a9(JSON.stringify(a.value),2048,a.redacted)}catch{return}}(e)??a7(e,2048)}function a8(e){return a6(e,e=>a7(e,2048))}function a6(e,t){if(void 0===e)return{redacted:!1};if("string"==typeof e)return t(e);if(!e||"object"!=typeof e)return{value:e,redacted:!1};if(Array.isArray(e)){let a=!1;return{value:e.map(e=>{let n=a6(e,t);return a||=n.redacted,n.value}),redacted:a}}let a=!1,n={};for(let[r,i]of Object.entries(e)){if(a5.test(r)){n[r]="[REDACTED]",a=!0;continue}let e=a6(i,t);n[r]=e.value,a||=e.redacted}return{value:n,redacted:a}}function a7(e,t){if(void 0===e)return{redacted:!1};let a=a1(e);return a9(a.value,t,a.redacted)}function a9(e,t,a){if(void 0===e)return{redacted:a};let n=e;return n.length>t&&(n=`${n.slice(0,t)}...[truncated]`,a=!0),{value:n,redacted:a}}async function ne(e,t){let a=tV(e,t),n=t.session?await e.sessions.get(t.session):void 0;return{...a,...t.appId??n?.appId?{appId:t.appId??n?.appId}:{},...t.appBundleId??n?.appBundleId?{appBundleId:t.appBundleId??n?.appBundleId}:{}}}function nt(e,t,a,n){return{...na(e),...void 0!==e.cursor?{cursor:a_(e.cursor,"cursor")}:{},limit:void 0===e.limit?t:eD(e.limit,n,1,a)}}function na(e){return{...void 0!==e.since?{since:a_(e.since,"since")}:{},...void 0!==e.until?{until:a_(e.until,"until")}:{}}}function nn(e,t,a=50){if(!Array.isArray(e))throw new b("INVALID_ARGS",`${t} must be an array of strings`);if(e.length>a)throw new b("INVALID_ARGS",`${t} must contain at most ${a} entries`);return e.map((e,a)=>a_(e,`${t}[${a}]`))}let nr=eV,ni=tA,ns=tK,no=tz,nl=t9,nc=ae,nd=at,np=aa,nu=an,nh=ar,nm=ai,nf=as,ng=ao,nb=async(e,t)=>await aC(e,t,"click"),nw=async(e,t)=>await aC(e,t,"press"),ny=async(e,t)=>{var a;if(!t.text)throw new b("INVALID_ARGS","fill requires text");let n=await ay(e,t,{action:"fill",requireInteractive:!0,promoteToHittableAncestor:!1});if(!e.backend.fill)throw new b("UNSUPPORTED_OPERATION","fill is not supported by this backend");let r=aU(await e.backend.fill(tV(e,t),n.point,t.text,{delayMs:t.delayMs})),i="node"in n?n.node.type??"":"",s=i&&!z(i,e.backend.platform)?`fill target ${a=n,a.target?.kind==="ref"?a.target.ref:a.target?.kind==="selector"?a.target.selector:"point"} resolved to "${i}", attempting fill anyway.`:void 0;return{...n,text:t.text,...s?{warning:s}:{},...r?{backendResult:r}:{}}},nv=async(e,t)=>{let a=t.text;if(!a)throw new b("INVALID_ARGS","type requires text");let n=eA(a);if(n)throw new b("INVALID_ARGS",`type does not accept a target ref like "${n}"`,{hint:`Use fill ${n} "text" to target that field, or press ${n} then type "text" to append.`});if(!e.backend.typeText)throw new b("UNSUPPORTED_OPERATION","type is not supported by this backend");let r=eD(t.delayMs??0,"delay-ms",0,1e4),i=aU(await e.backend.typeText(tV(e,t),a,{delayMs:r}));return{kind:"text",text:a,delayMs:r,...i?{backendResult:i}:{},...D(`Typed ${Array.from(a).length} chars`)}},nk=async(e,t)=>{let a=await ay(e,t,{action:"focus",requireInteractive:!0,promoteToHittableAncestor:!1});if(!e.backend.focus)throw new b("UNSUPPORTED_OPERATION","focus is not supported by this backend");let n=aE(await e.backend.focus(tV(e,t),a.point));return{...a,...n?{backendResult:n}:{},...D(`Focused (${a.point.x}, ${a.point.y})`)}},nx=async(e,t)=>{let a=await ay(e,t,{action:"longPress",requireInteractive:!0,promoteToHittableAncestor:!0});if(!e.backend.longPress)throw new b("UNSUPPORTED_OPERATION","longPress is not supported by this backend");let n=void 0===t.durationMs?void 0:eD(t.durationMs,"durationMs",0,12e4),r=aE(await e.backend.longPress(tV(e,t),a.point,{durationMs:n}));return{...a,...void 0!==n?{durationMs:n}:{},...r?{backendResult:r}:{},...D(`Long pressed (${a.point.x}, ${a.point.y})`)}},nA=async(e,t)=>{if(!e.backend.swipe)throw new b("UNSUPPORTED_OPERATION","swipe is not supported by this backend");let a=await aM(e,t),n=function(e,t){if(t.to)return{point:aO(t.to,"to")};let a=aN(t.direction,"swipe direction"),n=aL(t.distance??200,"swipe distance");switch(a){case"up":return{point:{x:e.x,y:e.y-n},direction:a,distance:n};case"down":return{point:{x:e.x,y:e.y+n},direction:a,distance:n};case"left":return{point:{x:e.x-n,y:e.y},direction:a,distance:n};case"right":return{point:{x:e.x+n,y:e.y},direction:a,distance:n}}}(a.point,t),r=void 0===t.durationMs?void 0:eD(t.durationMs,"durationMs",16,1e4),i=aE(await e.backend.swipe(tV(e,t),a.point,n.point,{durationMs:r}));return{kind:"swipe",from:a.point,to:n.point,...n.direction?{direction:n.direction}:{},...void 0!==n.distance?{distance:n.distance}:{},...void 0!==r?{durationMs:r}:{},...a.target?{fromTarget:a.target}:{},...i?{backendResult:i}:{},...D("Swiped")}},nD=async(e,t)=>{var a,n;if(!e.backend.scroll)throw new b("UNSUPPORTED_OPERATION","scroll is not supported by this backend");let r=aN(t.direction,"scroll direction"),i=(a=t.amount,n="scroll amount",void 0===a?void 0:aL(a,n)),s=function(e,t){if(void 0!==e){if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new b("INVALID_ARGS",`${t} must be a positive integer`);return e}}(t.pixels,"scroll pixels");if(void 0!==i&&void 0!==s)throw new b("INVALID_ARGS","scroll accepts either amount or pixels, not both");let o=await aS(e,t),l="viewport"===o.kind?{kind:"viewport"}:{kind:"point",point:o.point},c=aE(await e.backend.scroll(tV(e,t),l,{direction:r,...void 0!==i?{amount:i}:{},...void 0!==s?{pixels:s}:{}}));return{...o,direction:r,...void 0!==i?{amount:i}:{},...void 0!==s?{pixels:s}:{},...c?{backendResult:c}:{},...D(void 0!==s?`Scrolled ${r} by ${s}px`:void 0!==i?`Scrolled ${r} by ${i}`:`Scrolled ${r}`)}},nI=async(e,t)=>{if(!e.backend.pinch)throw new b("UNSUPPORTED_OPERATION","pinch is not supported by this backend");await ak(e,t,"pinch");let a=aL(t.scale,"pinch scale"),n=t.center?await ay(e,{...t,target:t.center},{action:"pinch",requireInteractive:!1,promoteToHittableAncestor:!1}):void 0,r=aE(await e.backend.pinch(tV(e,t),{scale:a,...n?{center:n.point}:{}}));return{kind:"pinch",scale:a,...n?{center:n.point,centerTarget:n}:{},...r?{backendResult:r}:{},...D(`Pinched to scale ${a}`)}},nR=async(e,t={})=>{if(!e.backend.pressBack)throw new b("UNSUPPORTED_OPERATION","system.back is not supported by this backend");let a=t.mode??"in-app";if("in-app"!==a&&"system"!==a)throw new b("INVALID_ARGS","system.back mode must be in-app or system");let n=aF(await e.backend.pressBack(tV(e,t),{mode:a}));return{kind:"systemBack",mode:a,...n?{backendResult:n}:{},...D("Back")}},nS=async(e,t={})=>{if(!e.backend.pressHome)throw new b("UNSUPPORTED_OPERATION","system.home is not supported by this backend");let a=aF(await e.backend.pressHome(tV(e,t)));return{kind:"systemHome",...a?{backendResult:a}:{},...D("Home")}},nM=async(e,t)=>{if(!e.backend.rotate)throw new b("UNSUPPORTED_OPERATION","system.rotate is not supported by this backend");let a=function(e){switch(e){case"portrait":case"portrait-upside-down":case"landscape-left":case"landscape-right":return e;default:throw new b("INVALID_ARGS","system.rotate orientation must be portrait, portrait-upside-down, landscape-left, or landscape-right")}}(t.orientation),n=aF(await e.backend.rotate(tV(e,t),a));return{kind:"systemRotated",orientation:a,...n?{backendResult:n}:{},...D(`Rotated to ${a}`)}},nN=async(e,t={})=>{if(!e.backend.setKeyboard)throw new b("UNSUPPORTED_OPERATION","system.keyboard is not supported by this backend");let a=t.action??"status";if("status"!==a&&"get"!==a&&"dismiss"!==a)throw new b("INVALID_ARGS","system.keyboard action must be status, get, or dismiss");let n=await e.backend.setKeyboard(tV(e,t),{action:a}),r=aF(n);if("dismiss"===a){let e=a$(n)?n.dismissed:void 0;return{kind:"keyboardDismissed",action:a,state:a$(n)?n:{},...r?{backendResult:r}:{},...D(!1===e?"Keyboard already hidden":"Keyboard dismissed")}}return{kind:"keyboardState",action:a,state:a$(n)?n:{},...r?{backendResult:r}:{}}},nO=async(e,t)=>{if("read"===t.action){if(!e.backend.getClipboard)throw new b("UNSUPPORTED_OPERATION","system.clipboard read is not supported by this backend");let a=await e.backend.getClipboard(tV(e,t));return{kind:"clipboardText",action:"read",text:"string"==typeof a?a:a.text}}if("write"!==t.action)throw new b("INVALID_ARGS","system.clipboard action must be read or write");if(!e.backend.setClipboard)throw new b("UNSUPPORTED_OPERATION","system.clipboard write is not supported by this backend");if("string"!=typeof t.text)throw new b("INVALID_ARGS","system.clipboard write requires text");let a=aF(await e.backend.setClipboard(tV(e,t),t.text));return{kind:"clipboardUpdated",action:"write",textLength:Array.from(t.text).length,...a?{backendResult:a}:{},...D("Clipboard updated")}},nL=async(e,t={})=>{if(!e.backend.openSettings)throw new b("UNSUPPORTED_OPERATION","system.settings is not supported by this backend");let a=aT(t.target,"target"),n=aF(await e.backend.openSettings(tV(e,t),a));return{kind:"settingsOpened",...a?{target:a}:{},...n?{backendResult:n}:{},...D(a?`Opened settings: ${a}`:"Opened settings")}},nP=async(e,t={})=>{if(!e.backend.handleAlert)throw new b("UNSUPPORTED_OPERATION","system.alert is not supported by this backend");let a=t.action??"get";if("get"!==a&&"accept"!==a&&"dismiss"!==a&&"wait"!==a)throw new b("INVALID_ARGS","system.alert action must be get, accept, dismiss, or wait");let n=void 0===t.timeoutMs?void 0:eD(t.timeoutMs,"timeoutMs",0,12e4),r=await e.backend.handleAlert(tV(e,t),a,{timeoutMs:n});var i=a,s=r;if("get"===i){if("alertStatus"!==s.kind)throw new b("COMMAND_FAILED","system.alert get returned an invalid backend result");return{kind:"alertStatus",action:i,alert:s.alert}}if("wait"===i){if("alertWait"!==s.kind)throw new b("COMMAND_FAILED","system.alert wait returned an invalid backend result");return{kind:"alertWait",action:i,alert:s.alert,...void 0!==s.waitedMs?{waitedMs:s.waitedMs}:{},...void 0!==s.timedOut?{timedOut:s.timedOut}:{},...D(s.alert?"Alert visible":"Alert wait timed out")}}if("alertHandled"!==s.kind)throw new b("COMMAND_FAILED",`system.alert ${i} returned an invalid backend result`);return{kind:"alertHandled",action:i,handled:s.handled,...s.alert?{alert:s.alert}:{},...s.button?{button:s.button}:{},...D(s.handled?`Alert ${i}ed`:"No alert handled")}},nE=async(e,t={})=>{if(!e.backend.openAppSwitcher)throw new b("UNSUPPORTED_OPERATION","system.appSwitcher is not supported by this backend");let a=aF(await e.backend.openAppSwitcher(tV(e,t)));return{kind:"appSwitcherOpened",...a?{backendResult:a}:{},...D("Opened app switcher")}},nC=async(e,t)=>{var a;if(!e.backend.openApp)throw new b("UNSUPPORTED_OPERATION","apps.open is not supported by this backend");let n=function(e){var t;let a=aT(e.app,"app"),n=aT(e.appId,"appId"),r=aT(e.bundleId,"bundleId"),i=aT(e.packageName,"packageName"),s=aT(e.url,"url"),o=aT(e.activity,"activity"),l={...a?{app:a}:{},...n?{appId:n}:{},...r?{bundleId:r}:{},...i?{packageName:i}:{},...s?{url:s}:{},...o?{activity:o}:{}};if(!((t=l).app??t.appId??t.bundleId??t.packageName??t.url??t.activity))throw new b("INVALID_ARGS","apps.open requires app, appId, bundleId, packageName, url, or activity");return l}(t),r=aV(await e.backend.openApp(aj(e,t),n,{relaunch:t.relaunch}));return{kind:"appOpened",target:n,relaunch:!0===t.relaunch,...r?{backendResult:r}:{},...D(`Opened: ${(a=n).app??a.appId??a.bundleId??a.packageName??a.url??a.activity??"app"}`)}},nU=async(e,t={})=>{if(!e.backend.closeApp)throw new b("UNSUPPORTED_OPERATION","apps.close is not supported by this backend");let a=aT(t.app,"app"),n=aV(await e.backend.closeApp(aj(e,t),a));return{kind:"appClosed",...a?{app:a}:{},...n?{backendResult:n}:{},...D(a?`Closed: ${a}`:"Closed app")}},nT=async(e,t={})=>{if(!e.backend.listApps)throw new b("UNSUPPORTED_OPERATION","apps.list is not supported by this backend");return{kind:"appsList",apps:await e.backend.listApps(aj(e,t),N(t.filter))}},n_=async(e,t)=>{if(!e.backend.getAppState)throw new b("UNSUPPORTED_OPERATION","apps.state is not supported by this backend");let a=a_(t.app,"app"),n=await e.backend.getAppState(aj(e,t),a);return{kind:"appState",app:a,state:n}},n$=async(e,t)=>{if(!e.backend.pushFile)throw new b("UNSUPPORTED_OPERATION","apps.push is not supported by this backend");let a=a_(t.app,"app"),n=await aq(e,t.input);try{let r=await e.backend.pushFile(aj(e,t),n.backendInput,a),i=aV(r);return{kind:"appPushed",app:a,inputKind:n.inputKind,...i?{backendResult:i}:{},...D(`Pushed to ${a}`)}}finally{await n.cleanup?.()}},nF=async(e,t)=>{var a,n;if(!e.backend.triggerAppEvent)throw new b("UNSUPPORTED_OPERATION","apps.triggerEvent is not supported by this backend");let r=function(e){let t=a_(e,"name");if(!aB.test(t))throw new b("INVALID_ARGS",`Invalid apps.triggerEvent name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});return t}(t.name);a=t.payload,n=`apps.triggerEvent payload for "${r}"`,void 0!==a&&aG(a,n,8192);let i=aV(await e.backend.triggerAppEvent(aj(e,t),{name:r,...t.payload?{payload:t.payload}:{}}));return{kind:"appEventTriggered",name:r,...t.payload?{payload:t.payload}:{},...i?{backendResult:i}:{},...D(`Triggered app event: ${r}`)}},nB=async(e,t={})=>{if(!e.backend.listDevices)throw new b("UNSUPPORTED_OPERATION","admin.devices is not supported by this backend");return{kind:"adminDevices",devices:await e.backend.listDevices(tV(e,t),t.filter)}},nq=async(e,t={})=>{if(!e.backend.bootDevice)throw new b("UNSUPPORTED_OPERATION","admin.boot is not supported by this backend");let a=function(e){if(!e)return;let t=aT(e.id,"target.id"),a=aT(e.name,"target.name"),n={...t?{id:t}:{},...a?{name:a}:{},...e.platform?{platform:e.platform}:{},...e.target?{target:e.target}:{},...void 0!==e.headless?{headless:e.headless}:{}};return Object.keys(n).length>0?n:void 0}(t.target),n=aJ(await e.backend.bootDevice(tV(e,t),a));return{kind:"deviceBooted",...a?{target:a}:{},...n?{backendResult:n}:{},...D("Booted device")}},nG=async(e,t)=>await aX(e,t,"install"),nj=async(e,t)=>await aX(e,t,"reinstall"),nV=async(e,t)=>await aX(e,t,"installFromSource"),nX=async(e,t)=>{let a=aW(t.action,"record"),n="start"===a?e.backend.startRecording:e.backend.stopRecording;if(!n)throw new b("UNSUPPORTED_OPERATION",`record ${a} is not supported by this backend`);let r=t.out?await eG(e,t.out,{field:"path",ext:".mp4"}):void 0;try{var i,s,o,l,c;let d,p,u=(i=t,s=r?.path,d=void 0===i.fps?void 0:eD(i.fps,"fps",1,60),p=void 0===i.quality?void 0:eD(i.quality,"quality",5,10),{...s?{outPath:s}:{},...void 0!==d?{fps:d}:{},...void 0!==p?{quality:p}:{},...void 0!==i.hideTouches?{showTouches:!0!==i.hideTouches}:{}}),h=await n.call(e.backend,tV(e,t),u),m=await r?.publish();return o=a,l=h,c=m,{..."string"==typeof l.path?{path:l.path}:{},..."string"==typeof l.telemetryPath?{telemetryPath:l.telemetryPath}:{},..."string"==typeof l.warning?{warning:l.warning}:{},...aQ(o,l,c,{startKind:"recordingStarted",stopKind:"recordingStopped",startMessage:"Recording started",stopMessage:"Recording stopped"})}}catch(e){throw await r?.cleanup?.(),e}},nY=async(e,t)=>{let a=aW(t.action,"trace"),n="start"===a?e.backend.startTrace:e.backend.stopTrace;if(!n)throw new b("UNSUPPORTED_OPERATION",`trace ${a} is not supported by this backend`);let r=t.out?await eG(e,t.out,{field:"outPath",ext:".trace"}):void 0;try{var i,s,o;let l={...r?.path?{outPath:r.path}:{}},c=await n.call(e.backend,tV(e,t),l),d=await r?.publish();return i=a,s=c,o=d,{..."string"==typeof s.outPath?{outPath:s.outPath}:{},...aQ(i,s,o,{startKind:"traceStarted",stopKind:"traceStopped",startMessage:"Trace started",stopMessage:"Trace stopped"})}}catch(e){throw await r?.cleanup?.(),e}},nK=async(e,t={})=>{var a,n;let r;if(!e.backend.readLogs)throw new b("UNSUPPORTED_OPERATION","diagnostics.logs is not supported by this backend");return r=!0===(a=await e.backend.readLogs(await ne(e,t),{...nt(n=t,100,500,"logs limit"),...void 0!==n.levels?{levels:nn(n.levels,"levels")}:{},...void 0!==n.search?{search:a_(n.search,"search")}:{},...void 0!==n.source?{source:a_(n.source,"source")}:{}})).redacted,{kind:"diagnosticsLogs",entries:a.entries.map(e=>{let t=a7(e.message,4096),a=a8(e.metadata);return r||=t.redacted||a.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.level?{level:e.level}:{},message:t.value??"",...e.source?{source:e.source}:{},...a.value?{metadata:a.value}:{}}}),...a.nextCursor?{nextCursor:a.nextCursor}:{},...a.timeWindow?{timeWindow:a.timeWindow}:{},...a.backend?{backend:a.backend}:{},redacted:r,...a.notes?{notes:a.notes}:{}}},nz=async(e,t={})=>{var a,n,r;let i;if(!e.backend.dumpNetwork)throw new b("UNSUPPORTED_OPERATION","diagnostics.network is not supported by this backend");let s={...nt(r=t,25,200,"network limit"),include:function(e){if(void 0===e)return"summary";if("summary"===e||"headers"===e||"body"===e||"all"===e)return e;throw new b("INVALID_ARGS","network include must be summary, headers, body, or all")}(r.include)};return a=await e.backend.dumpNetwork(await ne(e,t),s),n=s.include??"summary",i=!0===a.redacted,{kind:"diagnosticsNetwork",entries:a.entries.map(e=>{var t;let a=e.url?a2(t=e.url)??a7(t,2048):void 0,r="headers"===n||"all"===n?a3(e.requestHeaders):void 0,s="headers"===n||"all"===n?a3(e.responseHeaders):void 0,o="body"===n||"all"===n?a4(e.requestBody):void 0,l="body"===n||"all"===n?a4(e.responseBody):void 0,c=a8(e.metadata);return i||=(a?.redacted??!1)||(r?.redacted??!1)||(s?.redacted??!1)||(o?.redacted??!1)||(l?.redacted??!1)||c.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.method?{method:e.method}:{},...a?{url:a.value}:{},...void 0!==e.status?{status:e.status}:{},...void 0!==e.durationMs?{durationMs:e.durationMs}:{},...r?.value?{requestHeaders:r.value}:{},...s?.value?{responseHeaders:s.value}:{},...o?.value!==void 0?{requestBody:o.value}:{},...l?.value!==void 0?{responseBody:l.value}:{},...c.value?{metadata:c.value}:{}}}),...a.nextCursor?{nextCursor:a.nextCursor}:{},...a.timeWindow?{timeWindow:a.timeWindow}:{},...a.backend?{backend:a.backend}:{},redacted:i,...a.notes?{notes:a.notes}:{}}},nH=async(e,t={})=>{var a,n;let r;if(!e.backend.measurePerf)throw new b("UNSUPPORTED_OPERATION","diagnostics.perf is not supported by this backend");return r=!0===(a=await e.backend.measurePerf(await ne(e,t),{...na(n=t),...void 0!==n.sampleMs?{sampleMs:eD(n.sampleMs,"sampleMs",100,6e4)}:{},...void 0!==n.metrics?{metrics:nn(n.metrics,"metrics",20)}:{}})).redacted,{kind:"diagnosticsPerf",metrics:a.metrics.map(e=>{let t=a7(e.message,4096),a=a8(e.metadata);return r||=t.redacted||a.redacted,{name:e.name,...void 0!==e.value?{value:e.value}:{},...e.unit?{unit:e.unit}:{},...e.status?{status:e.status}:{},...void 0!==t.value?{message:t.value}:{},...a.value?{metadata:a.value}:{}}}),...a.startedAt?{startedAt:a.startedAt}:{},...a.endedAt?{endedAt:a.endedAt}:{},...a.backend?{backend:a.backend}:{},redacted:r,...a.notes?{notes:a.notes}:{}}};function nJ(e){let t={backend:e.backend,artifacts:e.artifacts,sessions:e.sessions??function(e=[]){let t=new Map(e.map(e=>[e.name,nW(e)]));return{get:e=>nW(t.get(e)),set:e=>{t.set(e.name,nW(e))},delete:e=>{t.delete(e)},list:()=>Array.from(t.values(),e=>nW(e))}}(),policy:e.policy??function(e={}){return{allowLocalInputPaths:!1,allowLocalOutputPaths:!1,maxImagePixels:2e7,allowNamedBackendCapabilities:[],...e}}(),diagnostics:e.diagnostics,clock:e.clock,signal:e.signal};return{...t,capture:{screenshot:e=>nr(t,e),diffScreenshot:e=>ni(t,e),snapshot:e=>ns(t,e),diffSnapshot:e=>no(t,e)},selectors:{find:e=>nl(t,e),get:e=>nc(t,e),getText:(e,a={})=>nd(t,{...a,target:e}),getAttrs:(e,a={})=>np(t,{...a,target:e}),is:e=>nu(t,e),isVisible:(e,a={})=>nh(t,{...a,target:e}),isHidden:(e,a={})=>nm(t,{...a,target:e}),wait:e=>nf(t,e),waitForText:(e,a={})=>ng(t,{...a,text:e})},interactions:{click:(e,a={})=>nb(t,{...a,target:e}),press:(e,a={})=>nw(t,{...a,target:e}),fill:(e,a,n={})=>ny(t,{...n,target:e,text:a}),typeText:(e,a={})=>nv(t,{...a,text:e}),focus:(e,a={})=>nk(t,{...a,target:e}),longPress:(e,a={})=>nx(t,{...a,target:e}),swipe:e=>nA(t,e),scroll:e=>nD(t,e),pinch:e=>nI(t,e)},system:{back:e=>nR(t,e),home:e=>nS(t,e),rotate:e=>nM(t,e),keyboard:e=>nN(t,e),clipboard:e=>nO(t,e),settings:e=>nL(t,e),alert:e=>nP(t,e),appSwitcher:e=>nE(t,e)},apps:{open:e=>nC(t,e),close:e=>nU(t,e),list:(e={})=>nT(t,{...e,filter:S(e.filter)}),state:e=>n_(t,e),push:e=>n$(t,e),triggerEvent:e=>nF(t,e)},admin:{devices:e=>nB(t,e),boot:e=>nq(t,e),install:e=>nG(t,e),reinstall:e=>nj(t,e),installFromSource:e=>nV(t,e)},recording:{record:e=>nX(t,e),trace:e=>nY(t,e)},observability:{logs:e=>nK(t,e),network:e=>nz(t,e),perf:e=>nH(t,e)}}}function nW(e){if(e)return{...e,...e.snapshot?{snapshot:structuredClone(e.snapshot)}:{},...e.metadata?{metadata:function(e){try{return structuredClone(e)}catch{return{...e}}}(e.metadata)}:{}}}function nQ(e={}){return{allowLocalInputPaths:!0,allowLocalOutputPaths:!0,maxImagePixels:2e7,allowNamedBackendCapabilities:[],...e}}let nZ=["app","frontmost-app","desktop","menubar"];function n0(e){let t=e?.trim().toLowerCase();if("app"===t||"frontmost-app"===t||"desktop"===t||"menubar"===t)return t;throw new b("INVALID_ARGS",`Invalid surface: ${e}. Use ${nZ.join("|")}.`)}let n1={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
1
+ let e,t,a,n,r,i,s,o;import{promises as l}from"node:fs";import{PNG as c}from"pngjs";import d from"node:path";import{normalizeRef as p,centerOfRect as u,buildSnapshotPresentationKey as h,findNodeByRef as m}from"./4057.js";import{isScrollableNodeLike as f}from"./2842.js";import{asAppError as g,AppError as b}from"./9152.js";import{SCREENSHOT_SPECIFIC_FLAG_DEFINITIONS as w,SCREENSHOT_COMMAND_FLAG_KEYS as y,PUBLIC_COMMANDS as v,ALL_DEVICE_COMMAND_CAPABILITY as k,defineCommand as x,INTERACTION_COMMAND_SCHEMAS as A,successText as D,commandCapabilityMap as I,commandSchemaMap as R}from"./3572.js";import{resolveAppsFilter as S,DEFAULT_APPS_FILTER as M,assertResolvedAppsFilter as N}from"./1393.js";import{whichCmd as O,runCmd as L}from"./9818.js";import{trimText as P,extractNodeText as E,parseSelectorChain as C,isNodeVisible as T,isNodeEditable as U,buildTextPreview as _,findNearestHittableAncestor as $,buildSelectorChainForNode as F,findSelectorChainMatch as B,resolveSelectorChain as q,findNodeByLabel as G,resolveRefLabel as j,describeTextSurface as V,extractReadableText as X,formatSelectorFailure as Y,normalizeType as K,isFillableType as z}from"./940.js";import{findBestMatchesByLocator as H}from"./7556.js";import"./7847.js";function J(e,t,a){return t>=e.x&&t<=e.x+e.width&&a>=e.y&&a<=e.y+e.height}function W(e){let t=null,a=-1;for(let n of e){let e=n.width*n.height;e>a&&(t=n,a=e)}return t}function Q(e,t,a,n){return Math.max(e,a)<=Math.min(t,n)}function Z(e){let t=e.trim().toLowerCase();return!!t&&/^(vertical|horizontal)\s+scroll\s+bar(?:,?\s*\d+\s+pages?)?$/.test(t)}function ee(e,t){if(!(e?.trim().toLowerCase()??"").includes("vertical scroll bar"))return null;let a=function(e){if(!e)return null;let t=/^(\d{1,3})%$/.exec(e.trim());if(!t)return null;let a=Number(t[1]);return Number.isFinite(a)?Math.max(0,Math.min(100,a)):null}(t);return null===a?null:a<=1?{above:!1,below:!0}:a>=99?{above:!0,below:!1}:{above:!0,below:!0}}function et(e){let t=new Map;for(let[a,n]of e.entries())t.set(n.index,a);let a=[],n=[];for(let[r,i]of e.entries()){let e=Math.max(0,i.depth??0);for(;n.length>0&&e<=n[n.length-1].depth;)n.pop();let s="number"==typeof i.parentIndex?t.get(i.parentIndex):void 0,o="number"==typeof s&&s<r?s:n[n.length-1]?.index;a.push({...i,index:r,depth:e,parentIndex:o}),n.push({depth:e,index:r})}return a}function ea(e){return new Map(e.map(e=>[e.index,e]))}function en(e){return e.label?.trim()||e.value?.trim()||e.identifier?.trim()||""}function er(e){if(0===e.length)return{nodes:e,hiddenCount:0,summaryLines:[]};let{byIndex:t,visibleNodeIndexes:a,offscreenNodes:n,hintedContainers:r}=es(e),i=0===a.size?e:e.filter(e=>a.has(e.index));return{nodes:i.map(e=>(function(e,t){let a=t.get(e.index);if(!a||0===a.size)return e;let n=!!(!0===e.hiddenContentAbove||a.has("above"))||void 0,r=!!(!0===e.hiddenContentBelow||a.has("below"))||void 0;return{...e,hiddenContentAbove:n,hiddenContentBelow:r}})(e,r.directionsByContainer)),hiddenCount:0===a.size?0:e.length-i.length,summaryLines:function(e,t,a){let n=new Map;for(let r of e){let e=function(e,t,a){if(!e.rect)return null;let n=el(e,t,a);return n?ec(e.rect,n):null}(r,t,a);if(!e)continue;let i=n.get(e)??[];i.push(r),n.set(e,i)}return["above","below"].flatMap(e=>{let t=n.get(e);if(!t||0===t.length)return[];let a=(function(e){let t=new Set,a=[];for(let n of e){let e=en(n);!e||t.has(e)||(t.add(e),a.push(e))}return a})(t).slice(0,3).map(e=>`"${e}"`),r=1===t.length?"interactive item":"interactive items",i=a.length>0?`: ${a.join(", ")}`:"";return[`[off-screen ${e}] ${t.length} ${r}${i}`]})}(n.filter(e=>!r.coveredNodeIndexes.has(e.index)&&function(e){if(!0===e.hittable)return!0;let t=(e.type??"").toLowerCase();return t.includes("button")||t.includes("link")||t.includes("textfield")||t.includes("edittext")||t.includes("searchfield")||t.includes("checkbox")||t.includes("radio")||t.includes("switch")||t.includes("menuitem")||!!en(e)}(e)),e,t)}}function ei(e){if(0===e.length)return new Map;let{hintedContainers:t}=es(e);var a=t.directionsByContainer;let n=new Map;for(let[e,t]of a){let a={};t.has("above")&&(a.hiddenContentAbove=!0),t.has("below")&&(a.hiddenContentBelow=!0),(a.hiddenContentAbove||a.hiddenContentBelow)&&n.set(e,a)}return n}function es(e){let t=ea(e),a=new Set,n=[];for(let r of e){if(eo(r,e,t)){!function(e,t,a){let n=e,r=new Set;for(;n&&!r.has(n.index);)r.add(n.index),t.add(n.index),n="number"==typeof n.parentIndex?a.get(n.parentIndex):void 0}(r,a,t);continue}n.push(r)}let r=function(e,t,a,n){let r=new Map,i=new Map,s=new Set;for(let e of t){if(!e.rect)continue;let t=ed(e,a,n);if(!t?.rect)continue;let o=ec(e.rect,t.rect);if(!o)continue;let l=r.get(t.index)??new Set;l.add(o),r.set(t.index,l);let c=i.get(t.index)??new Set;c.add(o),i.set(t.index,c),s.add(e.index)}return function(e,t,a,n,r){for(let i of e){let e=function(e){let t=ee(e.label,e.value);if(!t)return null;let a=new Set;return t.above&&a.add("above"),t.below&&a.add("below"),a.size>0?a:null}(i);if(!e||0===e.size)continue;let s=ed(i,t,a);if(!s)continue;let o=n.get(s.index)??new Set,l=r.get(s.index);for(let t of e)(!l||!(l.size>0)||l.has(t))&&o.add(t);n.set(s.index,o)}}(e,a,n,r,i),{directionsByContainer:r,coveredNodeIndexes:s}}(e,n,a,t);return{byIndex:t,visibleNodeIndexes:a,offscreenNodes:n,hintedContainers:r}}function eo(e,t,a=ea(t)){var n;if(!e.rect)return!0;let r=el(e,t,a);return!r||(n=e.rect,Q(n.x,n.x+n.width,r.x,r.x+r.width)&&Q(n.y,n.y+n.height,r.y,r.y+r.height))}function el(e,t,a=ea(t)){var n,r;let i=(n=e,r=a,ep(n,r,e=>!!e.rect)?.rect??null);return i||function(e,t){let a=u(t),n=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),r=n.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),i=W(r.map(e=>e.rect).filter(e=>J(e,a.x,a.y)));if(i)return i;let s=W(r.map(e=>e.rect));if(s)return s;let o=W(n.map(e=>e.rect).filter(e=>J(e,a.x,a.y)));return o||null}(t,e.rect??{x:0,y:0,width:0,height:0})}function ec(e,t){return e.y+e.height<=t.y?"above":e.y>=t.y+t.height?"below":null}function ed(e,t,a){return ep(e,a,e=>t.has(e.index))}function ep(e,t,a){let n="number"==typeof e.parentIndex?t.get(e.parentIndex):void 0,r=new Set;for(;n&&!r.has(n.index);){if(r.add(n.index),a(n)&&f(n))return n;n="number"==typeof n.parentIndex?t.get(n.parentIndex):void 0}return null}let eu="<wifi|airplane|location> <on|off>",eh="location set <lat> <lon>",em="animations <on|off>",ef="appearance <light|dark|toggle>",eg="faceid <match|nonmatch|enroll|unenroll>",eb="touchid <match|nonmatch|enroll|unenroll>",ew="fingerprint <match|nonmatch>",ey="permission <grant|deny|reset> <camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri> [full|limited]",ev="permission <grant|reset> <accessibility|screen-recording|input-monitoring>",ek=`macOS supports only settings ${ef} and settings ${ev}. wifi|airplane|location|animations remain unsupported on macOS.`,ex=`settings ${eu} | settings ${eh} | settings ${em} | settings ${ef} | settings ${eg} | settings ${eb} | settings ${ew} | settings ${ey} | settings ${ev}`,eA=`settings requires ${eu}, ${eh}, ${em}, ${ef}, ${eg}, ${eb}, ${ew}, ${ey}, or ${ev}`;function eD(e){let t=e.trim().toLowerCase();return"appearance"===t||"permission"===t}function eI(e){return`Unsupported macOS setting: ${e}. ${ek}`}function eR(e){let t=e?.trim().split(/\s+/,1)[0];if(!t||!t.startsWith("@")||t.length<3)return null;let a=t.slice(1);return/^[A-Za-z_-]*\d[\w-]*$/i.test(a)||/^(?:ref|node|element|el)[\w-]*$/i.test(a)?t:null}async function eS(e){let{edge:t,target:a={},scope:n,captureNodes:r}=e;try{let e=await r(n),i=function(e,t,a={}){var n,r,i;let s,o=(e??[]).map((e,t)=>({...e,ref:"ref"in e&&e.ref?e.ref:`e${t+1}`}));if(0===o.length)return{canScroll:!1,emptySnapshot:!0,signature:""};let l=ei(o),c=function(e,t,a,n){let r=new Map(e.map(e=>[e.index,e])),i=e.filter(e=>f(e)&&eT(e.rect));if(0===i.length)return null;let s=function(e,t){if(void 0===e)return null;let a=t.get(e);for(;a;){if(f(a)&&eT(a.rect))return a;a=void 0===a.parentIndex?void 0:t.get(a.parentIndex)}return null}(n.nodeIndex,r);if(s)return s;let o=n.point;if(o){let e=i.filter(e=>{var t,a;return e.rect&&(t=e.rect,(a=o).x>=t.x&&a.x<=t.x+t.width&&a.y>=t.y&&a.y<=t.y+t.height)}).sort(eP);if(e.length>0)return e.find(e=>eO(e,t.get(e.index),a))??e[0]??null}let l=i.filter(e=>eO(e,t.get(e.index),a)).sort(eE);return l.length>0?l[0]??null:i.filter(t=>eo(t,e)).sort(eE)[0]??i.sort(eE)[0]??null}(o,l,t,a),d=(c?(n=o,r=c.index,s=new Map(n.map(e=>[e.index,e])),n.filter(e=>e.index===r||function(e,t,a){let n=void 0===e.parentIndex?void 0:a.get(e.parentIndex);for(;n;){if(n.index===t)return!0;n=void 0===n.parentIndex?void 0:a.get(n.parentIndex)}return!1}(e,r,s))):o).map(e=>{let t=e.rect?["x","y","width","height"].map(t=>{var a;return a=e.rect?.[t],"number"==typeof a&&Number.isFinite(a)?a.toFixed(1):""}).join(","):"";return[String(e.index??""),String(e.parentIndex??""),String(e.type??""),String(e.label??""),String(e.value??""),t].join("|")}).join("\n");return c?{canScroll:eO(c,l.get(c.index),t),emptySnapshot:!1,signature:d,scope:[(i=c).identifier,i.label,i.value].map(e=>"string"==typeof e?e.trim():"").find(eL)}:{canScroll:!1,emptySnapshot:!1,signature:d}}(e,t,a);if(n&&i.emptySnapshot)return await eS({edge:t,target:a,captureNodes:r});return i}catch(e){var i,s,o;throw i=t,s=n,o=e,s?new b("COMMAND_FAILED",`Failed to verify scroll ${i} state for scoped container`,{scope:s,hint:`scroll ${i} could not verify the scoped scroll container. Run snapshot -i -c for the current screen and retry with a visible scroll target.`},o):new b("COMMAND_FAILED",`Failed to verify scroll ${i} state`,{hint:`scroll ${i} needs a snapshot showing hidden content ${"bottom"===i?"below":"above"} before it will move.`},o)}}async function eM(e){let t,{edge:a,captureState:n,scroll:r}=e,i=await n();i.scope&&(i=await n(i.scope));let s=0;for(;i.canScroll;){if(s>=40)throw new b("COMMAND_FAILED",`scroll ${a} reached the safety limit before the snapshot showed the edge`,{hint:"The scoped scroll container still reports hidden content. Use a smaller manual scroll + snapshot loop to inspect the current state."});t=await r(),s+=1,i=await n(i.scope)}return{passes:s,result:t}}function eN(e,t,a,n,r){return t&&0===a?`Already at ${t}; no hidden content ${"bottom"===t?"below":"above"} detected`:t?`Scrolled to ${t} with ${a} ${e} passes`:void 0!==r?`Scrolled ${e} by ${r}px`:void 0!==n?`Scrolled ${e} by ${n}`:`Scrolled ${e}`}function eO(e,t,a){return"bottom"===a?!0===e.hiddenContentBelow||t?.hiddenContentBelow===!0:!0===e.hiddenContentAbove||t?.hiddenContentAbove===!0}function eL(e){return e.length>0&&e.length<=80&&!/^(true|false)$/i.test(e)&&!/^\d+$/.test(e)&&!/^\d+%$/.test(e)}function eP(e,t){return eC(e.rect)-eC(t.rect)}function eE(e,t){return eC(t.rect)-eC(e.rect)}function eC(e){return e?e.width*e.height:0}function eT(e){return!!(e&&e.width>0&&e.height>0)}function eU(e,t,a,n){if(!Number.isFinite(e)||!Number.isInteger(e)||e<a||e>n)throw new b("INVALID_ARGS",`${t} must be an integer between ${a} and ${n}`);return e}function e_(e){if(void 0===e)throw new b("INVALID_ARGS","rotate requires an orientation argument. Use portrait|portrait-upside-down|landscape-left|landscape-right.");switch(e?.trim().toLowerCase()){case"portrait":return"portrait";case"portrait-upside-down":case"upside-down":return"portrait-upside-down";case"landscape-left":case"left":return"landscape-left";case"landscape-right":case"right":return"landscape-right";default:throw new b("INVALID_ARGS",`Invalid rotation: ${e}. Use portrait|portrait-upside-down|landscape-left|landscape-right.`)}}let e$=["snapshotInteractiveOnly","snapshotCompact","snapshotDepth","snapshotScope","snapshotRaw"],eF=[x({name:v.snapshot,schema:{usageOverride:"snapshot [--diff] [-i] [-c] [-d <depth>] [-s <scope>] [--raw] [--force-full]",helpDescription:"Capture accessibility tree or diff against the previous session baseline",positionalArgs:[],allowedFlags:["snapshotDiff",...e$,"snapshotForceFull"]},capability:k}),x({name:v.diff,schema:{usageOverride:"diff snapshot | diff screenshot --baseline <path> [current.png] [--out <diff.png>] [--threshold <0-1>] [--overlay-refs]",helpDescription:"Diff accessibility snapshot or compare screenshots pixel-by-pixel",summary:"Diff snapshot or screenshot",positionalArgs:["kind","current?"],allowedFlags:[...e$,"baseline","threshold","out","overlayRefs"]},capability:k}),x({name:v.screenshot,schema:{helpDescription:"Capture screenshot (macOS app sessions default to the app window; use --fullscreen for full desktop, --max-size to downscale, --overlay-refs to annotate current refs, or --no-stabilize for low-latency Android capture loops)",positionalArgs:["path?"],allowedFlags:y},capability:k})],eB=R(eF),eq=I(eF),eG=[x({name:v.reactNative,schema:{usageOverride:"react-native dismiss-overlay",listUsageOverride:"react-native dismiss-overlay",helpDescription:"Dismiss React Native LogBox/RedBox overlays safely",summary:"Dismiss React Native overlays",positionalArgs:["dismiss-overlay"],allowedFlags:[]},capability:{apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{}}})],ej=R(eG),eV=I(eG),eX=["snapshotDepth","snapshotScope","snapshotRaw"],eY=[x({name:v.wait,schema:{usageOverride:"wait <ms>|text <text>|@ref|<selector> [timeoutMs]",helpDescription:"Wait for duration, text, ref, or selector to appear",summary:"Wait for time, text, ref, or selector",positionalArgs:["durationOrSelector","timeoutMs?"],allowsExtraPositionals:!0,allowedFlags:[...eX]},capability:k}),x({name:v.get,schema:{usageOverride:"get text|attrs <@ref|selector>",helpDescription:"Return exposed element text/attributes by ref or selector; use snapshot -s @ref for truncated previews",summary:"Get exposed text or attrs by ref or selector",positionalArgs:["subcommand","target"],allowedFlags:[...eX]},capability:k}),x({name:v.find,schema:{usageOverride:"find <locator|text> <action> [value] [--first|--last]",helpDescription:"Find by text/label/value/role/id and run action",summary:"Find an element and act",positionalArgs:["query","action","value?"],allowsExtraPositionals:!0,allowedFlags:["snapshotDepth","snapshotRaw","findFirst","findLast"]},capability:k}),x({name:v.is,schema:{helpDescription:"Assert UI state (visible|hidden|exists|editable|selected|text)",summary:"Assert UI state",positionalArgs:["predicate","selector","value?"],allowsExtraPositionals:!0,allowedFlags:[...eX]},capability:k})],eK=R(eY),ez=I(eY),eH={apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{device:!0}},eJ={apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{},supports:e=>"macos"!==e.platform},eW=[x({name:v.open,schema:{helpDescription:"Boot device/simulator; optionally launch app or deep link URL (macOS also supports --surface app|frontmost-app|desktop|menubar)",summary:"Open an app, deep link or URL, save replays",positionalArgs:["appOrUrl?","url?"],allowedFlags:["activity","launchConsole","saveScript","relaunch","surface"]},capability:eH}),x({name:v.close,schema:{helpDescription:"Close app or just end session",summary:"Close app or end session",positionalArgs:["app?"],allowedFlags:["saveScript","shutdown"]},capability:eH}),x({name:v.reinstall,schema:{helpDescription:"Uninstall + install app from binary path",summary:"Reinstall app from binary path",positionalArgs:["app","path"],allowedFlags:[]},capability:eJ}),x({name:v.install,schema:{helpDescription:"Install app from binary path without uninstalling first",summary:"Install app from binary path",positionalArgs:["app","path"],allowedFlags:[]},capability:eJ}),x({name:v.installFromSource,schema:{usageOverride:"install-from-source <url> | install-from-source --github-actions-artifact <owner/repo:artifact>",listUsageOverride:"install-from-source <url> | install-from-source --github-actions-artifact",helpDescription:"Install app from a URL or remote-resolved source",summary:"Install app from a source",positionalArgs:["url?"],allowedFlags:["header","githubActionsArtifact","installSource","retainPaths","retentionMs"]},capability:eJ}),x({name:v.apps,schema:{helpDescription:"List user-installed apps; use --all to include system/OEM apps",summary:"List installed apps",positionalArgs:[],allowedFlags:["appsFilter"],defaults:{appsFilter:M}},capability:{apple:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0},linux:{}}})],eQ=R(eW),eZ=I(eW);function e0(e){let t=e?.trim().toLowerCase();return!!t&&(t.includes("open debugger to view warnings")||/^!,\s+/.test(t)||/^(warn|warning|error):\s+/.test(t)||/\b(?:possible\s+)?unhandled (?:promise )?rejection\b/.test(t)||t.includes("getsnapshot should be cached to avoid an infinite loop")||t.includes('unique "key" prop')||t.includes("unique 'key' prop")||t.includes("virtualizedlists should never be nested")||t.includes("failed prop type"))}function e1(e){return e.includes("open debugger to view warnings")||/^!,\s+open debugger\b/.test(e)}function e2(e,t){try{return c.sync.read(e)}catch(e){throw new b("COMMAND_FAILED",`Failed to decode ${t} as PNG`,{label:t,reason:e instanceof Error?e.message:String(e)})}}async function e5(e,t){if(!Number.isInteger(t)||t<1)throw new b("INVALID_ARGS","Screenshot max size must be a positive integer");let a=e2(await l.readFile(e),"screenshot"),n=Math.max(a.width,a.height);if(n<=t)return;let r=t/n,i=Math.max(1,Math.round(a.width*r)),s=Math.max(1,Math.round(a.height*r)),o=function(e,t,a){let n=new c({width:t,height:a});for(let r=0;r<a;r+=1){let i=r*e.height/a,s=(r+1)*e.height/a;for(let a=0;a<t;a+=1){let o=a*e.width/t,l=(a+1)*e.width/t,c=0,d=0,p=0,u=0,h=0;for(let t=Math.floor(i);t<Math.ceil(s);t+=1){let a=Math.min(t+1,s)-Math.max(t,i);for(let n=Math.floor(o);n<Math.ceil(l);n+=1){let r=a*(Math.min(n+1,l)-Math.max(n,o)),i=(t*e.width+n)*4;c+=(e.data[i]??0)*r,d+=(e.data[i+1]??0)*r,p+=(e.data[i+2]??0)*r,u+=(e.data[i+3]??0)*r,h+=r}}let m=(r*n.width+a)*4;n.data[m]=Math.round(c/h),n.data[m+1]=Math.round(d/h),n.data[m+2]=Math.round(p/h),n.data[m+3]=Math.round(u/h)}}return n}(a,i,s);await l.writeFile(e,c.sync.write(o))}async function e3(e,t,a){if("path"===t.kind&&!e.policy.allowLocalInputPaths)throw new b("INVALID_ARGS",`Local ${a.field??"input"} paths are not allowed by command policy`);try{return await e.artifacts.resolveInput(t,a)}catch(e){throw g(e)}}async function e4(e,t,a){if(t?.kind==="path"&&!e.policy.allowLocalOutputPaths)throw new b("INVALID_ARGS","Local output paths are not allowed by command policy");try{return await e.artifacts.reserveOutput(t,{...a,visibility:a.visibility??"client-visible",requestedClientPath:t?.kind==="downloadableArtifact"?t.clientPath??a.requestedClientPath:a.requestedClientPath})}catch(e){throw g(e)}}async function e8(e,t){try{return await e.artifacts.createTempFile(t)}catch(e){throw g(e)}}let e6=async(e,t)=>{let a;if(!e.backend.captureScreenshot)throw new b("UNSUPPORTED_OPERATION","screenshot is not supported by this backend");let n=await e4(e,t.out,{field:"path",ext:".png"});try{await e.backend.captureScreenshot({session:t.session,requestId:t.requestId,appId:t.appId,appBundleId:t.appBundleId,signal:t.signal??e.signal,metadata:t.metadata},n.path,{fullscreen:t.fullscreen,overlayRefs:t.overlayRefs,stabilize:t.stabilize,surface:t.surface}),void 0!==t.maxSize&&await e5(n.path,t.maxSize),a=await n.publish()}catch(e){throw await n.cleanup?.(),e}return{path:n.path,...a?{artifacts:[a]}:{},...D(`Saved screenshot: ${n.path}`)}},e7=[0,187,255,255];function e9(e,t,a,n){if(t<0||t>=e.width||a<0||a>=e.height)return;let r=(a*e.width+t)*4;e.data[r]=n[0],e.data[r+1]=n[1],e.data[r+2]=n[2],e.data[r+3]=n[3]}function te(e,t,a){return Math.min(Math.max(e,t),a)}let tt={icon:90,toggle:90,chevron:75,separator:45,visual:35,background:10},ta={leading:20,trailing:20,separator:10,unknown:0,background:-30};function tn(e){return"background"!==e.likelyKind}function tr(e,t){return e.width>=.25*t.width||e.height>=.06*t.height}function ti(e,t){let a,n=0;for(let r of t){let t=td(e,r.rect);t<=n||(n=t,a=r)}return a}function ts(e){let t=[];for(let a of[...e].sort((e,t)=>e.rect.y-t.rect.y)){let e=t.find(e=>{var t,n;return t=e.rect,td(t,n=a.rect)>0||Math.abs(tp(t).y-tp(n).y)<=.5*Math.max(t.height,n.height)});if(!e){t.push({rect:a.rect,blocks:[a]});continue}e.blocks.push(a),e.blocks.sort((e,t)=>e.rect.x-t.rect.x),e.rect=function(e){let t=1/0,a=1/0,n=-1/0,r=-1/0;for(let i of e)t=Math.min(t,i.x),a=Math.min(a,i.y),n=Math.max(n,i.x+i.width),r=Math.max(r,i.y+i.height);return{x:t,y:a,width:n-t,height:r-a}}([e.rect,a.rect])}return t}function to(e,t){let a,n=tp(e);for(let e of t){var r,i;let t=Math.sqrt((r=n,i=tp(e.rect),(r.x-i.x)**2+(r.y-i.y)**2));a&&t>=a.distance||(a={block:e,distance:t})}return a}function tl(e){let t=tc(e);return e.differentPixels>=24&&t.width>=3&&t.height>=3}function tc(e){return{x:e.minX,y:e.minY,width:e.maxX-e.minX+1,height:e.maxY-e.minY+1}}function td(e,t){return Math.max(0,Math.min(e.y+e.height,t.y+t.height)-Math.max(e.y,t.y))}function tp(e){return{x:e.x+e.width/2,y:e.y+e.height/2}}function tu(e,t,a){return Math.min(Math.max(e,t),a)}async function th(e){if(await O("tesseract"))try{let[t,a]=await Promise.all([tf(e.baselinePath),tf(e.currentPath)]);if(0!==t.exitCode||0!==a.exitCode)return;let n=tm(t.stdout,e.width,e.height),r=tm(a.stdout,e.width,e.height),i=function(e,t){let a=new Set,n=[];for(let i of e){var r;let e=tx(i.text),s=function(e,t,a,n){let r=null,i=1/0;for(let l=0;l<a.length;l+=1){var s,o;if(n.has(l))continue;let c=a[l];if(tx(c.text)!==t)continue;let d=(s=ty(e.normalizedRect),o=ty(c.normalizedRect),(s.x-o.x)**2+(s.y-o.y)**2);d>=i||(r=l,i=d)}return r}(i,e,t,a);if(null===s)continue;a.add(s);let o=function(e,t){let a={x:t.rect.x-e.rect.x,y:t.rect.y-e.rect.y,width:t.rect.width-e.rect.width,height:t.rect.height-e.rect.height},n=tI(t.rect.width/e.rect.width),r=tI(t.rect.height/e.rect.height),i=Math.abs(n-1)>=.08||Math.abs(r-1)>=.12;return{text:e.text,baselineRect:e.rect,currentRect:t.rect,delta:a,confidence:Math.round(100*Math.min(e.confidence,t.confidence))/100,possibleTextMetricMismatch:i}}(i,t[s]);r=o,(Math.abs(r.delta.x)>=2||Math.abs(r.delta.y)>=2||Math.abs(r.delta.width)>=2||Math.abs(r.delta.height)>=2||r.possibleTextMetricMismatch)&&n.push(o)}return n.sort((e,t)=>tg(t)-tg(e)).slice(0,12)}(n,r),s=function(e){let t=[];for(let a of[...e].sort((e,t)=>e.currentRect.y-t.currentRect.y)){let e=t.find(e=>32>=Math.abs(a.delta.x-tA(e.map(e=>e.delta.x))));e?e.push(a):t.push([a])}return t.filter(e=>e.length>=2).map(tb).filter(e=>e.yRange.max-e.yRange.min<=60).sort((e,t)=>tw(t)-tw(e)).slice(0,4)}(i);if(0===n.length&&0===r.length)return;return{provider:"tesseract",baselineBlocks:n.length,currentBlocks:r.length,baselineBlocksRaw:n,currentBlocksRaw:r,matches:i,...s.length>0?{movementClusters:s}:{}}}catch{return}}function tm(e,t,a){let[n,...r]=e.split(/\r?\n/);if(!n)return[];let i=new Map(n.split(" ").map((e,t)=>[e,t])),s=[];for(let e of r){var o;if(!e.trim())continue;let t=e.split(" "),a=tk(t,i,"level"),n=tv(t,i,"text").trim(),r=tk(t,i,"conf");if(5!==a||(o=n,!/[\p{L}\p{N}]/u.test(o))||r<0)continue;let l=tk(t,i,"left"),c=tk(t,i,"top"),d=tk(t,i,"width"),p=tk(t,i,"height");d<=0||p<=0||s.push({key:[tv(t,i,"page_num"),tv(t,i,"block_num"),tv(t,i,"par_num"),tv(t,i,"line_num")].join(":"),text:n,confidence:r,rect:{x:l,y:c,width:d,height:p}})}let l=new Map;for(let e of s){let t=l.get(e.key);t?t.push(e):l.set(e.key,[e])}return Array.from(l.values()).flatMap(e=>(function(e){let t=[...e].sort((e,t)=>e.rect.x-t.rect.x),a=[],n=[];for(let e of t){let t=n.at(-1);if(!t){n.push(e);continue}if(e.rect.x-(t.rect.x+t.rect.width)>Math.max(48,2.5*Math.max(t.rect.height,e.rect.height))){a.push(n),n=[e];continue}n.push(e)}return n.length>0&&a.push(n),a})(e)).map(e=>(function(e,t,a){if(0===e.length)return null;let n=[...e].sort((e,t)=>e.rect.x-t.rect.x),r=function(e){let t=1/0,a=1/0,n=-1/0,r=-1/0;for(let i of e)t=Math.min(t,i.x),a=Math.min(a,i.y),n=Math.max(n,i.x+i.width),r=Math.max(r,i.y+i.height);return{x:t,y:a,width:n-t,height:r-a}}(n.map(e=>e.rect)),i=Math.round(100*tA(n.map(e=>e.confidence)))/100;return{text:n.map(e=>e.text).join(" "),confidence:i,rect:r,normalizedRect:{x:tD(r.x/t),y:tD(r.y/a),width:tD(r.width/t),height:tD(r.height/a)}}})(e,t,a)).filter(e=>null!==e)}function tf(e){return L("tesseract",[e,"stdout","-l","eng","tsv"],{allowFailure:!0,timeoutMs:1e4})}function tg(e){return Math.abs(e.delta.x)+Math.abs(e.delta.y)+Math.abs(e.delta.width)+Math.abs(e.delta.height)+25*!!e.possibleTextMetricMismatch}function tb(e){let t=e.map(e=>e.delta.x),a=e.map(e=>e.delta.y);return{texts:e.map(e=>e.text),xRange:{min:Math.min(...t),max:Math.max(...t)},yRange:{min:Math.min(...a),max:Math.max(...a)}}}function tw(e){return 2*Math.abs((e.xRange.min+e.xRange.max)/2)+Math.abs((e.yRange.min+e.yRange.max)/2)}function ty(e){return{x:e.x+e.width/2,y:e.y+e.height/2}}function tv(e,t,a){let n=t.get(a);return void 0===n?"":e[n]??""}function tk(e,t,a){let n=Number(tv(e,t,a));return Number.isFinite(n)?n:0}function tx(e){return e.trim().replace(/\s+/g," ").toLowerCase()}function tA(e){return e.reduce((e,t)=>e+t,0)/e.length}function tD(e){return Math.round(100*e*100)/100}function tI(e){return Math.round(1e3*e)/1e3}function tR(e,t,a,n){return{r:Math.round(e/n),g:Math.round(t/n),b:Math.round(a/n)}}function tS(e){return .2126*e.r+.7152*e.g+.0722*e.b}function tM(e){return`#${tN(e.r)}${tN(e.g)}${tN(e.b)}`}function tN(e){return e.toString(16).padStart(2,"0")}function tO(e){return Math.round(100*e*100)/100}let tL=255*Math.sqrt(3);async function tP(e,t,a={}){let n,r,i,s;await tE(e,"Baseline image not found"),await tE(t,"Current screenshot not found");let o=a.outputPath,[p,u]=await Promise.all([l.readFile(e),l.readFile(t)]),h=e2(p,"baseline screenshot"),m=e2(u,"current screenshot");tC(h.width,h.height,"baseline screenshot",a.maxPixels),tC(m.width,m.height,"current screenshot",a.maxPixels);let f=a.threshold??.1;if(h.width!==m.width||h.height!==m.height){let e=h.width*h.height;return await tT(a.outputPath),{match:!1,mismatchPercentage:100,totalPixels:e,differentPixels:e,dimensionMismatch:{expected:{width:h.width,height:h.height},actual:{width:m.width,height:m.height}}}}let g=h.width*h.height,b=f*tL,w=new c({width:h.width,height:h.height}),y=new Uint8Array(g),v=0;for(let e=0,t=0;e<h.data.length;e+=4,t+=1){if(Math.sqrt((h.data[e]-m.data[e])**2+(h.data[e+1]-m.data[e+1])**2+(h.data[e+2]-m.data[e+2])**2)>b){v+=1,y[t]=1;let a=tU(m,e);w.data[e]=t_(a,220,.78),w.data[e+1]=t_(a,0,.78),w.data[e+2]=t_(a,0,.78),w.data[e+3]=255;continue}let a=tU(m,e);w.data[e]=a,w.data[e+1]=a,w.data[e+2]=a,w.data[e+3]=255}let k=v>0?(A=(n=function(e){let{diffMask:t,baseline:a,current:n}=e,{width:r,height:i}=a,s=new Uint8Array(t.length),o=new Int32Array(t.length),l=[];for(let e=0;e<t.length;e+=1){if(1!==t[e]||1===s[e])continue;let c=0,d=0;o[0]=e,d+=1,s[e]=1;let p=e%r,u=Math.floor(e/r),h={minX:p,minY:u,maxX:p,maxY:u,differentPixels:0,baselineRed:0,baselineGreen:0,baselineBlue:0,currentRed:0,currentGreen:0,currentBlue:0};for(;c<d;){let e=o[c];c+=1,function(e,t,a,n,r){let i=t%a,s=Math.floor(t/a),o=4*t;e.minX=Math.min(e.minX,i),e.minY=Math.min(e.minY,s),e.maxX=Math.max(e.maxX,i),e.maxY=Math.max(e.maxY,s),e.differentPixels+=1,e.baselineRed+=n.data[o],e.baselineGreen+=n.data[o+1],e.baselineBlue+=n.data[o+2],e.currentRed+=r.data[o],e.currentGreen+=r.data[o+1],e.currentBlue+=r.data[o+2]}(h,e,r,a,n);let l=e%r,p=Math.floor(e/r);for(let e=-1;e<=1;e+=1){let a=p+e;if(!(a<0)&&!(a>=i))for(let n=-1;n<=1;n+=1){if(0===n&&0===e)continue;let i=l+n;if(i<0||i>=r)continue;let c=a*r+i;1===t[c]&&1!==s[c]&&(s[c]=1,o[d]=c,d+=1)}}}l.push(h)}return l}(x={diffMask:y,baseline:h,current:m,totalPixels:g,differentPixels:v,maxRegions:a.maxRegions})).length<=2e3?function(e){let t=[];for(let r of e.sort((e,t)=>{let a=e.minY-t.minY;return 0!==a?a:e.minX-t.minX})){var a,n;let e=t.find(e=>{var t,a,n;return t=e,a=r,n=12,t.minX-n<=a.maxX&&a.minX-n<=t.maxX&&t.minY-n<=a.maxY&&a.minY-n<=t.maxY});if(!e){t.push({...r});continue}a=e,n=r,a.minX=Math.min(a.minX,n.minX),a.minY=Math.min(a.minY,n.minY),a.maxX=Math.max(a.maxX,n.maxX),a.maxY=Math.max(a.maxY,n.maxY),a.differentPixels+=n.differentPixels,a.baselineRed+=n.baselineRed,a.baselineGreen+=n.baselineGreen,a.baselineBlue+=n.baselineBlue,a.currentRed+=n.currentRed,a.currentGreen+=n.currentGreen,a.currentBlue+=n.currentBlue}return t}(n):n,A.flatMap(e=>{var t,a,n;let r;return(t=e,a=x.baseline.width,n=x.baseline.height,r=t.maxX-t.minX+1,t.maxY-t.minY+1>=Math.max(48,Math.round(.07*n))&&r>=.35*a)?function(e,t,a){var n;let r=function(e,t){let a=[],n=null;for(let r=0;r<e.length;r+=1){if(e[r]<=t){n??=r;continue}null!==n&&(r-n>=6&&a.push([n,r-1]),n=null)}return null!==n&&e.length-n>=6&&a.push([n,e.length-1]),a}((n=function(e,t,a){let n=[];for(let r=e.minY;r<=e.maxY;r+=1){let i=0;for(let n=e.minX;n<=e.maxX;n+=1)1===t[r*a+n]&&(i+=1);n.push(i)}return n}(e,t.diffMask,t.baseline.width)).map((e,t)=>{let a=0,r=0,i=Math.max(0,t-3),s=Math.min(n.length-1,t+3);for(let e=i;e<=s;e+=1)a+=n[e],r+=1;return Math.round(a/r)}),Math.max(1,Math.round((e.maxX-e.minX+1)*.08))),i=function(e,t,a){let n=[],r=e.minY;for(let[i,s]of t){let t=e.minY+Math.round((i+s)/2);t-r+1<a||e.maxY-t<a||(n.push([r,t]),r=t+1)}return n.push([r,e.maxY]),n}(e,r,a);if(i.length<=1)return[e];let s=i.map(([a,n])=>(function(e,t,a,n){let r=null;for(let o=t;o<=a;o+=1)for(let t=e.minX;t<=e.maxX;t+=1){var i,s;let e=o*n.baseline.width+t;1===n.diffMask[e]&&function(e,t,a,n,r,i){let s=4*t;e.minX=Math.min(e.minX,a),e.minY=Math.min(e.minY,n),e.maxX=Math.max(e.maxX,a),e.maxY=Math.max(e.maxY,n),e.differentPixels+=1,e.baselineRed+=r.data[s],e.baselineGreen+=r.data[s+1],e.baselineBlue+=r.data[s+2],e.currentRed+=i.data[s],e.currentGreen+=i.data[s+1],e.currentBlue+=i.data[s+2]}(r??={minX:i=t,minY:s=o,maxX:i,maxY:s,differentPixels:0,baselineRed:0,baselineGreen:0,baselineBlue:0,currentRed:0,currentGreen:0,currentBlue:0},e,t,o,n.baseline,n.current)}return r})(e,a,n,t)).filter(e=>null!==e);return s.length>1?s:[e]}(e,x,Math.max(24,Math.round(.03*x.baseline.height))):[e]})).sort((e,t)=>{let a=t.differentPixels-e.differentPixels;if(0!==a)return a;let n=e.minY-t.minY;return 0!==n?n:e.minX-t.minX}).slice(0,Math.max(0,x.maxRegions??8)).map((e,t)=>{var a,n,r,i,s,o,l,c,d,p,u;let h,m,f,g,b,w,y,v,k,A,D,I,R,S,M,N,O;return a=e,n=t+1,r={width:x.baseline.width,height:x.baseline.height,totalPixels:x.totalPixels,differentPixels:x.differentPixels},w={x:a.minX,y:a.minY,width:a.maxX-a.minX+1,height:a.maxY-a.minY+1},y={x:Math.round(a.minX+w.width/2),y:Math.round(a.minY+w.height/2)},v=tR(a.baselineRed,a.baselineGreen,a.baselineBlue,a.differentPixels),k=tR(a.currentRed,a.currentGreen,a.currentBlue,a.differentPixels),A=w.width*w.height,D=tO(a.differentPixels/A),I=Math.round(tS(v)),R=Math.round(tS(k)),S=(i=w,s=r.width,o=r.height,i.width>=.55*s&&i.height>=.12*o?"large-area":i.width>=2.5*i.height?"horizontal-band":i.height>=2.5*i.width?"vertical-band":"compact"),M=(h=A/r.totalPixels)>=.04?"large":h>=.01?"medium":"small",N=(l=v,c=k,m=tS(l),Math.abs(f=tS(c)-m)>=12?f>0?"brighter":"darker":Math.max(Math.abs(c.r-l.r),Math.abs(c.g-l.g),Math.abs(c.b-l.b))>=12?"color-shift":"mixed"),O=(d=y,p=r.width,u=r.height,g=d.x<p/3?"left":d.x>2*p/3?"right":"center",b=d.y<u/3?"top":d.y>2*u/3?"bottom":"middle","center"===g&&"middle"===b?"center":`${b}-${g}`),{index:n,rect:w,normalizedRect:{x:tO(w.x/r.width),y:tO(w.y/r.height),width:tO(w.width/r.width),height:tO(w.height/r.height)},differentPixels:a.differentPixels,shareOfDiffPercentage:tO(a.differentPixels/r.differentPixels),densityPercentage:D,shape:S,size:M,location:O,averageBaselineColorHex:tM(v),averageCurrentColorHex:tM(k),baselineLuminance:I,currentLuminance:R,dominantChange:N}}):[];if(v>0&&o){var x,A,D;for(let e of k)e.rect.width<4||e.rect.height<4||function(e,t){let a=te(t.x,0,e.width-1),n=te(t.y,0,e.height-1),r=te(t.x+t.width-1,0,e.width-1),i=te(t.y+t.height-1,0,e.height-1);for(let t=0;t<2;t+=1){for(let s=a;s<=r;s+=1)e9(e,s,n+t,e7),e9(e,s,i-t,e7);for(let s=n;s<=i;s+=1)e9(e,a+t,s,e7),e9(e,r-t,s,e7)}}(w,e.rect);await l.mkdir(d.dirname(o),{recursive:!0}),await l.writeFile(o,c.sync.write(w))}else await tT(a.outputPath);let I=v>0?await th({baselinePath:e,currentPath:t,width:h.width,height:h.height}):void 0,R=I&&(I.matches.length>0||(I.movementClusters?.length??0)>0)?{provider:I.provider,baselineBlocks:I.baselineBlocks,currentBlocks:I.currentBlocks,matches:I.matches,...I.movementClusters?{movementClusters:I.movementClusters}:{}}:void 0,S=v>0&&I?(r=function(e){let t=[];for(let a of e.sort((e,t)=>e.minY-t.minY||e.minX-t.minX)){let e=t.find(e=>{var t,n,r;return t=e,n=a,r=10,t.minX-r<=n.maxX&&n.minX-r<=t.maxX&&t.minY-r<=n.maxY&&n.minY-r<=t.maxY});if(!e){t.push({...a});continue}e.minX=Math.min(e.minX,a.minX),e.minY=Math.min(e.minY,a.minY),e.maxX=Math.max(e.maxX,a.maxX),e.maxY=Math.max(e.maxY,a.maxY),e.differentPixels+=a.differentPixels}return t}(function(e,t,a){let n=new Uint8Array(e.length),r=new Int32Array(e.length),i=[];for(let s=0;s<e.length;s+=1){if(1!==e[s]||1===n[s])continue;let o=0,l=0;r[0]=s,l+=1,n[s]=1;let c=s%t,d=Math.floor(s/t),p={minX:c,minY:d,maxX:c,maxY:d,differentPixels:0};for(;o<l;){let i=r[o];o+=1;let s=i%t,c=Math.floor(i/t);p.minX=Math.min(p.minX,s),p.minY=Math.min(p.minY,c),p.maxX=Math.max(p.maxX,s),p.maxY=Math.max(p.maxY,c),p.differentPixels+=1;for(let i=-1;i<=1;i+=1){let o=c+i;if(!(o<0)&&!(o>=a))for(let a=-1;a<=1;a+=1){if(0===a&&0===i)continue;let c=s+a;if(c<0||c>=t)continue;let d=o*t+c;1===e[d]&&1!==n[d]&&(n[d]=1,r[l]=d,l+=1)}}}i.push(p)}return i}(function(e,t,a,n){let r=new Uint8Array(e);if(!n)return r;for(let e of[...n.baselineBlocksRaw,...n.currentBlocksRaw]){var i;!function(e,t,a,n){let r=tu(Math.floor(n.x),0,t-1),i=tu(Math.floor(n.y),0,a-1),s=tu(Math.ceil(n.x+n.width),0,t),o=tu(Math.ceil(n.y+n.height),0,a);for(let a=i;a<o;a+=1)for(let n=r;n<s;n+=1)e[a*t+n]=0}(r,t,a,{x:(i=e.rect).x-8,y:i.y-8,width:i.width+16,height:i.height+16})}return r}((D={diffMask:y,width:h.width,height:h.height,regions:k,ocr:I}).diffMask,D.width,D.height,D.ocr),D.width,D.height)),i=ts(D.ocr?.currentBlocksRaw??[]),s=ts(D.ocr?.baselineBlocksRaw??[]),r.filter(tl).map(e=>{var t,a,n,r,o,l,c,d,p,u,h;let m,f,g,b,w,y,v,k,x,A;return t=e,a=D,n=i,r=s,b=function(e,t){let a,n=0;for(let r of t){let t=function(e,t){let a=Math.max(e.x,t.x),n=Math.max(e.y,t.y),r=Math.min(e.x+e.width,t.x+t.width),i=Math.min(e.y+e.height,t.y+t.height);return r<=a||i<=n?0:(r-a)*(i-n)}(e,r.rect);t<=n||(n=t,a=r)}return a?.index}(g=tc(t),a.regions),w=function(e,t,a){let n=ti(e,t);if(n)return to(e,n.blocks);let r=ti(e,a);return r?to(e,r.blocks):void 0}(g,n,r),y=function(e,t,a){if(e.height<=3&&e.width>=.12*a)return"separator";if(!t)return e.width>=.4*a?"background":"unknown";if(e.width>=.4*a)return"background";let n=e.x+e.width/2,r=t.x+t.width/2;return n<r-t.width/2?"leading":n>r+t.width/2?"trailing":e.width>=.35*a?"background":"unknown"}(g,w?.block.rect,a.width),v=(o=g,l=y,c=t.differentPixels,d=a,m=o.width/o.height,f=c/(o.width*o.height),"separator"===l?"separator":"background"===l?"background":"trailing"===l&&m>=1.5&&m<=3.8&&f>=.35?"toggle":"trailing"===l&&o.width<=.06*d.width&&o.height<=.04*d.height?"chevron":"leading"===l&&m>=.55&&m<=1.8?"icon":tr(o,d)?"background":"visual"),k={...b?{regionIndex:b}:{},slot:y,likelyKind:v,rect:g},{...b?{regionIndex:b}:{},slot:y,likelyKind:v,rect:g,...w?{nearestText:w.block.text.trim().replace(/^[^\p{L}\p{N}]+/u,"").replace(/^\p{L}\s+/u,"")}:{},score:(p=k,u=t.differentPixels,h=a,x=tr(p.rect,h)?-35:0,A=20*!!p.regionIndex,tt[p.likelyKind]+ta[p.slot]+A+x+Math.min(20,u/200))}}).filter(e=>e.rect.y>=.08*D.height).filter(tn).sort((e,t)=>t.score-e.score).slice(0,Math.max(0,D.maxDeltas??12)).map((e,t)=>{var a;return a=e,{index:t+1,...a.regionIndex?{regionIndex:a.regionIndex}:{},slot:a.slot,likelyKind:a.likelyKind,rect:a.rect,...a.nearestText?{nearestText:a.nearestText}:{}}})):[],M=g>0?Math.round(v/g*1e4)/100:0;return{...v>0&&o?{diffPath:o}:{},...k.length>0?{regions:k}:{},...R?{ocr:R}:{},...S.length>0?{nonTextDeltas:S}:{},totalPixels:g,differentPixels:v,mismatchPercentage:M,match:0===v}}async function tE(e,t){try{await l.access(e)}catch{throw new b("INVALID_ARGS",`${t}: ${e}`)}}function tC(e,t,a,n){if(null==n||n<=0)return;let r=e*t;if(!(r<=n))throw new b("INVALID_ARGS",`${a} is ${r} pixels, which exceeds the configured maxImagePixels limit of ${n}`)}async function tT(e){if(e)try{await l.unlink(e)}catch(e){var t;if(!("object"==typeof(t=e)&&null!==t&&"code"in t&&"ENOENT"===t.code))throw e}}function tU(e,t){return t_(Math.round(.299*e.data[t]+.587*e.data[t+1]+.114*e.data[t+2]),255,.72)}function t_(e,t,a){return Math.round(e*(1-a)+t*a)}function t$(e){return e.width*e.height}function tF(e){return Math.round(100*e*100)/100}let tB=async(e,t)=>{let a,n,r;if(!t.baseline)throw new b("INVALID_ARGS","diff screenshot requires a baseline image");let i=function(e){if(null==e||""===e)return .1;let t=Number(e);if(Number.isNaN(t)||t<0||t>1)throw new b("INVALID_ARGS","--threshold must be a number between 0 and 1");return t}(t.threshold),s=t.current??{kind:"live"};if(t.overlayRefs&&!tK(s))throw new b("INVALID_ARGS","diff screenshot <current.png> cannot use --overlay-refs because saved-image comparisons have no live accessibility refs");let o=await e3(e,t.baseline,{usage:"diff screenshot baseline",field:"baseline"}),l=[];try{let c;c=tK(s)?(n=await tq(e,t)).path:(a=await e3(e,s,{usage:"diff screenshot current",field:"current"})).path,r=t.out?await e4(e,t.out,{field:"diffPath",ext:".png"}):void 0;let d=await tP(o.path,c,{threshold:i,outputPath:r?.path,maxPixels:e.policy.maxImagePixels});tK(s)&&(d=await tG(e,t,r?.path,d,l));let p=d.diffPath?await r?.publish():void 0;return p&&l.push(p),d.diffPath||await r?.cleanup?.(),{...d,...l.length>0?{artifacts:l}:{}}}catch(e){throw await r?.cleanup?.(),e}finally{await o.cleanup?.(),await a?.cleanup?.(),await n?.cleanup?.()}};async function tq(e,t){let a=await e8(e,{prefix:"agent-device-diff-current",ext:".png"});try{await tj(e,t,a.path,tV(t))}catch(e){throw await a.cleanup(),e}return a}async function tG(e,t,a,n,r){var i,s,o,l;if(!t.overlayRefs)return n;if(n.match||n.dimensionMismatch)return a&&await tY(a),n;let c=(i=t,s=a,i.currentOverlayOut?i.currentOverlayOut:i.out?.kind==="path"?{kind:"path",path:tX(s??i.out.path)}:i.out?.kind==="downloadableArtifact"?{kind:"downloadableArtifact",...i.out.clientPath?{clientPath:tX(i.out.clientPath)}:{},...i.out.fileName?{fileName:tX(i.out.fileName)}:{}}:void 0),d=await e4(e,c,{field:"currentOverlayPath",ext:".png"});try{let a=await tj(e,t,d.path,{overlayRefs:!0,...tV(t)}),i=await d.publish();return i&&r.push(i),{...n,currentOverlayPath:a.path??d.path,...a.overlayRefs?{currentOverlayRefCount:a.overlayRefs.length}:{},...n.regions&&a.overlayRefs?{regions:(o=n.regions,l=a.overlayRefs,o.map(e=>{var t,a;let n,r=(t=e,a=l,n=t$(t.rect),a.map(e=>{var a,r;let i,s,o,l,c=e.overlayRect,d=(a=t.rect,r=c,i=Math.max(a.x,r.x),s=Math.max(a.y,r.y),o=Math.min(a.x+a.width,r.x+r.width),l=Math.min(a.y+a.height,r.y+r.height),o<=i||l<=s?0:(o-i)*(l-s));return d<=0?null:{ref:e.ref,...e.label?{label:e.label}:{},rect:c,overlayCoveragePercentage:tF(d/t$(c)),regionCoveragePercentage:tF(d/n)}}).filter(e=>null!==e).sort((e,t)=>{let a=t.regionCoveragePercentage-e.regionCoveragePercentage;return 0!==a?a:t.overlayCoveragePercentage-e.overlayCoveragePercentage}).slice(0,3).map(e=>({ref:e.ref,...e.label?{label:e.label}:{},rect:e.rect,regionCoveragePercentage:e.regionCoveragePercentage})));return r.length>0?{...e,currentOverlayMatches:r}:e}))}:{}}}catch(e){throw await d.cleanup?.(),e}}async function tj(e,t,a,n={}){if(!e.backend.captureScreenshot)throw new b("UNSUPPORTED_OPERATION","screenshot is not supported by this backend");return await e.backend.captureScreenshot({session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata},a,n)??{}}function tV(e){return e.surface?{surface:e.surface}:{}}function tX(e){let t=d.extname(e),a=t?e.slice(0,-t.length):e;return`${a}.current-overlay${t||".png"}`}async function tY(e){try{await l.unlink(tX(e))}catch(e){var t;if(!("object"==typeof(t=e)&&null!==t&&"code"in t&&"ENOENT"===t.code))throw e}}function tK(e){return"live"===e.kind}let tz={application:"application",navigationbar:"navigation-bar",tabbar:"tab-bar",button:"button",imagebutton:"button",link:"link",cell:"cell",statictext:"text",checkedtextview:"text",textfield:"text-field",edittext:"text-field",textarea:"text-view",switch:"switch",slider:"slider",image:"image",imageview:"image",webview:"webview",framelayout:"group",linearlayout:"group",relativelayout:"group",constraintlayout:"group",viewgroup:"group",view:"group",listview:"list",recyclerview:"list",collectionview:"collection",searchfield:"search",segmentedcontrol:"segmented-control",group:"group",window:"window",checkbox:"checkbox",radio:"radio",menuitem:"menu-item",toolbar:"toolbar",scrollarea:"scroll-area",scrollview:"scroll-area",nestedscrollview:"scroll-area",table:"table"};function tH(e,t={}){let a=[],n=[];for(let r of e){let e=r.depth??0,i=r.label?.trim()||r.value?.trim()||r.identifier?.trim()||"",s=tQ(r.type??"Element");if("group"===s&&!i)continue;for(;a.length>0&&e<=a[a.length-1];)a.pop();let o=a.length;a.push(e),n.push({node:r,depth:o,type:s,text:tJ(r,o,!1,s,t)})}return n}function tJ(e,t,a,n,r={}){var i,s,o,l,c,d,p,u;let h,m=n??tQ(e.type??"Element"),f=V(e,m),g=(i=e,s=m,o=r,l=f,o.summarizeTextSurfaces&&l.shouldSummarize&&function(e,t,a){let n=P(e.label);if(n&&n!==a)return n;let r=P(e.identifier);if(r&&!t0(r)&&r!==a)return r;switch(t){case"text":case"text-view":return"Text view";case"text-field":return"Text field";case"search":return"Search field";default:return""}}(i,s,l.text)||tW(i,s)),b=" ".repeat(t),w=e.ref?`@${e.ref}`:"",y=(c=e,d=m,p=r,u=f,h=[],(!1===c.enabled&&h.push("disabled"),p.summarizeTextSurfaces)?(!0===c.selected&&h.push("selected"),!0===c.focused&&h.push("focused"),tZ(d)&&h.push("editable"),function(e,t){if("scroll-area"===t)return!0;let a=(e.type??"").toLowerCase(),n=`${e.role??""} ${e.subrole??""}`.toLowerCase();return a.includes("scroll")||n.includes("scroll")}(c,d)&&h.push("scrollable"),h.push(...c.presentationHints??[]),u.shouldSummarize&&(h.push(`preview:"${_(u.text).replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`),h.push("truncated")),t1(h)):h).map(e=>` [${e}]`).join(""),v=g?` "${g}"`:"";return a?`${b}${w} [${m}]${y}`.trimEnd():`${b}${w} [${m}]${v}${y}`.trimEnd()}function tW(e,t){var a,n;let r=e.label?.trim();if(r&&(a=t,n=r,("scroll-area"===a||"list"===a||"collection"===a||"table"===a)&&Z(n)))return"";let i=e.value?.trim();if(tZ(t)){if(i)return i;if(r)return r}else if(r)return r;if(i)return i;let s=e.identifier?.trim();return!s||t0(s)&&("group"===t||"image"===t||"list"===t||"collection"===t)?"":s}function tQ(e){var t;let a=e.replace(/XCUIElementType/gi,"").toLowerCase(),n=e.includes(".")&&(e.startsWith("android.")||e.startsWith("androidx.")||e.startsWith("com."));return(a.includes(".")&&(a=a.replace(/^android\.widget\./,"").replace(/^android\.view\./,"").replace(/^android\.webkit\./,"").replace(/^androidx\./,"").replace(/^com\.google\.android\./,"").replace(/^com\.android\./,""),n&&a.includes(".")&&(a=a.slice(a.lastIndexOf(".")+1))),"textview"===a)?n?"text":"text-view":(t=a,(Object.prototype.hasOwnProperty.call(tz,t)?tz[t]:void 0)||a||"element")}function tZ(e){return"text-field"===e||"text-view"===e||"search"===e}function t0(e){return/^[\w.]+:id\/[\w.-]+$/i.test(e)}function t1(e){return[...new Set(e)]}function t2(e,t){let a=tQ(e.type??"Element"),n=tW(e,a),r=!1===e.enabled?"disabled":"enabled",i=!0===e.selected?"selected":"unselected",s=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),a,n,r,i,s].join("|")}function t5(e,t){return t.flatten?e.map(e=>({text:tJ(e,0,!1),comparable:t2(e,0)})):tH(e).map(e=>({text:e.text,comparable:t2(e.node,e.depth)}))}function t3(e,t){return e.get(t)??0}function t4(e){let t=e.map(e=>[e.label,e.value,e.identifier,e.type,e.role].filter(Boolean).join(" ")).join("\n").toLowerCase(),a=ae(e,t6),n=ae(e,t7),r=ae(e,e0,t9),i=ae(e,e1),s=at(a),o=at(n),l=at(r),c=/\b[\w.$<>/-]+\.(?:tsx?|jsx?):\d+(?::\d+)?\b/.test(t)||/\b[\w.$<>/-]+\.(?:tsx?|jsx?)\s+\(\d+:\d+\)/.test(t),d=s.length>0||o.length>0||/\b(reload js|copy stack)\b/.test(t),p=/\b(redbox|runtime error|reload js|copy stack|component stack|call stack)\b/.test(t)||c&&d;return{detected:l.length>0||i.length>0||d&&(/\b(logbox|redbox|reload js|copy stack|component stack|call stack|runtime error|open debugger to view warnings)\b/.test(t)||c),redBox:p,dismissRefs:s,minimizeRefs:o,collapsedRefs:l,dismissNodes:a,minimizeNodes:n,collapsedNodes:r}}function t8(e){let t,a=t4(e);if(!a.detected)return null;if(a.redBox){let e=aa(a.minimizeNodes);if(e)return an(e,"minimize");let t=aa(a.dismissNodes);return t?{...an(t,ar(t)),warning:"RedBox Minimize control was not exposed; used Dismiss fallback"}:null}let n=aa(a.dismissNodes);if(n)return an(n,ar(n));let r=0===(t=a.collapsedNodes.filter(e=>e.rect)).length?null:t.sort((e,t)=>{let a=+(!0===e.hittable),n=+(!0===t.hittable);if(a!==n)return n-a;let r=e.rect?.width??0,i=t.rect?.width??0;return r!==i?i-r:(t.rect?.y??0)-(e.rect?.y??0)})[0];return r?.rect?{action:"close-collapsed-banner",point:function(e){var t,a;if(!e.rect)throw Error("Collapsed React Native warning node must have rect");let n=Math.min(e.rect.height,52),r=Math.min(36,Math.max(18,.45*n));return{x:Math.round((t=e.rect.x+e.rect.width-r,a=e.rect.x+1,Math.min(e.rect.x+e.rect.width-1,Math.max(a,t)))),y:Math.round(e.rect.y+n/2)}}(r),ref:r.ref,label:ai(r)}:null}function t6(e){return"dismiss"===e||"close"===e||["x","\xd7","✕","✖","⨯"].includes(e)}function t7(e){return/^minimi[sz]e$/.test(e)}function t9(e){return!e.rect||e.rect.height<=180}function ae(e,t,a=()=>!0){let n=[];for(let r of e)r.ref&&a(r)&&[r.label,r.value,r.identifier].map(e=>e?.trim().toLowerCase()).filter(e=>!!e).some(e=>t(e))&&n.push(r);return n}function at(e){return e.map(e=>e.ref)}function aa(e){return e.find(e=>e.rect)??null}function an(e,t){if(!e.rect)throw Error("React Native overlay target node must have rect");return{action:t,point:u(e.rect),ref:e.ref,label:ai(e)}}function ar(e){return"dismiss"===ai(e)?.trim().toLowerCase()?"dismiss":"close"}function ai(e){return e.label??e.value??e.identifier}function as(e){return e.map(e=>({index:e.index,depth:e.depth,parentIndex:e.parentIndex,type:e.type,role:e.role,subrole:e.subrole,label:e.label,value:e.value,identifier:e.identifier,enabled:e.enabled,selected:e.selected,focused:e.focused,hittable:e.hittable,rect:e.rect,bundleId:e.bundleId,appName:e.appName,windowTitle:e.windowTitle,surface:e.surface,hiddenContentAbove:e.hiddenContentAbove,hiddenContentBelow:e.hiddenContentBelow}))}function ao(e){return"text"===e||"label"===e||"any"===e}function al(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}function ac(e){return e.clock?.now()??Date.now()}async function ad(e,t){e.clock?await e.clock.sleep(t):await new Promise(e=>setTimeout(e,t))}let ap=async(e,t)=>{var a;let n,r,i=await ah(e,t),s=function(e){var t,a,n,r,i;let{previous:s,current:o,options:l,identity:c}=e;if(!0===l.forceFull||!0===l.raw||!s||!1===s.comparisonSafe||!1===o.comparisonSafe||(t=s,a=o,n=c,t.backend&&a.backend&&t.backend!==a.backend||n?.previousAppBundleId&&n.currentAppBundleId&&n.previousAppBundleId!==n.currentAppBundleId)||!s.presentationKey||s.presentationKey!==o.presentationKey||(r=s,i=o,r.truncated!==i.truncated||JSON.stringify(as(r.nodes))!==JSON.stringify(as(i.nodes))))return;let d=l.scope?.trim();return{ageMs:Math.max(0,o.createdAt-s.createdAt),nodeCount:o.nodes.length,...!0===l.interactiveOnly?{interactiveOnly:!0}:{},...d?{scope:d}:{}}}({previous:i.session?.snapshot,current:i.snapshot,options:t,identity:{previousAppBundleId:i.session?.appBundleId,currentAppBundleId:i.result.appBundleId??i.session?.appBundleId}});return await e.sessions.set(am(t.session,i)),{nodes:i.snapshot.nodes,truncated:i.snapshot.truncated??!1,visibility:function(e){var t;let{nodes:a,backend:n,snapshotRaw:r}=e;if(r||"macos-helper"===(t=n)||"linux-atspi"===t)return{partial:!1,visibleNodeCount:a.length,totalNodeCount:a.length,reasons:[]};let i=er(a),s=new Set;return i.hiddenCount>0&&s.add("offscreen-nodes"),i.nodes.some(e=>e.hiddenContentAbove)&&s.add("scroll-hidden-above"),i.nodes.some(e=>e.hiddenContentBelow)&&s.add("scroll-hidden-below"),{partial:s.size>0,visibleNodeCount:i.nodes.length,totalNodeCount:a.length,reasons:[...s]}}({nodes:i.snapshot.nodes,backend:i.snapshot.backend,snapshotRaw:t.raw}),...i.result.androidSnapshot?{androidSnapshot:i.result.androidSnapshot}:{},...i.warnings.length>0?{warnings:i.warnings}:{},...s?{unchanged:s}:{},...(n=(a=i).result.appName??a.session?.appName,r=a.result.appBundleId??a.session?.appBundleId,{...n||r?{appName:n??r}:{},...r?{appBundleId:r}:{}})}},au=async(e,t)=>{let a=await ah(e,t),n=!0===t.interactiveOnly,r=a.session?.snapshot,i=am(t.session,a);if(!r){let t=function(e,t={}){return t5(e,t).length}(a.snapshot.nodes,{flatten:n});return await e.sessions.set(i),{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:t},lines:[],...a.warnings.length>0?{warnings:a.warnings}:{}}}let s=function(e,t,a={}){let n=function(e,t){let a=e.length,n=t.length,r=a+n,i=new Map,s=[];i.set(1,0);for(let o=0;o<=r;o+=1){s.push(new Map(i));for(let r=-o;r<=o;r+=2){let l=r===-o||r!==o&&t3(i,r-1)<t3(i,r+1)?t3(i,r+1):t3(i,r-1)+1,c=l-r;for(;l<a&&c<n&&e[l].comparable===t[c].comparable;)l+=1,c+=1;if(i.set(r,l),l>=a&&c>=n)return function(e,t,a,n,r){let i=[],s=n,o=r;for(let n=e.length-1;n>=0;n-=1){let r=e[n],l=s-o,c=l===-n||l!==n&&t3(r,l-1)<t3(r,l+1)?l+1:l-1,d=t3(r,c),p=d-c;for(;s>d&&o>p;)i.push({kind:"unchanged",text:a[o-1].text}),s-=1,o-=1;if(0===n)break;s===d?(i.push({kind:"added",text:a[p].text}),o=p):(i.push({kind:"removed",text:t[d].text}),s=d)}return i.reverse(),i}(s,e,t,a,n)}}return[]}(t5(e,a),t5(t,a)),r={additions:0,removals:0,unchanged:0};for(let e of n)"added"===e.kind&&(r.additions+=1),"removed"===e.kind&&(r.removals+=1),"unchanged"===e.kind&&(r.unchanged+=1);return{summary:r,lines:n}}(r.nodes,a.snapshot.nodes,{flatten:n});return await e.sessions.set(i),{mode:"snapshot",baselineInitialized:!1,summary:s.summary,lines:s.lines,...a.warnings.length>0?{warnings:a.warnings}:{}}};async function ah(e,t){var a,n,r,i,s,o;let l,c,d,p;if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let u=t.session??"default",m=await e.sessions.get(u),f=await e.backend.captureSnapshot({session:u,requestId:t.requestId,appId:m?.appId,appBundleId:m?.appBundleId,signal:t.signal??e.signal,metadata:t.metadata},{interactiveOnly:t.interactiveOnly,compact:t.compact,depth:t.depth,scope:t.scope,raw:t.raw}),g=(n=f,r=e,a=n.snapshot?n.snapshot:{nodes:n.nodes??[],truncated:n.truncated,backend:n.backend,createdAt:ac(r)},a.presentationKey?a:{...a,presentationKey:h(t)}),w=ac(e);return{snapshot:g,result:f,session:m,warnings:((l=[...(i={result:f,snapshot:g,options:t,session:m,capturedAt:g.createdAt??w,runtimeNow:w}).result.warnings??[]]).push(...function(e){let t=e.result.analysis;if("android"!==e.snapshot.backend||!0!==e.options.interactiveOnly||e.snapshot.nodes.length>0||!t||(t.rawNodeCount??0)<12)return[];let a=[`Interactive snapshot is empty after filtering ${t.rawNodeCount} raw Android nodes. Likely causes: the app content is not accessibility-visible yet, a transient route change, or depth/filter options hid the target.`];return"number"==typeof e.options.depth&&"number"==typeof t.maxDepth&&t.maxDepth>=e.options.depth+2&&a.push(`Interactive output is empty at depth ${e.options.depth}; retry without -d.`),a}(i)),(c=function(e){if(e?.backend!=="uiautomator-dump")return;let t=e.fallbackReason?` Reason: ${e.fallbackReason}`:"";return`Android snapshot helper unavailable; using stock UIAutomator dump, which can time out on busy React Native UIs.${t}`}(i.result.androidSnapshot))&&l.push(c),(d=function(e){if(t4(e).detected)return"Hint: React Native warning/error overlay detected. It overlays part of the app and should be handled before interacting.\nRun: agent-device react-native dismiss-overlay\nThen run: agent-device snapshot -i -c\nUse refs from the new snapshot."}(i.snapshot.nodes))&&l.push(d),(p=function(e){var t,a;let n=e.session?.snapshot,r=!!n&&[e.capturedAt,e.runtimeNow].some(e=>{let t=e-n.createdAt;return t>=0&&t<=2e3});if(!e.result.freshness&&n&&r&&(t=n.nodes.length,a=e.snapshot.nodes.length,!(t<12)&&a<=Math.floor(.2*t)))return af}(i))&&l.push(p),l.push(...(s=i.result.freshness,o=i.snapshot.backend,s?.staleAfterRetries&&"android"===o?"stuck-route"===s.reason?[`Recent ${s.action} was followed by a nearly identical snapshot after ${s.retryCount} automatic retr${1===s.retryCount?"y":"ies"}. If you expected navigation or submit, the tree may still be stale. Use screenshot as visual truth, wait briefly, then re-snapshot once.`]:"sharp-drop"===s.reason?[af]:[]:[])),Array.from(new Set(l)))}}function am(e,t){let a=t.session?.name??e??"default";return{...t.session??{name:a},name:a,snapshot:t.snapshot,appName:t.result.appName??t.session?.appName,appBundleId:t.result.appBundleId??t.session?.appBundleId}}let af="Recent snapshots dropped sharply in node count, which suggests stale or mid-transition UI. Use screenshot as visual truth, wait briefly, then re-snapshot once.";function ag(e){return["visible","hidden","exists","editable","selected","text"].includes(e)}function ab(e){let{predicate:t,node:a,nodes:n,expectedText:r,platform:i}=e,s=E(a),o=U(a,i),l=!0===a.selected,c="text"===t?T(a):function(e,t){if(!0===e.hittable)return!0;if(aw(e.rect))return function(e,t){return eo(e,t)}(e,t);if(e.rect)return!1;let a=function(e,t){let a=new Map(t.map(e=>[e.index,e])),n=e,r=new Set;for(;"number"==typeof n.parentIndex&&!r.has(n.index);){r.add(n.index);let e=a.get(n.parentIndex);if(!e)break;if(function(e){let t=K(e.type??"");return!(t.includes("application")||t.includes("window")||t.includes("scrollview")||t.includes("tableview")||t.includes("collectionview"))&&"table"!==t&&"list"!==t&&"listview"!==t&&(!0===e.hittable||aw(e.rect))}(e))return e;n=e}return null}(e,t);return!!a&&(!0===a.hittable||!!aw(a.rect)&&function(e,t){return eo(e,t)}(a,t))}(a,n),d=!1;switch(t){case"visible":d=c;break;case"hidden":d=!c;break;case"editable":d=o;break;case"selected":d=l;break;case"text":d=s===(r??"")}let p="text"===t?`expected="${r??""}" actual="${s}"`:`actual=${JSON.stringify({visible:c,editable:o,selected:l})}`;return{pass:d,actualText:s,details:p}}function aw(e){return!!(e&&Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.width)&&Number.isFinite(e.height)&&e.width>0&&e.height>0)}async function ay(e,t){let a=t??"default",n=await e.sessions.get(a);if(!n)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");if(!n.snapshot)throw new b("INVALID_ARGS","No snapshot in session. Run snapshot first.");return{sessionName:a,session:n,snapshot:n.snapshot}}async function av(e,t,a={updateSession:!0}){let n=e.backend.captureSnapshot;if(!n)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let r=t.session??"default",i=await e.sessions.get(r),s=await n(al(e,t),{interactiveOnly:!1,compact:!1,depth:t.depth,scope:a.scope??t.scope,raw:t.raw}),o=s.snapshot??{nodes:s.nodes??[],truncated:s.truncated,backend:s.backend,createdAt:ac(e)};return a.updateSession&&i&&await e.sessions.set({...i,snapshot:o}),{sessionName:r,session:i,snapshot:o}}async function ak(e,t,a){if(e.backend.readText){let n=await e.backend.readText(al(e,{session:t.sessionName}),a);if(n.text.trim())return n.text}return X(a)}let ax=async(e,t)=>{let a=t.locator??"any";if(!t.query)throw new b("INVALID_ARGS","find requires a value");if("wait"===t.action)return await aL(e,t,a);let n=await av(e,t,{updateSession:!0,scope:ao(a)?t.query:void 0}),r=H(n.snapshot.nodes,a,t.query,{requireRect:!1}).matches[0];if(!r)throw new b("COMMAND_FAILED","find did not match any element");if("exists"===t.action)return{kind:"found",found:!0};let i=`@${r.ref}`;return"get_attrs"===t.action?{kind:"attrs",ref:i,node:r}:{kind:"text",ref:i,text:await ak(e,n,r),node:r}},aA=async(e,t)=>{if("ref"===t.target.kind){let a=await ay(e,t.session),n=function(e,t,a){let n=p(t);if(!n)throw new b("INVALID_ARGS",a.invalidRefMessage);let r=m(e,n)??(a.fallbackLabel.length>0?G(e,a.fallbackLabel):null);if(!r)throw new b("COMMAND_FAILED",a.notFoundMessage);return{ref:n,node:r}}(a.snapshot.nodes,t.target.ref,{fallbackLabel:t.target.fallbackLabel??"",invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${t.target.ref} not found`}),r=F(n.node,e.backend.platform,{action:"get"}),i={kind:"ref",ref:`@${n.ref}`};return"attrs"===t.property?{kind:"attrs",target:i,node:n.node,selectorChain:r}:{kind:"text",target:i,text:await ak(e,a,n.node),node:n.node,selectorChain:r}}let a=await aT(e,t,t.session??"default",{selector:t.target.selector,disambiguateAmbiguous:"text"===t.property}),n=F(a.node,e.backend.platform,{action:"get"});if("attrs"===t.property)return{kind:"attrs",target:{kind:"selector",selector:a.selector},node:a.node,selectorChain:n};let r=await ak(e,a.capture,a.node);return{kind:"text",target:{kind:"selector",selector:a.selector},text:r,node:a.node,selectorChain:n}},aD=async(e,t)=>{let a=await aA(e,{...t,property:"text",target:t.target});if("text"!==a.kind)throw new b("COMMAND_FAILED","getText returned non-text result");return a},aI=async(e,t)=>{let a=await aA(e,{...t,property:"attrs",target:t.target});if("attrs"!==a.kind)throw new b("COMMAND_FAILED","getAttrs returned non-attrs result");return a},aR=async(e,t)=>{if(!ag(t.predicate))throw new b("INVALID_ARGS","is requires predicate: visible|hidden|exists|editable|selected|text");if("text"===t.predicate&&!t.expectedText)throw new b("INVALID_ARGS","is text requires expected text value");let a=await av(e,t,{updateSession:!0}),n=C(t.selector);if("exists"===t.predicate){let r=B(a.snapshot.nodes,n,{platform:e.backend.platform});if(!r)throw new b("COMMAND_FAILED",Y(n,[],{unique:!1}));return{predicate:t.predicate,pass:!0,selector:r.selector.raw,matches:r.matches,selectorChain:n.selectors.map(e=>e.raw)}}let r=q(a.snapshot.nodes,n,{platform:e.backend.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:!1});if(!r)throw new b("COMMAND_FAILED",Y(n,[],{unique:!0}));let i=ab({predicate:t.predicate,node:r.node,nodes:a.snapshot.nodes,expectedText:t.expectedText,platform:e.backend.platform});if(!i.pass)throw new b("COMMAND_FAILED",`is ${t.predicate} failed for selector ${r.selector.raw}: ${i.details}`);return{predicate:t.predicate,pass:!0,selector:r.selector.raw,..."text"===t.predicate?{text:i.actualText}:{},selectorChain:n.selectors.map(e=>e.raw)}},aS=async(e,t)=>await aR(e,{...t,predicate:"visible",selector:t.target.selector}),aM=async(e,t)=>await aR(e,{...t,predicate:"hidden",selector:t.target.selector}),aN=async(e,t)=>{if("sleep"===t.target.kind)return await ad(e,t.target.durationMs),{kind:"sleep",waitedMs:t.target.durationMs};if("ref"===t.target.kind){let a=await ay(e,t.session),n=p(t.target.ref);if(!n)throw new b("INVALID_ARGS",`Invalid ref: ${t.target.ref}`);let r=m(a.snapshot.nodes,n),i=r?j(r,a.snapshot.nodes):void 0;if(!i)throw new b("COMMAND_FAILED",`Ref ${t.target.ref} not found or has no label`);return await aE(e,t,i,t.target.timeoutMs)}if("selector"===t.target.kind)return await aP(e,t,t.target.selector,t.target.timeoutMs);if(!t.target.text)throw new b("INVALID_ARGS","wait requires text");return await aE(e,t,t.target.text,t.target.timeoutMs)},aO=async(e,t)=>{let a=await aN(e,{...t,target:{kind:"text",text:t.text,timeoutMs:t.timeoutMs}});if("text"!==a.kind)throw new b("COMMAND_FAILED","waitForText returned non-text result");return a};async function aL(e,t,a){let n=t.timeoutMs??1e4,r=ac(e);for(;ac(e)-r<n;){if(H((await av(e,t,{updateSession:!0,scope:ao(a)?t.query:void 0})).snapshot.nodes,a,t.query,{requireRect:!1}).matches[0])return{kind:"found",found:!0,waitedMs:ac(e)-r};await ad(e,300)}throw new b("COMMAND_FAILED","find wait timed out")}async function aP(e,t,a,n){let r=n??1e4,i=ac(e),s=C(a);for(;ac(e)-i<r;){let a=B((await av(e,t,{updateSession:!0})).snapshot.nodes,s,{platform:e.backend.platform});if(a)return{kind:"selector",selector:a.selector.raw,waitedMs:ac(e)-i};await ad(e,300)}throw new b("COMMAND_FAILED",`wait timed out for selector: ${a}`)}async function aE(e,t,a,n){let r=n??1e4,i=ac(e);for(;ac(e)-i<r;){if(e.backend.findText?(await e.backend.findText(al(e,t),a)).found:await aC(e,t,a))return{kind:"text",text:a,waitedMs:ac(e)-i};await ad(e,300)}throw new b("COMMAND_FAILED",`wait timed out for text: ${a}`)}async function aC(e,t,a){return!!G((await av(e,t,{updateSession:!0})).snapshot.nodes,a)}async function aT(e,t,a,n){let r=await av(e,{...t,session:a},{updateSession:!0}),i=C(n.selector),s=q(r.snapshot.nodes,i,{platform:e.backend.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:n.disambiguateAmbiguous});if(!s)throw new b("COMMAND_FAILED",Y(i,[],{unique:!0}));return{capture:r,node:s.node,selector:s.selector.raw,ref:`@${s.node.ref}`}}function aU(e){let t=a_(e);if(!t)return null;let a=u(t);return Number.isFinite(a.x)&&Number.isFinite(a.y)?a:null}function a_(e){if(!e)return null;let t=Number(e.x),a=Number(e.y),n=Number(e.width),r=Number(e.height);return Number.isFinite(t)&&Number.isFinite(a)&&Number.isFinite(n)&&Number.isFinite(r)&&!(n<0)&&!(r<0)?{x:t,y:a,width:n,height:r}:null}let a$=["button","link","menuitem","tabitem","textfield","searchfield","securetextfield","checkbox","radio","switch","cell"];function aF(e,t){var a;let n=function(e,t){let a=a_(t.rect);if(!a)return null;let n=t,r=new Set;for(;!r.has(n.ref);){r.add(n.ref);let t=e.filter(e=>{if(e.parentIndex!==n.index||!e.hittable)return!1;let t=a_(e.rect);return!!t&&aq(t,a)});if(1!==t.length)break;n=t[0]}return n===t?null:n}(e,t);if(n?.rect&&aU(n.rect))return{node:n,reason:"same-rect-descendant"};if([(a=t).type,a.role,a.subrole].map(e=>K(e??"")).some(aB)&&t.rect&&aU(t.rect))return{node:t,reason:"semantic-target"};let r=$(e,t);return r?.rect&&aU(r.rect)?!function(e,t,a){var n,r,i,s;let o,l,c,d=a_(e.rect),p=a_(t.rect);if(!d||!p)return!1;let h=function(e,t){let a=u(t),n=e.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}).map(e=>a_(e.rect)).filter(e=>null!==e);if(0===n.length)return null;let r=n.filter(e=>J(e,a.x,a.y));return W(r.length>0?r:n)}(a,d);return!!h&&(n=p,r=h,o=(i=n,s=r,Math.max(0,Math.min(i.x+i.width,s.x+s.width)-Math.max(i.x,s.x))*Math.max(0,Math.min(i.y+i.height,s.y+s.height)-Math.max(i.y,s.y))),l=n.width*n.height,c=r.width*r.height,!(o<=0)&&!(l<=0)&&!(c<=0)&&!!(o/c>=.9)&&!!(o/l>=.8))&&!aq(d,p)}(t,r,e)?{node:r,reason:"hittable-ancestor"}:{node:t,reason:"overly-broad-ancestor"}:{node:t,reason:"original"}}function aB(e){return"tab"===e||a$.some(t=>e.includes(t))}function aq(e,t){return .5>=Math.abs(e.x-t.x)&&.5>=Math.abs(e.y-t.y)&&.5>=Math.abs(e.width-t.width)&&.5>=Math.abs(e.height-t.height)}async function aG(e,t,a){if(await aV(e,t,a.action),"point"===t.target.kind)return{kind:"point",point:{x:t.target.x,y:t.target.y}};if("ref"===t.target.kind){let n=await aY(e,t,t.target),r=n.resolved,i=a.promoteToHittableAncestor?aF(n.snapshot.nodes,r.node).node:r.node;return function(e,t,a,n){let r=e.rect?el(e,t):null;if(!(!e.rect||!r||eo(e,t)))throw new b("COMMAND_FAILED",`Ref ${a} is off-screen and not safe to ${n}`,{reason:"offscreen_ref",ref:p(a),rect:e.rect,viewport:r,hint:`Use scroll with the direction from the off-screen summary, take a fresh snapshot, then retry ${n} with the new ref or a selector.`})}(i,n.snapshot.nodes,t.target.ref,a.action),{kind:"ref",point:az(i,`Ref ${t.target.ref} not found or has invalid bounds`),target:{kind:"ref",ref:`@${r.ref}`},node:i,selectorChain:F(i,e.backend.platform,{action:"fill"===a.action?"fill":"click"}),refLabel:j(i,n.snapshot.nodes)}}let n=await aj(e,t,a.requireInteractive),r=C(t.target.selector),i=q(n.snapshot.nodes,r,{platform:e.backend.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0});if(!i||!i.node.rect)throw new b("COMMAND_FAILED",Y(r,i?.diagnostics??[],{unique:!0}));let s=a.promoteToHittableAncestor?aF(n.snapshot.nodes,i.node).node:i.node;return{kind:"selector",point:az(s,`Selector ${i.selector.raw} resolved to invalid bounds`),target:{kind:"selector",selector:i.selector.raw},node:s,selectorChain:F(s,e.backend.platform,{action:"fill"===a.action?"fill":"click"}),refLabel:j(s,n.snapshot.nodes)}}async function aj(e,t,a){if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION","snapshot is not supported by this backend");let n=t.session??"default",r=await e.sessions.get(n);if(!r)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");let i=await e.backend.captureSnapshot(al(e,t),{interactiveOnly:a,compact:a}),s=i.snapshot??{nodes:i.nodes??[],truncated:i.truncated,backend:i.backend,createdAt:ac(e)};return await e.sessions.set({...r,snapshot:s}),{snapshot:s}}async function aV(e,t,a){if("macos"!==e.backend.platform)return;let n=await aX(e,t);if(("desktop"===n||"menubar"===n)&&("menubar"!==n||"click"!==a&&"press"!==a))throw new b("UNSUPPORTED_OPERATION",`${a} is not supported on macOS ${n} sessions yet. Open an app session to act, or use the ${n} surface to inspect.`)}async function aX(e,t){let a=await e.sessions.get(t.session??"default");return a?.metadata?.surface}async function aY(e,t,a){let n=t.session??"default",r=await e.sessions.get(n);if(!r)throw new b("SESSION_NOT_FOUND","No active session. Run open first.");if(!r.snapshot)throw new b("INVALID_ARGS","No snapshot in session. Run snapshot first.");let i=a.fallbackLabel??"",s=aK(r.snapshot.nodes,a.ref,{fallbackLabel:i,requireRect:!0});if(s)return{snapshot:r.snapshot,resolved:s};let o=await aj(e,t,!0),l=aK(o.snapshot.nodes,a.ref,{fallbackLabel:i,requireRect:!0});if(!l)throw new b("COMMAND_FAILED",`Ref ${a.ref} not found or has no bounds`);return{...o,resolved:l}}function aK(e,t,a){let n=p(t);if(!n)throw new b("INVALID_ARGS",`Invalid ref: ${t}`);let r=m(e,n);if(aH(r,a.requireRect))return{ref:n,node:r};let i=a.fallbackLabel.length>0?G(e,a.fallbackLabel):null;return aH(i,a.requireRect)?{ref:n,node:i}:null}function az(e,t){if(!e.rect)throw new b("COMMAND_FAILED",t);let a=u(e.rect);if(!Number.isFinite(a.x)||!Number.isFinite(a.y))throw new b("COMMAND_FAILED",t);return a}function aH(e,t){if(!e)return!1;if(!t)return!0;if(!e.rect)return!1;let{x:a,y:n,width:r,height:i}=e.rect;if(!Number.isFinite(Number(a))||!Number.isFinite(Number(n))||!Number.isFinite(Number(r))||!Number.isFinite(Number(i))||0>Number(r)||0>Number(i))return!1;let s=u(e.rect);return Number.isFinite(s.x)&&Number.isFinite(s.y)}async function aJ(e,t){let a=t.target??{kind:"viewport"};return"viewport"===a.kind?(await aV(e,t,"scroll"),{kind:"viewport"}):await aG(e,{...t,target:a},{action:"scroll",requireInteractive:!1,promoteToHittableAncestor:!1})}async function aW(e,t){if(t.from){var a;if("x"in(a=t.from)&&"y"in a)return await aV(e,t,"swipe"),{point:a0(t.from,"from")};let n=await aG(e,{...t,target:t.from},{action:"swipe",requireInteractive:!1,promoteToHittableAncestor:!1});return{point:n.point,target:n}}if(!t.direction)throw new b("INVALID_ARGS","swipe requires from+to or a direction");return await aV(e,t,"swipe"),{point:u(function(e){let t=e.filter(t=>eo(t,e)).map(e=>e.rect).filter(a2),a=t.length>0?t:e.map(e=>e.rect).filter(a2);if(0===a.length)throw new b("COMMAND_FAILED","Cannot infer viewport for directional swipe");let n=Math.min(...a.map(e=>e.x)),r=Math.min(...a.map(e=>e.y));return{x:n,y:r,width:Math.max(...a.map(e=>e.x+e.width))-n,height:Math.max(...a.map(e=>e.y+e.height))-r}}((await aj(e,t,!1)).snapshot.nodes)),target:{kind:"viewport"}}}async function aQ(e,t,a,n,r){if(!e.backend.captureSnapshot)throw new b("UNSUPPORTED_OPERATION",`scroll ${a} requires snapshot support to verify hidden content before scrolling`);let{captureSnapshot:i}=e.backend;return await eS({edge:a,target:n,scope:r,captureNodes:async a=>{let n=await i(al(e,t),{compact:!0,scope:a});return n.snapshot?.nodes??n.nodes??[]}})}function aZ(e,t){switch(e){case"up":case"down":case"left":case"right":return e;default:throw new b("INVALID_ARGS",`${t} must be up, down, left, or right`)}}function a0(e,t){let a=Number(e.x),n=Number(e.y);if(!Number.isFinite(a)||!Number.isFinite(n))throw new b("INVALID_ARGS",`${t} point requires finite x and y`);return{x:a,y:n}}function a1(e,t){if(!Number.isFinite(e)||e<=0)throw new b("INVALID_ARGS",`${t} must be a positive number`);return e}function a2(e){return!!(e&&e.width>0&&e.height>0)}function a5(e){return e&&"object"==typeof e?e:void 0}async function a3(e,t,a){let n=await aG(e,t,{action:a,requireInteractive:!0,promoteToHittableAncestor:!0});if(!e.backend.tap)throw new b("UNSUPPORTED_OPERATION","tap is not supported by this backend");let r=a4(await e.backend.tap(al(e,t),n.point,{button:t.button,count:t.count,intervalMs:t.intervalMs,holdMs:t.holdMs,jitterPx:t.jitterPx,doubleTap:t.doubleTap}));return{...n,...r?{backendResult:r}:{}}}function a4(e){return e&&"object"==typeof e?e:void 0}function a8(e,t){if(void 0!==e)return a6(e,t)}function a6(e,t){let a=e?.trim();if(!a)throw new b("INVALID_ARGS",`${t} must be a non-empty string`);return a}function a7(e){return!!(e&&"object"==typeof e)}function a9(e){return e&&"object"==typeof e?e:void 0}let ne=/^[A-Za-z0-9_.:-]{1,64}$/;async function nt(e,t){if(!t||"object"!=typeof t)throw new b("INVALID_ARGS","apps.push requires an input");if("json"===t.kind)return na(t.payload,"apps.push JSON payload",8192),{backendInput:{kind:"json",payload:t.payload},inputKind:"json"};let a=await e3(e,t,{usage:"apps.push",field:"input"});return{backendInput:{kind:"file",path:a.path},inputKind:"file",...a.cleanup?{cleanup:a.cleanup}:{}}}function na(e,t,a){if(function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))throw new b("INVALID_ARGS",`${t} must be a JSON object`)}(e,t),Buffer.byteLength(function(e,t){try{let a=JSON.stringify(e);if("string"!=typeof a)throw new b("INVALID_ARGS",`${t} must be JSON-serializable`);return a}catch{throw new b("INVALID_ARGS",`${t} must be JSON-serializable`)}}(e,t),"utf8")>a)throw new b("INVALID_ARGS",`${t} exceeds ${a} bytes`)}function nn(e,t){return{session:t.session,requestId:t.requestId,signal:t.signal??e.signal,metadata:t.metadata}}function nr(e){return e&&"object"==typeof e?e:void 0}async function ni(e,t,a){let n="reinstall"===a?"reinstallApp":"installApp",r=e.backend[n];if(!r)throw new b("UNSUPPORTED_OPERATION",`admin.${a} is not supported by this backend`);let i="app"in t&&void 0!==t.app?a6(t.app,"app"):void 0;if("installFromSource"!==a&&!i)throw new b("INVALID_ARGS",`admin.${a} requires app`);let s=al(e,t),o=await ns(e,s,t.source);try{var l,c,d,p,u;let t,n,h,m,f,g,b,w,y=await r.call(e.backend,s,{...i?{app:i}:{},source:o.source});return l=a,c=i,d=o.source,p=y,t=nd(p),n=nc(p,"appName"),h=nc(p,"appId"),m=nc(p,"bundleId"),f=nc(p,"packageName"),g=nc(p,"launchTarget"),b=nc(p,"installablePath"),w=nc(p,"archivePath"),{kind:"reinstall"===l?"appReinstalled":"installFromSource"===l?"appInstalledFromSource":"appInstalled",...c?{app:c}:{},source:d,...h?{appId:h}:{},...n?{appName:n}:{},...m?{bundleId:m}:{},...f?{packageName:f}:{},...g?{launchTarget:g}:{},...b?{installablePath:b}:{},...w?{archivePath:w}:{},...t?{backendResult:t}:{},...D(`${"reinstall"===l?"Reinstalled":"Installed"}: ${n??g??c??(u=d,"path"===u.kind?u.path:"uploadedArtifact"===u.kind?u.id:u.url)}`)}}finally{await o.cleanup?.()}}async function ns(e,t,a){let n=nl(a),r=await no(e,n);try{let a=e.backend.resolveInstallSource?await e.backend.resolveInstallSource(t,r.source):r.source;return{source:nl(a),...r.cleanup?{cleanup:r.cleanup}:{}}}catch(e){if(r.cleanup)try{await r.cleanup()}catch{}throw e}}async function no(e,t){if("url"===t.kind)return{source:t};let a=await e3(e,t,{usage:"admin.install",field:"source"});return{source:{kind:"path",path:a.path},...a.cleanup?{cleanup:a.cleanup}:{}}}function nl(e){if(!e||"object"!=typeof e)throw new b("INVALID_ARGS","install source is required");if("path"===e.kind)return{kind:"path",path:a6(e.path,"source.path")};if("uploadedArtifact"===e.kind)return{kind:"uploadedArtifact",id:a6(e.id,"source.id")};if("url"===e.kind){let t=a6(e.url,"source.url");return function(e){let t;try{t=new URL(e)}catch{throw new b("INVALID_ARGS",`Invalid install source URL: ${e}`)}if("http:"!==t.protocol&&"https:"!==t.protocol)throw new b("INVALID_ARGS","Install source URL must use http or https")}(t),{kind:"url",url:t}}throw new b("INVALID_ARGS","install source kind must be path, uploadedArtifact, or url")}function nc(e,t){let a=e[t];return"string"==typeof a&&a.length>0?a:void 0}function nd(e){return e&&"object"==typeof e?e:void 0}function np(e,t){if("start"===e||"stop"===e)return e;throw new b("INVALID_ARGS",`${t} action must be start or stop`)}function nu(e,t,a,n){return{kind:"start"===e?n.startKind:n.stopKind,action:e,...a?{artifact:a}:{},backendResult:t,...D("start"===e?n.startMessage:n.stopMessage)}}let nh=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i,nm=/\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g;function nf(e){var t,a;let n=!1,r=e;return{value:(t=r=(r=(r=(r=(r=r.replaceAll(/(authorization|token|secret|password|passwd|api[-_]?key)=([^&\s]+)/gi,(e,t)=>(n=!0,`${String(t)}=[REDACTED]`))).replaceAll(/("(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)"\s*:\s*")([^"]*)(")/gi,(e,t,a,r)=>(n=!0,`${String(t)}[REDACTED]${String(r)}`))).replaceAll(/\b(Bearer\s+)([^\s",;]+)/gi,(e,t)=>(n=!0,`${String(t)}[REDACTED]`))).replaceAll(/((?:authorization|cookie|token|secret|password|passwd|api[-_]?key)\s*[:=]\s*)([^\s,;&]+)/gi,(e,t)=>(n=!0,`${String(t)}[REDACTED]`))).replaceAll(nm,()=>(n=!0,"[REDACTED]")),a=()=>{n=!0},r=/(https?:\/\/|token|secret|password|authorization|cookie|api[-_]?key)/i.test(t)?t.replaceAll(/https?:\/\/[^\s"'<>)]+/gi,e=>{let t=ng(e);return t?(t.redacted&&a(),t.value):e}):t),redacted:n}}function ng(e){try{let t=new URL(e),a=function(e){let t=!1;for(let a of Array.from(e.searchParams.keys()))nh.test(a)&&(e.searchParams.set(a,"[REDACTED]"),t=!0);return t}(t);return(t.username||t.password)&&(t.username="REDACTED",t.password="REDACTED",a=!0),{value:t.toString(),redacted:a}}catch{return}}let nb=/(?:authorization|cookie|token|secret|password|passwd|api[-_]?key)/i;function nw(e){if(!e)return{redacted:!1};let t=!1,a={};for(let[n,r]of Object.entries(e))if(nb.test(n))a[n]="[REDACTED]",t=!0;else{let e=nx(r,2048);a[n]=e.value??"",t||=e.redacted}return{value:a,redacted:t}}function ny(e){return void 0===e?{redacted:!1}:function(e){try{let t=JSON.parse(e),a=nk(t,nf);return nA(JSON.stringify(a.value),2048,a.redacted)}catch{return}}(e)??nx(e,2048)}function nv(e){return nk(e,e=>nx(e,2048))}function nk(e,t){if(void 0===e)return{redacted:!1};if("string"==typeof e)return t(e);if(!e||"object"!=typeof e)return{value:e,redacted:!1};if(Array.isArray(e)){let a=!1;return{value:e.map(e=>{let n=nk(e,t);return a||=n.redacted,n.value}),redacted:a}}let a=!1,n={};for(let[r,i]of Object.entries(e)){if(nb.test(r)){n[r]="[REDACTED]",a=!0;continue}let e=nk(i,t);n[r]=e.value,a||=e.redacted}return{value:n,redacted:a}}function nx(e,t){if(void 0===e)return{redacted:!1};let a=nf(e);return nA(a.value,t,a.redacted)}function nA(e,t,a){if(void 0===e)return{redacted:a};let n=e;return n.length>t&&(n=`${n.slice(0,t)}...[truncated]`,a=!0),{value:n,redacted:a}}async function nD(e,t){let a=al(e,t),n=t.session?await e.sessions.get(t.session):void 0;return{...a,...t.appId??n?.appId?{appId:t.appId??n?.appId}:{},...t.appBundleId??n?.appBundleId?{appBundleId:t.appBundleId??n?.appBundleId}:{}}}function nI(e,t,a,n){return{...nR(e),...void 0!==e.cursor?{cursor:a6(e.cursor,"cursor")}:{},limit:void 0===e.limit?t:eU(e.limit,n,1,a)}}function nR(e){return{...void 0!==e.since?{since:a6(e.since,"since")}:{},...void 0!==e.until?{until:a6(e.until,"until")}:{}}}function nS(e,t,a=50){if(!Array.isArray(e))throw new b("INVALID_ARGS",`${t} must be an array of strings`);if(e.length>a)throw new b("INVALID_ARGS",`${t} must contain at most ${a} entries`);return e.map((e,a)=>a6(e,`${t}[${a}]`))}let nM=e6,nN=tB,nO=ap,nL=au,nP=ax,nE=aA,nC=aD,nT=aI,nU=aR,n_=aS,n$=aM,nF=aN,nB=aO,nq=async(e,t)=>await a3(e,t,"click"),nG=async(e,t)=>await a3(e,t,"press"),nj=async(e,t)=>{var a;if(!t.text)throw new b("INVALID_ARGS","fill requires text");let n=await aG(e,t,{action:"fill",requireInteractive:!0,promoteToHittableAncestor:!1});if(!e.backend.fill)throw new b("UNSUPPORTED_OPERATION","fill is not supported by this backend");let r=a4(await e.backend.fill(al(e,t),n.point,t.text,{delayMs:t.delayMs})),i="node"in n?n.node.type??"":"",s=i&&!z(i,e.backend.platform)?`fill target ${a=n,a.target?.kind==="ref"?a.target.ref:a.target?.kind==="selector"?a.target.selector:"point"} resolved to "${i}", attempting fill anyway.`:void 0;return{...n,text:t.text,...s?{warning:s}:{},...r?{backendResult:r}:{}}},nV=async(e,t)=>{let a=t.text;if(!a)throw new b("INVALID_ARGS","type requires text");let n=eR(a);if(n)throw new b("INVALID_ARGS",`type does not accept a target ref like "${n}"`,{hint:`Use fill ${n} "text" to target that field, or press ${n} then type "text" to append.`});if(!e.backend.typeText)throw new b("UNSUPPORTED_OPERATION","type is not supported by this backend");let r=eU(t.delayMs??0,"delay-ms",0,1e4),i=a4(await e.backend.typeText(al(e,t),a,{delayMs:r}));return{kind:"text",text:a,delayMs:r,...i?{backendResult:i}:{},...D(`Typed ${Array.from(a).length} chars`)}},nX=async(e,t)=>{let a=await aG(e,t,{action:"focus",requireInteractive:!0,promoteToHittableAncestor:!1});if(!e.backend.focus)throw new b("UNSUPPORTED_OPERATION","focus is not supported by this backend");let n=a5(await e.backend.focus(al(e,t),a.point));return{...a,...n?{backendResult:n}:{},...D(`Focused (${a.point.x}, ${a.point.y})`)}},nY=async(e,t)=>{let a=await aG(e,t,{action:"longPress",requireInteractive:!0,promoteToHittableAncestor:!0});if(!e.backend.longPress)throw new b("UNSUPPORTED_OPERATION","longPress is not supported by this backend");let n=void 0===t.durationMs?void 0:eU(t.durationMs,"durationMs",0,12e4),r=a5(await e.backend.longPress(al(e,t),a.point,{durationMs:n}));return{...a,...void 0!==n?{durationMs:n}:{},...r?{backendResult:r}:{},...D(`Long pressed (${a.point.x}, ${a.point.y})`)}},nK=async(e,t)=>{if(!e.backend.swipe)throw new b("UNSUPPORTED_OPERATION","swipe is not supported by this backend");let a=await aW(e,t),n=function(e,t){if(t.to)return{point:a0(t.to,"to")};let a=aZ(t.direction,"swipe direction"),n=a1(t.distance??200,"swipe distance");switch(a){case"up":return{point:{x:e.x,y:e.y-n},direction:a,distance:n};case"down":return{point:{x:e.x,y:e.y+n},direction:a,distance:n};case"left":return{point:{x:e.x-n,y:e.y},direction:a,distance:n};case"right":return{point:{x:e.x+n,y:e.y},direction:a,distance:n}}}(a.point,t),r=void 0===t.durationMs?void 0:eU(t.durationMs,"durationMs",16,1e4),i=a5(await e.backend.swipe(al(e,t),a.point,n.point,{durationMs:r}));return{kind:"swipe",from:a.point,to:n.point,...n.direction?{direction:n.direction}:{},...void 0!==n.distance?{distance:n.distance}:{},...void 0!==r?{durationMs:r}:{},...a.target?{fromTarget:a.target}:{},...i?{backendResult:i}:{},...D("Swiped")}},nz=async(e,t)=>{var a,n,r,i;let s;if(!e.backend.scroll)throw new b("UNSUPPORTED_OPERATION","scroll is not supported by this backend");let o="bottom"===(a=t.direction)?{direction:"down",edge:"bottom"}:"top"===a?{direction:"up",edge:"top"}:{direction:aZ(a,"scroll direction")},l=(n=t.amount,r="scroll amount",void 0===n?void 0:a1(n,r)),c=function(e,t){if(void 0!==e){if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new b("INVALID_ARGS",`${t} must be a positive integer`);return e}}(t.pixels,"scroll pixels");if(void 0!==l&&void 0!==c)throw new b("INVALID_ARGS","scroll accepts either amount or pixels, not both");let d=await aJ(e,t),p="viewport"===d.kind?{kind:"viewport"}:{kind:"point",point:d.point},u=e.backend.scroll,h=async()=>await u(al(e,t),p,{direction:o.direction,...void 0!==l?{amount:l}:{},...void 0!==c?{pixels:c}:{}}),m=0;if(o.edge){let a=o.edge,n="viewport"===(i=d).kind?{}:{point:i.point,nodeIndex:"node"in i?i.node.index:void 0},r=await eM({edge:a,captureState:async r=>await aQ(e,t,a,n,r),scroll:h});s=r.result,m=r.passes}else s=await h(),m=1;let f=a5(s);return{...d,direction:o.direction,...o.edge?{edge:o.edge,passes:m}:{},...void 0!==l?{amount:l}:{},...void 0!==c?{pixels:c}:{},...f?{backendResult:f}:{},...D(eN(o.direction,o.edge,m,l,c))}},nH=async(e,t)=>{if(!e.backend.pinch)throw new b("UNSUPPORTED_OPERATION","pinch is not supported by this backend");await aV(e,t,"pinch");let a=a1(t.scale,"pinch scale"),n=t.center?await aG(e,{...t,target:t.center},{action:"pinch",requireInteractive:!1,promoteToHittableAncestor:!1}):void 0,r=a5(await e.backend.pinch(al(e,t),{scale:a,...n?{center:n.point}:{}}));return{kind:"pinch",scale:a,...n?{center:n.point,centerTarget:n}:{},...r?{backendResult:r}:{},...D(`Pinched to scale ${a}`)}},nJ=async(e,t={})=>{if(!e.backend.pressBack)throw new b("UNSUPPORTED_OPERATION","system.back is not supported by this backend");let a=t.mode??"in-app";if("in-app"!==a&&"system"!==a)throw new b("INVALID_ARGS","system.back mode must be in-app or system");let n=a9(await e.backend.pressBack(al(e,t),{mode:a}));return{kind:"systemBack",mode:a,...n?{backendResult:n}:{},...D("Back")}},nW=async(e,t={})=>{if(!e.backend.pressHome)throw new b("UNSUPPORTED_OPERATION","system.home is not supported by this backend");let a=a9(await e.backend.pressHome(al(e,t)));return{kind:"systemHome",...a?{backendResult:a}:{},...D("Home")}},nQ=async(e,t)=>{if(!e.backend.rotate)throw new b("UNSUPPORTED_OPERATION","system.rotate is not supported by this backend");let a=function(e){switch(e){case"portrait":case"portrait-upside-down":case"landscape-left":case"landscape-right":return e;default:throw new b("INVALID_ARGS","system.rotate orientation must be portrait, portrait-upside-down, landscape-left, or landscape-right")}}(t.orientation),n=a9(await e.backend.rotate(al(e,t),a));return{kind:"systemRotated",orientation:a,...n?{backendResult:n}:{},...D(`Rotated to ${a}`)}},nZ=async(e,t={})=>{if(!e.backend.setKeyboard)throw new b("UNSUPPORTED_OPERATION","system.keyboard is not supported by this backend");let a=t.action??"status";if("status"!==a&&"get"!==a&&"dismiss"!==a)throw new b("INVALID_ARGS","system.keyboard action must be status, get, or dismiss");let n=await e.backend.setKeyboard(al(e,t),{action:a}),r=a9(n);if("dismiss"===a){let e=a7(n)?n.dismissed:void 0;return{kind:"keyboardDismissed",action:a,state:a7(n)?n:{},...r?{backendResult:r}:{},...D(!1===e?"Keyboard already hidden":"Keyboard dismissed")}}return{kind:"keyboardState",action:a,state:a7(n)?n:{},...r?{backendResult:r}:{}}},n0=async(e,t)=>{if("read"===t.action){if(!e.backend.getClipboard)throw new b("UNSUPPORTED_OPERATION","system.clipboard read is not supported by this backend");let a=await e.backend.getClipboard(al(e,t));return{kind:"clipboardText",action:"read",text:"string"==typeof a?a:a.text}}if("write"!==t.action)throw new b("INVALID_ARGS","system.clipboard action must be read or write");if(!e.backend.setClipboard)throw new b("UNSUPPORTED_OPERATION","system.clipboard write is not supported by this backend");if("string"!=typeof t.text)throw new b("INVALID_ARGS","system.clipboard write requires text");let a=a9(await e.backend.setClipboard(al(e,t),t.text));return{kind:"clipboardUpdated",action:"write",textLength:Array.from(t.text).length,...a?{backendResult:a}:{},...D("Clipboard updated")}},n1=async(e,t={})=>{if(!e.backend.openSettings)throw new b("UNSUPPORTED_OPERATION","system.settings is not supported by this backend");let a=a8(t.target,"target"),n=a9(await e.backend.openSettings(al(e,t),a));return{kind:"settingsOpened",...a?{target:a}:{},...n?{backendResult:n}:{},...D(a?`Opened settings: ${a}`:"Opened settings")}},n2=async(e,t={})=>{if(!e.backend.handleAlert)throw new b("UNSUPPORTED_OPERATION","system.alert is not supported by this backend");let a=t.action??"get";if("get"!==a&&"accept"!==a&&"dismiss"!==a&&"wait"!==a)throw new b("INVALID_ARGS","system.alert action must be get, accept, dismiss, or wait");let n=void 0===t.timeoutMs?void 0:eU(t.timeoutMs,"timeoutMs",0,12e4),r=await e.backend.handleAlert(al(e,t),a,{timeoutMs:n});var i=a,s=r;if("get"===i){if("alertStatus"!==s.kind)throw new b("COMMAND_FAILED","system.alert get returned an invalid backend result");return{kind:"alertStatus",action:i,alert:s.alert}}if("wait"===i){if("alertWait"!==s.kind)throw new b("COMMAND_FAILED","system.alert wait returned an invalid backend result");return{kind:"alertWait",action:i,alert:s.alert,...void 0!==s.waitedMs?{waitedMs:s.waitedMs}:{},...void 0!==s.timedOut?{timedOut:s.timedOut}:{},...D(s.alert?"Alert visible":"Alert wait timed out")}}if("alertHandled"!==s.kind)throw new b("COMMAND_FAILED",`system.alert ${i} returned an invalid backend result`);return{kind:"alertHandled",action:i,handled:s.handled,...s.alert?{alert:s.alert}:{},...s.button?{button:s.button}:{},...D(s.handled?`Alert ${i}ed`:"No alert handled")}},n5=async(e,t={})=>{if(!e.backend.openAppSwitcher)throw new b("UNSUPPORTED_OPERATION","system.appSwitcher is not supported by this backend");let a=a9(await e.backend.openAppSwitcher(al(e,t)));return{kind:"appSwitcherOpened",...a?{backendResult:a}:{},...D("Opened app switcher")}},n3=async(e,t)=>{var a;if(!e.backend.openApp)throw new b("UNSUPPORTED_OPERATION","apps.open is not supported by this backend");let n=function(e){var t;let a=a8(e.app,"app"),n=a8(e.appId,"appId"),r=a8(e.bundleId,"bundleId"),i=a8(e.packageName,"packageName"),s=a8(e.url,"url"),o=a8(e.activity,"activity"),l={...a?{app:a}:{},...n?{appId:n}:{},...r?{bundleId:r}:{},...i?{packageName:i}:{},...s?{url:s}:{},...o?{activity:o}:{}};if(!((t=l).app??t.appId??t.bundleId??t.packageName??t.url??t.activity))throw new b("INVALID_ARGS","apps.open requires app, appId, bundleId, packageName, url, or activity");return l}(t),r=nr(await e.backend.openApp(nn(e,t),n,{relaunch:t.relaunch}));return{kind:"appOpened",target:n,relaunch:!0===t.relaunch,...r?{backendResult:r}:{},...D(`Opened: ${(a=n).app??a.appId??a.bundleId??a.packageName??a.url??a.activity??"app"}`)}},n4=async(e,t={})=>{if(!e.backend.closeApp)throw new b("UNSUPPORTED_OPERATION","apps.close is not supported by this backend");let a=a8(t.app,"app"),n=nr(await e.backend.closeApp(nn(e,t),a));return{kind:"appClosed",...a?{app:a}:{},...n?{backendResult:n}:{},...D(a?`Closed: ${a}`:"Closed app")}},n8=async(e,t={})=>{if(!e.backend.listApps)throw new b("UNSUPPORTED_OPERATION","apps.list is not supported by this backend");return{kind:"appsList",apps:await e.backend.listApps(nn(e,t),N(t.filter))}},n6=async(e,t)=>{if(!e.backend.getAppState)throw new b("UNSUPPORTED_OPERATION","apps.state is not supported by this backend");let a=a6(t.app,"app"),n=await e.backend.getAppState(nn(e,t),a);return{kind:"appState",app:a,state:n}},n7=async(e,t)=>{if(!e.backend.pushFile)throw new b("UNSUPPORTED_OPERATION","apps.push is not supported by this backend");let a=a6(t.app,"app"),n=await nt(e,t.input);try{let r=await e.backend.pushFile(nn(e,t),n.backendInput,a),i=nr(r);return{kind:"appPushed",app:a,inputKind:n.inputKind,...i?{backendResult:i}:{},...D(`Pushed to ${a}`)}}finally{await n.cleanup?.()}},n9=async(e,t)=>{var a,n;if(!e.backend.triggerAppEvent)throw new b("UNSUPPORTED_OPERATION","apps.triggerEvent is not supported by this backend");let r=function(e){let t=a6(e,"name");if(!ne.test(t))throw new b("INVALID_ARGS",`Invalid apps.triggerEvent name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});return t}(t.name);a=t.payload,n=`apps.triggerEvent payload for "${r}"`,void 0!==a&&na(a,n,8192);let i=nr(await e.backend.triggerAppEvent(nn(e,t),{name:r,...t.payload?{payload:t.payload}:{}}));return{kind:"appEventTriggered",name:r,...t.payload?{payload:t.payload}:{},...i?{backendResult:i}:{},...D(`Triggered app event: ${r}`)}},re=async(e,t={})=>{if(!e.backend.listDevices)throw new b("UNSUPPORTED_OPERATION","admin.devices is not supported by this backend");return{kind:"adminDevices",devices:await e.backend.listDevices(al(e,t),t.filter)}},rt=async(e,t={})=>{if(!e.backend.bootDevice)throw new b("UNSUPPORTED_OPERATION","admin.boot is not supported by this backend");let a=function(e){if(!e)return;let t=a8(e.id,"target.id"),a=a8(e.name,"target.name"),n={...t?{id:t}:{},...a?{name:a}:{},...e.platform?{platform:e.platform}:{},...e.target?{target:e.target}:{},...void 0!==e.headless?{headless:e.headless}:{}};return Object.keys(n).length>0?n:void 0}(t.target),n=nd(await e.backend.bootDevice(al(e,t),a));return{kind:"deviceBooted",...a?{target:a}:{},...n?{backendResult:n}:{},...D("Booted device")}},ra=async(e,t)=>await ni(e,t,"install"),rn=async(e,t)=>await ni(e,t,"reinstall"),rr=async(e,t)=>await ni(e,t,"installFromSource"),ri=async(e,t)=>{let a=np(t.action,"record"),n="start"===a?e.backend.startRecording:e.backend.stopRecording;if(!n)throw new b("UNSUPPORTED_OPERATION",`record ${a} is not supported by this backend`);let r=t.out?await e4(e,t.out,{field:"path",ext:".mp4"}):void 0;try{var i,s,o,l,c;let d,p,u=(i=t,s=r?.path,d=void 0===i.fps?void 0:eU(i.fps,"fps",1,60),p=void 0===i.quality?void 0:eU(i.quality,"quality",5,10),{...s?{outPath:s}:{},...void 0!==d?{fps:d}:{},...void 0!==p?{quality:p}:{},...void 0!==i.hideTouches?{showTouches:!0!==i.hideTouches}:{}}),h=await n.call(e.backend,al(e,t),u),m=await r?.publish();return o=a,l=h,c=m,{..."string"==typeof l.path?{path:l.path}:{},..."string"==typeof l.telemetryPath?{telemetryPath:l.telemetryPath}:{},..."string"==typeof l.warning?{warning:l.warning}:{},...nu(o,l,c,{startKind:"recordingStarted",stopKind:"recordingStopped",startMessage:"Recording started",stopMessage:"Recording stopped"})}}catch(e){throw await r?.cleanup?.(),e}},rs=async(e,t)=>{let a=np(t.action,"trace"),n="start"===a?e.backend.startTrace:e.backend.stopTrace;if(!n)throw new b("UNSUPPORTED_OPERATION",`trace ${a} is not supported by this backend`);let r=t.out?await e4(e,t.out,{field:"outPath",ext:".trace"}):void 0;try{var i,s,o;let l={...r?.path?{outPath:r.path}:{}},c=await n.call(e.backend,al(e,t),l),d=await r?.publish();return i=a,s=c,o=d,{..."string"==typeof s.outPath?{outPath:s.outPath}:{},...nu(i,s,o,{startKind:"traceStarted",stopKind:"traceStopped",startMessage:"Trace started",stopMessage:"Trace stopped"})}}catch(e){throw await r?.cleanup?.(),e}},ro=async(e,t={})=>{var a,n;let r;if(!e.backend.readLogs)throw new b("UNSUPPORTED_OPERATION","diagnostics.logs is not supported by this backend");return r=!0===(a=await e.backend.readLogs(await nD(e,t),{...nI(n=t,100,500,"logs limit"),...void 0!==n.levels?{levels:nS(n.levels,"levels")}:{},...void 0!==n.search?{search:a6(n.search,"search")}:{},...void 0!==n.source?{source:a6(n.source,"source")}:{}})).redacted,{kind:"diagnosticsLogs",entries:a.entries.map(e=>{let t=nx(e.message,4096),a=nv(e.metadata);return r||=t.redacted||a.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.level?{level:e.level}:{},message:t.value??"",...e.source?{source:e.source}:{},...a.value?{metadata:a.value}:{}}}),...a.nextCursor?{nextCursor:a.nextCursor}:{},...a.timeWindow?{timeWindow:a.timeWindow}:{},...a.backend?{backend:a.backend}:{},redacted:r,...a.notes?{notes:a.notes}:{}}},rl=async(e,t={})=>{var a,n,r;let i;if(!e.backend.dumpNetwork)throw new b("UNSUPPORTED_OPERATION","diagnostics.network is not supported by this backend");let s={...nI(r=t,25,200,"network limit"),include:function(e){if(void 0===e)return"summary";if("summary"===e||"headers"===e||"body"===e||"all"===e)return e;throw new b("INVALID_ARGS","network include must be summary, headers, body, or all")}(r.include)};return a=await e.backend.dumpNetwork(await nD(e,t),s),n=s.include??"summary",i=!0===a.redacted,{kind:"diagnosticsNetwork",entries:a.entries.map(e=>{var t;let a=e.url?ng(t=e.url)??nx(t,2048):void 0,r="headers"===n||"all"===n?nw(e.requestHeaders):void 0,s="headers"===n||"all"===n?nw(e.responseHeaders):void 0,o="body"===n||"all"===n?ny(e.requestBody):void 0,l="body"===n||"all"===n?ny(e.responseBody):void 0,c=nv(e.metadata);return i||=(a?.redacted??!1)||(r?.redacted??!1)||(s?.redacted??!1)||(o?.redacted??!1)||(l?.redacted??!1)||c.redacted,{...e.timestamp?{timestamp:e.timestamp}:{},...e.method?{method:e.method}:{},...a?{url:a.value}:{},...void 0!==e.status?{status:e.status}:{},...void 0!==e.durationMs?{durationMs:e.durationMs}:{},...r?.value?{requestHeaders:r.value}:{},...s?.value?{responseHeaders:s.value}:{},...o?.value!==void 0?{requestBody:o.value}:{},...l?.value!==void 0?{responseBody:l.value}:{},...c.value?{metadata:c.value}:{}}}),...a.nextCursor?{nextCursor:a.nextCursor}:{},...a.timeWindow?{timeWindow:a.timeWindow}:{},...a.backend?{backend:a.backend}:{},redacted:i,...a.notes?{notes:a.notes}:{}}},rc=async(e,t={})=>{var a,n;let r;if(!e.backend.measurePerf)throw new b("UNSUPPORTED_OPERATION","diagnostics.perf is not supported by this backend");return r=!0===(a=await e.backend.measurePerf(await nD(e,t),{...nR(n=t),...void 0!==n.sampleMs?{sampleMs:eU(n.sampleMs,"sampleMs",100,6e4)}:{},...void 0!==n.metrics?{metrics:nS(n.metrics,"metrics",20)}:{}})).redacted,{kind:"diagnosticsPerf",metrics:a.metrics.map(e=>{let t=nx(e.message,4096),a=nv(e.metadata);return r||=t.redacted||a.redacted,{name:e.name,...void 0!==e.value?{value:e.value}:{},...e.unit?{unit:e.unit}:{},...e.status?{status:e.status}:{},...void 0!==t.value?{message:t.value}:{},...a.value?{metadata:a.value}:{}}}),...a.startedAt?{startedAt:a.startedAt}:{},...a.endedAt?{endedAt:a.endedAt}:{},...a.backend?{backend:a.backend}:{},redacted:r,...a.notes?{notes:a.notes}:{}}};function rd(e){let t={backend:e.backend,artifacts:e.artifacts,sessions:e.sessions??function(e=[]){let t=new Map(e.map(e=>[e.name,rp(e)]));return{get:e=>rp(t.get(e)),set:e=>{t.set(e.name,rp(e))},delete:e=>{t.delete(e)},list:()=>Array.from(t.values(),e=>rp(e))}}(),policy:e.policy??function(e={}){return{allowLocalInputPaths:!1,allowLocalOutputPaths:!1,maxImagePixels:2e7,allowNamedBackendCapabilities:[],...e}}(),diagnostics:e.diagnostics,clock:e.clock,signal:e.signal};return{...t,capture:{screenshot:e=>nM(t,e),diffScreenshot:e=>nN(t,e),snapshot:e=>nO(t,e),diffSnapshot:e=>nL(t,e)},selectors:{find:e=>nP(t,e),get:e=>nE(t,e),getText:(e,a={})=>nC(t,{...a,target:e}),getAttrs:(e,a={})=>nT(t,{...a,target:e}),is:e=>nU(t,e),isVisible:(e,a={})=>n_(t,{...a,target:e}),isHidden:(e,a={})=>n$(t,{...a,target:e}),wait:e=>nF(t,e),waitForText:(e,a={})=>nB(t,{...a,text:e})},interactions:{click:(e,a={})=>nq(t,{...a,target:e}),press:(e,a={})=>nG(t,{...a,target:e}),fill:(e,a,n={})=>nj(t,{...n,target:e,text:a}),typeText:(e,a={})=>nV(t,{...a,text:e}),focus:(e,a={})=>nX(t,{...a,target:e}),longPress:(e,a={})=>nY(t,{...a,target:e}),swipe:e=>nK(t,e),scroll:e=>nz(t,e),pinch:e=>nH(t,e)},system:{back:e=>nJ(t,e),home:e=>nW(t,e),rotate:e=>nQ(t,e),keyboard:e=>nZ(t,e),clipboard:e=>n0(t,e),settings:e=>n1(t,e),alert:e=>n2(t,e),appSwitcher:e=>n5(t,e)},apps:{open:e=>n3(t,e),close:e=>n4(t,e),list:(e={})=>n8(t,{...e,filter:S(e.filter)}),state:e=>n6(t,e),push:e=>n7(t,e),triggerEvent:e=>n9(t,e)},admin:{devices:e=>re(t,e),boot:e=>rt(t,e),install:e=>ra(t,e),reinstall:e=>rn(t,e),installFromSource:e=>rr(t,e)},recording:{record:e=>ri(t,e),trace:e=>rs(t,e)},observability:{logs:e=>ro(t,e),network:e=>rl(t,e),perf:e=>rc(t,e)}}}function rp(e){if(e)return{...e,...e.snapshot?{snapshot:structuredClone(e.snapshot)}:{},...e.metadata?{metadata:function(e){try{return structuredClone(e)}catch{return{...e}}}(e.metadata)}:{}}}function ru(e={}){return{allowLocalInputPaths:!0,allowLocalOutputPaths:!0,maxImagePixels:2e7,allowNamedBackendCapabilities:[],...e}}let rh=["app","frontmost-app","desktop","menubar"];function rm(e){let t=e?.trim().toLowerCase();if("app"===t||"frontmost-app"===t||"desktop"===t||"menubar"===t)return t;throw new b("INVALID_ARGS",`Invalid surface: ${e}. Use ${rh.join("|")}.`)}let rf={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
2
2
 
3
3
  Version-matched operating guide for normal agent-device work.
4
4
 
@@ -29,19 +29,20 @@ Bootstrap:
29
29
  Do not open artifact paths or invent package ids. If apps lookup misses the target and no URL/artifact is provided, ask or stop.
30
30
 
31
31
  Snapshots and refs:
32
- snapshot reads visible state. snapshot -i gets current interactive refs.
32
+ snapshot reads visible state. snapshot -i gets current interactive refs only; it is the fast path when the next step is an interaction.
33
33
  Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions; use --raw or --json only when you need the full provider tree.
34
34
  Snapshot legend:
35
35
  @e12 [button] label="Add to cart" id="add-cart" enabled hittable -> press @e12 or press 'id="add-cart"'.
36
36
  @e13 [textinput] label="Notes" preview="Leave at side..." truncated -> snapshot -s @e13 before reading.
37
37
  @e14 [cell] label="Profiles" focused -> tvOS focus is currently on this row.
38
38
  [off-screen below] 4 items: "Privacy", "About" -> scroll down, then snapshot -i; those are hints, not refs.
39
- Re-snapshot after navigation, submit, modal/list/reload/dynamic changes.
39
+ Re-snapshot after navigation, submit, typing/fill, modal/list/reload/dynamic changes when you need new refs.
40
40
  Anti-pattern: snapshot -i followed by snapshot -i | grep ...
41
- Refs from the first snapshot remain valid until you press, fill, scroll, go back, wait for async UI, or otherwise change app state.
41
+ Refs from the first snapshot remain valid until you press, fill, type, scroll, go back, wait for async UI, or otherwise change app state.
42
+ After a mutation, prefer a known selector/label directly (for example press 'label="Send"') because interaction commands refresh interactive state internally. If you need to discover the new control, use snapshot -i, or snapshot -i -s "Composer" when a stable container label/id can scope the refresh.
42
43
  For a targeted query, use find/get/is. If you truly need the full tree again, pass --force-full.
43
44
  Off-screen summaries are scroll hints; use scroll, not swipe, then snapshot -i.
44
- Missing target in a long list: use a short manual scroll + snapshot loop with a max attempt count; do not rely on unbounded scrollintoview.
45
+ Missing target in a long list: use a short manual scroll + snapshot loop with a max attempt count. If a named target is summarized as off-screen below/above, use scroll down/up, then snapshot -i; do not use scroll bottom/top because the target may appear before the absolute list edge. Use scroll bottom/top only when the task explicitly asks for the list edge. Edge scrolls verify hidden content with snapshots and stop when no matching hidden content remains.
45
46
  Truncated text/input previews: do not use get text first; expand with snapshot -s @ref (for example snapshot -s @e7), then read the scoped output.
46
47
  Rare iOS accessibility gaps: if a row ref is shown disabled/hittable:false and press @ref reports success but no UI change, or a horizontal tab/filter bar is collapsed into one composite/seekbar with no child refs, run agent-device snapshot -i -c --json to read rects, compute the target center, press x y, then diff snapshot -i. Coordinates are fallback-only; document why you used them.
47
48
 
@@ -89,8 +90,9 @@ Navigation and gestures:
89
90
  If app-owned back is ambiguous or has just misrouted, prefer a visible nav/back button ref, tab-bar ref, or deep link over repeated back/system back.
90
91
  App-owned action sheets, menus, and camera/scan screens are normal UI. After opening one, run snapshot -i or wait for the option, press by label/ref, handle visible permission sheets through UI or platform-supported native alerts, then wait for a concrete result before returning to chat/form state.
91
92
  Keep count/pause/pattern on one swipe; flags are --count, --pause-ms, --pattern ping-pong.
92
- longpress duration and pinch scale/center are positional:
93
+ longpress accepts coordinates, @refs, or selectors. Prefer @ref/selector from snapshot -i; use coordinates only as a fallback when accessibility refs miss the exact target. Duration and pinch scale/center are positional:
93
94
  agent-device longpress 300 500 800
95
+ agent-device longpress @e12 800
94
96
  agent-device swipe 320 500 40 500 --count 8 --pause-ms 30 --pattern ping-pong
95
97
  agent-device pinch 0.5 200 400
96
98
 
@@ -101,7 +103,7 @@ Validation and evidence:
101
103
  If task says snapshot, use snapshot. If it asks visual evidence, use screenshot.
102
104
  Icon/tappable visual proof: screenshot --overlay-refs. Flag is --overlay-refs.
103
105
  Startup/frame health/CPU/memory: perf --json or metrics. Replay maintenance: replay -u ./flow.ad.
104
- Recording: record start/stop. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
106
+ Recording: record start/stop. By default, stop burns touch overlays into the video; use record start --hide-touches for the fastest raw recording. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
105
107
  Stable known flow: batch ./steps.json, not workflow batch.
106
108
  Inline batch JSON example:
107
109
  agent-device batch --steps '[{"command":"open","positionals":["settings"],"flags":{}},{"command":"wait","positionals":["100"],"flags":{}}]'
@@ -117,7 +119,7 @@ React Native dev loop:
117
119
  agent-device metro reload
118
120
  agent-device find "Home"
119
121
  Do not use agent-device reload. Use open --relaunch for native startup reset.
120
- React Native apps: use help react-native for Metro/Fast Refresh, LogBox/RedBox overlays, DevTools routing, and RN-specific blockers.
122
+ React Native apps: use help react-native for Metro/Fast Refresh, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.
121
123
  Android RN/Expo Metro: run adb reverse tcp:<port> tcp:<port> before opening the app or URL; it is harmless even if already configured.
122
124
  Expo Go is a host shell. Use a provided project URL instead of inventing a bundle id; if no URL is provided but a target/app name is provided, open that target and do not inspect project files to find one. On iOS, prefer host + URL when the host shell is known because direct URL open can report success while leaving the runner/shell focused; verify with snapshot -i after opening:
123
125
  agent-device open "Expo Go" exp://127.0.0.1:8081 --platform ios
@@ -149,6 +151,10 @@ Logs:
149
151
  agent-device logs path
150
152
  Do not cat a full stale log into agent context. Open or grep only the relevant window when needed.
151
153
  logs clear --restart is the compact command to clear old logs and start a fresh capture; do not split it into logs stop, logs clear, logs start.
154
+ On iOS simulators, logs scope by bundle id and resolved app executable, so use this instead of raw simctl log stream predicates.
155
+ For iOS simulator launch-time stdout/stderr, use --launch-console on the direct app launch:
156
+ agent-device open MyApp --platform ios --relaunch --launch-console ./artifacts/app.console.log
157
+ --launch-console is only for direct iOS simulator app launches, not URL opens.
152
158
 
153
159
  Network:
154
160
  Use network dump for recent session HTTP traffic parsed from app logs.
@@ -158,14 +164,15 @@ Network:
158
164
  network log is a supported alias, but network dump --include headers is the clearest plan form. Do not write network log headers.
159
165
 
160
166
  Alerts:
161
- Native alerts:
167
+ Native and platform dialogs:
162
168
  agent-device alert wait 3000
163
169
  agent-device alert accept
164
170
  agent-device alert dismiss
165
- If alert accept says no alert but a permission sheet is visibly on screen, treat it as normal UI:
171
+ Android support is snapshot-derived for runtime permission prompts and native app dialogs. iOS support is runner-derived for XCTest alerts, app-owned modal popups with native blocking markers, and blocking system dialogs. Use cheap alert get for an immediate check; use alert wait <short-ms> only when a prompt may appear after async work.
172
+ If alert says no alert but a sheet is visibly on screen, treat it as app-owned UI:
166
173
  agent-device snapshot -i
167
174
  agent-device press 'label="Allow"'
168
- Android runtime permission prompts are visible UI. Do not use alert wait for them, and do not use settings permission to answer a dialog already on screen. Reserve settings permission for setup/resetting permission state before a flow.
175
+ Do not use settings permission to answer a dialog already on screen. Reserve settings permission for setup/resetting permission state before a flow.
169
176
 
170
177
  Diagnostics and traces:
171
178
  Use --debug for CLI/daemon diagnostic ids and log paths.
@@ -266,10 +273,11 @@ React Native dev loop:
266
273
  Expo Go/dev clients are host shells. Use provided project URLs, verify with snapshot -i after opening, and ask instead of inventing app ids or URLs. Help workflow owns the full Expo URL command shapes.
267
274
 
268
275
  Overlays and busy RN UIs:
269
- React Native warning/error overlays belong to the app run. Treat them as blockers before normal app work: press visible Dismiss/Close immediately when unrelated, or press the collapsed warning banner first if only a warning chip is visible; then re-snapshot and report the overlay in the final summary. Use screenshot --overlay-refs only if visual evidence is required.
270
- Full-screen RedBox stack traces are app errors, not failed navigation. If Minimize is visible, prefer Minimize over Dismiss; Dismiss can re-trigger infinite-loop render errors such as getSnapshot/useOnyx stack paths.
276
+ If snapshot reports a React Native warning/error overlay, handle it before interacting with the app: run agent-device react-native dismiss-overlay, then agent-device snapshot -i -c. Use refs from the new snapshot.
277
+ Do not manually press warning/error text bodies, collapsed banner bodies, full-screen warning parents, or broad LogBox/RedBox refs. The dismiss-overlay command owns the narrow LogBox/RedBox targeting policy.
278
+ Report the overlay in the final summary. Use screenshot --overlay-refs before dismissing only if visual evidence is required.
271
279
  If snapshot times out because the UI never becomes idle, Android accessibility may be blocked by busy or continuously changing app UI. After that timeout, use screenshot as visual truth instead of repeatedly retrying snapshots.
272
- Android runtime permission dialogs are visible UI: inspect snapshot -i and press Allow/Deny by visible label/ref. Use alert wait/accept/dismiss only where the platform supports native alerts.
280
+ Android runtime permission dialogs and native alerts are handled by alert wait/accept/dismiss. If alert reports no alert, treat the visible surface as app-owned UI and use snapshot -i plus press by label/ref.
273
281
 
274
282
  React DevTools routing:
275
283
  Keep the agent-device react-devtools prefix on every React DevTools command.
@@ -356,7 +364,7 @@ Loop:
356
364
 
357
365
  Coverage:
358
366
  Navigation, forms, empty/error/loading states, offline or retry behavior, permissions, settings, accessibility labels, orientation/keyboard, and obvious performance stalls.
359
- React Native warning/error overlays can be real findings or test blockers. Capture them, dismiss if unrelated, re-snapshot, and report them.
367
+ React Native warning/error overlays can be real findings or test blockers. Capture them, use react-native dismiss-overlay if unrelated, re-snapshot, and report them.
360
368
  Expo Go/dev-client shells: use the provided exp:// or dev-client URL and record whether the shell, project load, or app UI is being tested. On iOS dogfood, prefer agent-device open "Expo Go" <url> when Expo Go is the known shell, then snapshot -i to confirm the project UI rather than the runner splash.
361
369
  Android RN/Expo Metro: run adb reverse tcp:<port> tcp:<port> before opening the app or URL; it is harmless even if already configured.
362
370
  Categories: visual, functional, UX, content, performance, diagnostics, permissions, accessibility.
@@ -372,6 +380,7 @@ Evidence commands:
372
380
  agent-device --session qa logs mark "issue-001 repro"
373
381
  agent-device --session qa logs path
374
382
  agent-device --session qa record start ./dogfood-output/videos/issue-001.mp4
383
+ agent-device --session qa record start ./dogfood-output/videos/benchmark.mp4 --hide-touches
375
384
  agent-device --session qa record stop
376
385
  agent-device --session qa close
377
386
 
@@ -393,10 +402,10 @@ Rules:
393
402
  Prefer refs for exploration and selectors for deterministic replay.
394
403
  Use logs, network, screenshot --overlay-refs, trace, perf, or react-devtools only when they add evidence to a specific issue.
395
404
  Never delete screenshots, videos, traces, or report artifacts during a session.
396
- Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}},n2=[{key:"config",names:["--config"],type:"string",usageLabel:"--config <path>",usageDescription:"Load CLI defaults from a specific config file"},{key:"remoteConfig",names:["--remote-config"],type:"string",usageLabel:"--remote-config <path>",usageDescription:"Load remote host + Metro workflow settings from a specific profile file"},{key:"stateDir",names:["--state-dir"],type:"string",usageLabel:"--state-dir <path>",usageDescription:"Daemon state directory (defaults to ~/.agent-device)"},{key:"daemonBaseUrl",names:["--daemon-base-url"],type:"string",usageLabel:"--daemon-base-url <url>",usageDescription:"Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)"},{key:"daemonAuthToken",names:["--daemon-auth-token"],type:"string",usageLabel:"--daemon-auth-token <token>",usageDescription:"Remote HTTP daemon auth token (sent as request token and bearer header)"},{key:"daemonTransport",names:["--daemon-transport"],type:"enum",enumValues:["auto","socket","http"],usageLabel:"--daemon-transport auto|socket|http",usageDescription:"Daemon client transport preference"},{key:"daemonServerMode",names:["--daemon-server-mode"],type:"enum",enumValues:["socket","http","dual"],usageLabel:"--daemon-server-mode socket|http|dual",usageDescription:"Daemon server mode used when spawning daemon"},{key:"tenant",names:["--tenant"],type:"string",usageLabel:"--tenant <id>",usageDescription:"Tenant scope identifier for isolated daemon sessions"},{key:"sessionIsolation",names:["--session-isolation"],type:"enum",enumValues:["none","tenant"],usageLabel:"--session-isolation none|tenant",usageDescription:"Session isolation strategy (tenant prefixes session namespace)"},{key:"runId",names:["--run-id"],type:"string",usageLabel:"--run-id <id>",usageDescription:"Run identifier used for tenant lease admission checks"},{key:"leaseId",names:["--lease-id"],type:"string",usageLabel:"--lease-id <id>",usageDescription:"Lease identifier bound to tenant/run admission scope"},{key:"leaseBackend",names:["--lease-backend"],type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"],usageLabel:"--lease-backend ios-simulator|ios-instance|android-instance",usageDescription:"Lease backend for remote tenant connection admission"},{key:"force",names:["--force"],type:"boolean",usageLabel:"--force",usageDescription:"Force connection state replacement when reconnecting"},{key:"noLogin",names:["--no-login"],type:"boolean",usageLabel:"--no-login",usageDescription:"Connect: fail instead of starting implicit cloud login"},{key:"sessionLock",names:["--session-lock"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock reject|strip",usageDescription:"Lock bound-session device routing for this CLI invocation and nested batch steps"},{key:"sessionLocked",names:["--session-locked"],type:"boolean",usageLabel:"--session-locked",usageDescription:"Deprecated alias for --session-lock reject"},{key:"sessionLockConflicts",names:["--session-lock-conflicts"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock-conflicts reject|strip",usageDescription:"Deprecated alias for --session-lock"},{key:"platform",names:["--platform"],type:"enum",enumValues:["ios","macos","android","linux","apple"],usageLabel:"--platform ios|macos|android|linux|apple",usageDescription:"Platform to target (`apple` aliases the Apple automation backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv","desktop"],usageLabel:"--target mobile|tv|desktop",usageDescription:"Device target class to match"},{key:"device",names:["--device"],type:"string",usageLabel:"--device <name>",usageDescription:"Device name to target"},{key:"udid",names:["--udid"],type:"string",usageLabel:"--udid <udid>",usageDescription:"iOS device UDID"},{key:"serial",names:["--serial"],type:"string",usageLabel:"--serial <serial>",usageDescription:"Android device serial"},{key:"surface",names:["--surface"],type:"enum",enumValues:nZ,usageLabel:"--surface app|frontmost-app|desktop|menubar",usageDescription:"macOS session surface for open (defaults to app)"},{key:"headless",names:["--headless"],type:"boolean",usageLabel:"--headless",usageDescription:"Boot: launch Android emulator without a GUI window"},{key:"metroHost",names:["--metro-host"],type:"string",usageLabel:"--metro-host <host>",usageDescription:"Session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"Session-scoped Metro/debug port hint"},{key:"metroProjectRoot",names:["--project-root"],type:"string",usageLabel:"--project-root <path>",usageDescription:"metro prepare: React Native project root (default: cwd)"},{key:"metroKind",names:["--kind"],type:"enum",enumValues:["auto","react-native","expo"],usageLabel:"--kind auto|react-native|expo",usageDescription:"metro prepare: detect or force the Metro launcher kind"},{key:"metroPublicBaseUrl",names:["--public-base-url"],type:"string",usageLabel:"--public-base-url <url>",usageDescription:"metro prepare: public base URL used for direct bundle hints"},{key:"metroProxyBaseUrl",names:["--proxy-base-url"],type:"string",usageLabel:"--proxy-base-url <url>",usageDescription:"metro prepare: optional bridge origin for remote Metro access"},{key:"metroBearerToken",names:["--bearer-token"],type:"string",usageLabel:"--bearer-token <token>",usageDescription:"metro prepare: host bridge bearer token (prefer AGENT_DEVICE_PROXY_TOKEN or AGENT_DEVICE_METRO_BEARER_TOKEN)"},{key:"metroPreparePort",names:["--port"],type:"int",min:1,max:65535,usageLabel:"--port <port>",usageDescription:"metro prepare: local Metro port (default: 8081)"},{key:"metroListenHost",names:["--listen-host"],type:"string",usageLabel:"--listen-host <host>",usageDescription:"metro prepare: host Metro listens on (default: 0.0.0.0)"},{key:"metroStatusHost",names:["--status-host"],type:"string",usageLabel:"--status-host <host>",usageDescription:"metro prepare: host used for local /status polling (default: 127.0.0.1)"},{key:"metroStartupTimeoutMs",names:["--startup-timeout-ms"],type:"int",min:1,usageLabel:"--startup-timeout-ms <ms>",usageDescription:"metro prepare: timeout while waiting for Metro to become ready"},{key:"metroProbeTimeoutMs",names:["--probe-timeout-ms"],type:"int",min:1,usageLabel:"--probe-timeout-ms <ms>",usageDescription:"metro prepare: timeout for /status and proxy bridge calls"},{key:"metroRuntimeFile",names:["--runtime-file"],type:"string",usageLabel:"--runtime-file <path>",usageDescription:"metro prepare: optional file path to persist the JSON result"},{key:"metroNoReuseExisting",names:["--no-reuse-existing"],type:"boolean",usageLabel:"--no-reuse-existing",usageDescription:"metro prepare: always start a fresh Metro process"},{key:"metroNoInstallDeps",names:["--no-install-deps"],type:"boolean",usageLabel:"--no-install-deps",usageDescription:"metro prepare: skip package-manager install when node_modules is missing"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"Session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"Session-scoped deep link / launch URL hint"},{key:"iosSimulatorDeviceSet",names:["--ios-simulator-device-set"],type:"string",usageLabel:"--ios-simulator-device-set <path>",usageDescription:"Scope iOS simulator discovery/commands to this simulator device set"},{key:"androidDeviceAllowlist",names:["--android-device-allowlist"],type:"string",usageLabel:"--android-device-allowlist <serials>",usageDescription:"Comma/space separated Android serial allowlist for discovery/selection"},{key:"activity",names:["--activity"],type:"string",usageLabel:"--activity <component>",usageDescription:"Android app launch activity (package/Activity); not for URL opens"},{key:"header",names:["--header"],type:"string",multiple:!0,usageLabel:"--header <name:value>",usageDescription:"install-from-source: repeatable HTTP header for URL downloads"},{key:"githubActionsArtifact",names:["--github-actions-artifact"],type:"string",usageLabel:"--github-actions-artifact <owner/repo:artifact>",usageDescription:"install-from-source: GitHub Actions artifact resolved by a remote daemon"},{key:"installSource",names:[],type:"string"},{key:"session",names:["--session"],type:"string",usageLabel:"--session <name>",usageDescription:"Named session"},{key:"count",names:["--count"],type:"int",min:1,max:200,usageLabel:"--count <n>",usageDescription:"Repeat count for press/swipe series"},{key:"fps",names:["--fps"],type:"int",min:1,max:120,usageLabel:"--fps <n>",usageDescription:"Record: target frames per second (iOS physical device runner)"},{key:"quality",names:["--quality"],type:"int",min:5,max:10,usageLabel:"--quality <5-10>",usageDescription:"Record: scale recording resolution from 5 (50%) through 10 (native resolution)"},{key:"hideTouches",names:["--hide-touches"],type:"boolean",usageLabel:"--hide-touches",usageDescription:"Record: disable touch overlays in the final video"},{key:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{key:"delayMs",names:["--delay-ms"],type:"int",min:0,max:1e4,usageLabel:"--delay-ms <ms>",usageDescription:"Delay between typed characters"},{key:"holdMs",names:["--hold-ms"],type:"int",min:0,max:1e4,usageLabel:"--hold-ms <ms>",usageDescription:"Press hold duration for each iteration"},{key:"jitterPx",names:["--jitter-px"],type:"int",min:0,max:100,usageLabel:"--jitter-px <n>",usageDescription:"Deterministic coordinate jitter radius for press"},{key:"pixels",names:["--pixels"],type:"int",min:1,max:1e5,usageLabel:"--pixels <n>",usageDescription:"Scroll: explicit gesture distance in pixels"},{key:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{key:"clickButton",names:["--button"],type:"enum",enumValues:["primary","secondary","middle"],usageLabel:"--button primary|secondary|middle",usageDescription:"Click: choose mouse button (middle reserved for future macOS support)"},{key:"backMode",names:["--in-app"],type:"enum",enumValues:["in-app","system"],setValue:"in-app",usageLabel:"--in-app",usageDescription:"Back: use app-provided back UI when available"},{key:"backMode",names:["--system"],type:"enum",enumValues:["in-app","system"],setValue:"system",usageLabel:"--system",usageDescription:"Back: use system back input or gesture when available"},{key:"pauseMs",names:["--pause-ms"],type:"int",min:0,max:1e4,usageLabel:"--pause-ms <ms>",usageDescription:"Delay between swipe iterations"},{key:"pattern",names:["--pattern"],type:"enum",enumValues:["one-way","ping-pong"],usageLabel:"--pattern one-way|ping-pong",usageDescription:"Swipe repeat pattern"},{key:"verbose",names:["--debug","--verbose","-v"],type:"boolean",usageLabel:"--debug, --verbose, -v",usageDescription:"Enable debug diagnostics and stream daemon/runner logs"},{key:"json",names:["--json"],type:"boolean",usageLabel:"--json",usageDescription:"JSON output"},{key:"help",names:["--help","-h"],type:"boolean",usageLabel:"--help, -h",usageDescription:"Print help and exit"},{key:"version",names:["--version","-V"],type:"boolean",usageLabel:"--version, -V",usageDescription:"Print version and exit"},{key:"snapshotDiff",names:["--diff"],type:"boolean",usageLabel:"--diff",usageDescription:"Snapshot: show structural diff against the previous session baseline"},{key:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{key:"networkInclude",names:["--include"],type:"enum",enumValues:["summary","headers","body","all"],usageLabel:"--include summary|headers|body|all",usageDescription:"Network: include headers, bodies, or both in output"},{key:"shutdown",names:["--shutdown"],type:"boolean",usageLabel:"--shutdown",usageDescription:"close: shutdown associated simulator/emulator after ending session"},{key:"relaunch",names:["--relaunch"],type:"boolean",usageLabel:"--relaunch",usageDescription:"open: terminate app process before launching it"},{key:"restart",names:["--restart"],type:"boolean",usageLabel:"--restart",usageDescription:"logs clear: stop active stream, clear logs, then start streaming again"},{key:"retainPaths",names:["--retain-paths"],type:"boolean",usageLabel:"--retain-paths",usageDescription:"install-from-source: keep materialized artifact paths after install"},{key:"retentionMs",names:["--retention-ms"],type:"int",min:1,usageLabel:"--retention-ms <ms>",usageDescription:"install-from-source: retention TTL for materialized artifact paths"},{key:"noRecord",names:["--no-record"],type:"boolean",usageLabel:"--no-record",usageDescription:"Do not record this action"},{key:"replayUpdate",names:["--update","-u"],type:"boolean",usageLabel:"--update, -u",usageDescription:"Replay: update selectors and rewrite replay file in place"},{key:"replayMaestro",names:["--maestro"],type:"boolean",usageLabel:"--maestro",usageDescription:"Replay: treat input as a prototype Maestro YAML flow and execute the supported subset through replay"},{key:"replayEnv",names:["-e","--env"],type:"string",multiple:!0,usageLabel:"-e KEY=VALUE, --env KEY=VALUE",usageDescription:"Replay/Test: inject or override a ${KEY} variable for the script (repeatable)"},{key:"failFast",names:["--fail-fast"],type:"boolean",usageLabel:"--fail-fast",usageDescription:"Test: stop the suite after the first failing script"},{key:"timeoutMs",names:["--timeout"],type:"int",min:1,usageLabel:"--timeout <ms>",usageDescription:"Test: maximum wall-clock time per script attempt"},{key:"retries",names:["--retries"],type:"int",min:0,max:3,usageLabel:"--retries <n>",usageDescription:"Test: retry each failed script up to n additional times"},{key:"artifactsDir",names:["--artifacts-dir"],type:"string",usageLabel:"--artifacts-dir <path>",usageDescription:"Test: root directory for suite artifacts"},{key:"reportJunit",names:["--report-junit"],type:"string",usageLabel:"--report-junit <path>",usageDescription:"Test: write a JUnit XML report for the replay suite"},{key:"steps",names:["--steps"],type:"string",usageLabel:"--steps <json>",usageDescription:"Batch: JSON array of steps"},{key:"stepsFile",names:["--steps-file"],type:"string",usageLabel:"--steps-file <path>",usageDescription:"Batch: read steps JSON from file"},{key:"batchOnError",names:["--on-error"],type:"enum",enumValues:["stop"],usageLabel:"--on-error stop",usageDescription:"Batch: stop when a step fails"},{key:"batchMaxSteps",names:["--max-steps"],type:"int",min:1,max:1e3,usageLabel:"--max-steps <n>",usageDescription:"Batch: maximum number of allowed steps"},{key:"appsFilter",names:["--all"],type:"enum",enumValues:["user-installed","all"],setValue:"all",usageLabel:"--all",usageDescription:"Apps: include system/OEM apps"},{key:"snapshotInteractiveOnly",names:["-i"],type:"boolean",usageLabel:"-i",usageDescription:"Snapshot: interactive elements only"},{key:"snapshotCompact",names:["-c"],type:"boolean",usageLabel:"-c",usageDescription:"Snapshot: compact output (drop empty structure)"},{key:"snapshotDepth",names:["--depth","-d"],type:"int",min:0,usageLabel:"--depth, -d <depth>",usageDescription:"Snapshot: limit snapshot depth"},{key:"snapshotScope",names:["--scope","-s"],type:"string",usageLabel:"--scope, -s <scope>",usageDescription:"Snapshot: scope snapshot to label/identifier"},{key:"snapshotRaw",names:["--raw"],type:"boolean",usageLabel:"--raw",usageDescription:"Snapshot: raw node output"},{key:"snapshotForceFull",names:["--force-full"],type:"boolean",usageLabel:"--force-full",usageDescription:"Snapshot: re-emit the full tree even when unchanged"},{key:"findFirst",names:["--first"],type:"boolean",usageLabel:"--first",usageDescription:"Find: pick the first match when ambiguous"},{key:"findLast",names:["--last"],type:"boolean",usageLabel:"--last",usageDescription:"Find: pick the last match when ambiguous"},{key:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"},{key:"overlayRefs",names:["--overlay-refs"],type:"boolean",usageLabel:"--overlay-refs",usageDescription:"Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide"},...w,{key:"baseline",names:["--baseline","-b"],type:"string",usageLabel:"--baseline, -b <path>",usageDescription:"Diff screenshot: path to baseline image file"},{key:"threshold",names:["--threshold"],type:"string",usageLabel:"--threshold <0-1>",usageDescription:"Diff screenshot: color distance threshold (default 0.1)"}],n5=new Set(["json","config","remoteConfig","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","leaseBackend","sessionLock","sessionLocked","sessionLockConflicts","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),n3={boot:{helpDescription:"Ensure target device/simulator is booted and ready",summary:"Boot target device/simulator",positionalArgs:[],allowedFlags:["headless"]},...e_,connect:{usageOverride:"connect [--remote-config <path>] [--tenant <id>] [--run-id <id>] [--lease-backend <backend>] [--force] [--no-login]",helpDescription:"Connect to a remote daemon, authenticate when needed, and save remote session state. AGENT_DEVICE_CLOUD_BASE_URL is the bridge/control-plane API origin; use AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_... for CI/service-token automation.",summary:"Connect to remote daemon",positionalArgs:[],allowedFlags:["force","noLogin","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","launchUrl"],skipCapabilityCheck:!0},mcp:{helpDescription:"Start the official stdio MCP discovery router. It exposes only a status tool with CLI install, verify, and starting-help guidance; device automation still runs through terminal CLI commands.",summary:"Start MCP discovery router",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},disconnect:{helpDescription:"Disconnect remote daemon state, stop owned Metro companion, and release lease",summary:"Disconnect remote daemon",positionalArgs:[],allowedFlags:["shutdown"],skipCapabilityCheck:!0},connection:{usageOverride:"connection status",listUsageOverride:"connection status",helpDescription:"Inspect active remote connection state",summary:"Inspect remote connection",positionalArgs:["status"],allowedFlags:[],skipCapabilityCheck:!0},auth:{usageOverride:"auth status|login|logout",listUsageOverride:"auth status|login|logout",helpDescription:"Manage cloud CLI authentication",summary:"Manage cloud authentication",positionalArgs:["status|login|logout"],allowedFlags:[],skipCapabilityCheck:!0},push:{helpDescription:"Simulate push notification payload delivery",summary:"Deliver push payload",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},...eM,devices:{helpDescription:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},appstate:{helpDescription:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},metro:{usageOverride:"metro prepare (--public-base-url <url> | --proxy-base-url <url>) [--project-root <path>] [--port <port>] [--kind auto|react-native|expo]\n agent-device metro reload [--metro-host <host>] [--metro-port <port>] [--bundle-url <url>]",listUsageOverride:"metro prepare --public-base-url <url> | --proxy-base-url <url>; metro reload",helpDescription:"Prepare a local Metro runtime or ask Metro to reload connected React Native apps",summary:"Prepare Metro or reload apps",positionalArgs:["prepare|reload"],allowedFlags:["metroHost","metroPort","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","bundleUrl"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",listUsageOverride:"clipboard read | clipboard write <text>",helpDescription:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",helpDescription:"Inspect Android keyboard visibility/type or dismiss the device keyboard",summary:"Inspect or dismiss the device keyboard",positionalArgs:["action?"],allowedFlags:[]},perf:{helpDescription:"Show session performance metrics, including frame health on Android and iOS devices",summary:"Show performance metrics",positionalArgs:[],allowedFlags:[]},"react-devtools":{usageOverride:"react-devtools [...args]",listUsageOverride:"react-devtools [...args]",helpDescription:"Run pinned agent-react-devtools commands for React Native performance profiling, component trees, props/state/hooks, and render analysis",summary:"Profile React Native performance and component renders",positionalArgs:["args?"],allowsExtraPositionals:!0,allowedFlags:[],skipCapabilityCheck:!0},back:{usageOverride:"back [--in-app|--system]",helpDescription:"Navigate back with explicit app or system semantics",summary:"Go back",positionalArgs:[],allowedFlags:["backMode"]},home:{helpDescription:"Go to home screen (where supported)",summary:"Go home",positionalArgs:[],allowedFlags:[]},rotate:{usageOverride:"rotate <portrait|portrait-upside-down|landscape-left|landscape-right>",helpDescription:"Rotate device orientation on iOS and Android",summary:"Rotate device orientation",positionalArgs:["orientation"],allowedFlags:[]},"app-switcher":{helpDescription:"Open app switcher (where supported)",summary:"Open app switcher",positionalArgs:[],allowedFlags:[]},...eP,alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",helpDescription:"Inspect or handle alert (iOS simulator and macOS desktop)",summary:"Inspect or handle iOS/macOS alerts",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",helpDescription:"Tap/click by coordinates, snapshot ref, or selector",summary:"Tap by coordinates, ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap","clickButton",...eO]},replay:{helpDescription:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate","replayMaestro","replayEnv"],skipCapabilityCheck:!0},test:{usageOverride:"test <path-or-glob>...",listUsageOverride:"test <path-or-glob>...",helpDescription:"Run one or more .ad scripts as a serial test suite",summary:"Run .ad test suites",positionalArgs:["pathOrGlob"],allowsExtraPositionals:!0,allowedFlags:["replayUpdate","replayEnv","failFast","timeoutMs","retries","artifactsDir","reportJunit"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",listUsageOverride:"batch --steps <json> | --steps-file <path>",helpDescription:"Execute multiple commands in one daemon request",summary:"Run multiple commands",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",helpDescription:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",summary:"Press by coordinates, ref, or selector",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...eO]},longpress:{helpDescription:"Long press by coordinates (iOS and Android)",summary:"Long press by coordinates",positionalArgs:["x","y","durationMs?"],allowedFlags:[]},swipe:{helpDescription:"Swipe coordinates with optional repeat pattern",summary:"Swipe coordinates",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{helpDescription:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},...A,fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",helpDescription:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...eO,"delayMs"]},scroll:{usageOverride:"scroll <direction> [amount] [--pixels <n>]",helpDescription:"Scroll in direction (relative amount or explicit pixels)",summary:"Scroll in a direction",positionalArgs:["direction","amount?"],allowedFlags:["pixels"]},pinch:{helpDescription:"Pinch/zoom gesture (Apple simulator or macOS app session)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",helpDescription:"Trigger app-defined event hook via deep link template",summary:"Trigger app event hook",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] [--quality <5-10>] [--hide-touches] | record stop",listUsageOverride:"record start [path] | record stop",helpDescription:"Start/stop screen recording",summary:"Start or stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps","quality","hideTouches"]},trace:{usageOverride:"trace start <path> | trace stop <path>",listUsageOverride:"trace start <path> | trace stop <path>",helpDescription:"Start/stop trace log capture; when an artifact path is requested, pass the same positional path to start and stop",summary:"Start or stop trace capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",helpDescription:"Session app log info, start/stop streaming, diagnostics, and markers",summary:"Manage session app logs",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] [--include summary|headers|body|all] | network log [limit] [summary|headers|body|all] [--include summary|headers|body|all]",helpDescription:"Dump recent HTTP(s) traffic parsed from the session app log",summary:"Show recent HTTP traffic",positionalArgs:["dump|log","limit?","include?"],allowedFlags:["networkInclude"]},settings:{usageOverride:ey,listUsageOverride:"settings [area] [options]",helpDescription:"Toggle OS settings, animation scales, appearance, and app permissions (macOS supports only settings appearance <light|dark|toggle> and settings permission <grant|reset> <accessibility|screen-recording|input-monitoring>; wifi|airplane|location|animations remain unsupported on macOS; mobile permission actions use the active session app)",summary:"Change OS settings and app permissions",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",helpDescription:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},n4=new Map,n8=new Map;for(let e of n2){for(let t of e.names)n4.set(t,e);let t=n8.get(e.key);t?t.push(e):n8.set(e.key,[e])}function n6(e){return n4.get(e)}function n7(){return n2}function n9(e){if(e)return n3[e]}function re(e,t){let a=n9(e);if(!a?.defaults)return!1;let n=!1;for(let[e,r]of Object.entries(a.defaults))void 0===t[e]&&(t[e]=r,n=!0);return n}function rt(){return Object.keys(n3)}function ra(e){if(!e)return!1;let t=e.trim().toLowerCase();return"1"===t||"true"===t||"yes"===t||"on"===t}function rn(e){let t=e.endsWith("?"),a=t?e.slice(0,-1):e;return t?`[${a}]`:`<${a}>`}let rr=(e=`agent-device <command> [args] [--json]
405
+ Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}},rg=[{key:"config",names:["--config"],type:"string",usageLabel:"--config <path>",usageDescription:"Load CLI defaults from a specific config file"},{key:"remoteConfig",names:["--remote-config"],type:"string",usageLabel:"--remote-config <path>",usageDescription:"Load remote host + Metro workflow settings from a specific profile file"},{key:"stateDir",names:["--state-dir"],type:"string",usageLabel:"--state-dir <path>",usageDescription:"Daemon state directory (defaults to ~/.agent-device)"},{key:"daemonBaseUrl",names:["--daemon-base-url"],type:"string",usageLabel:"--daemon-base-url <url>",usageDescription:"Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)"},{key:"daemonAuthToken",names:["--daemon-auth-token"],type:"string",usageLabel:"--daemon-auth-token <token>",usageDescription:"Remote HTTP daemon auth token (sent as request token and bearer header)"},{key:"daemonTransport",names:["--daemon-transport"],type:"enum",enumValues:["auto","socket","http"],usageLabel:"--daemon-transport auto|socket|http",usageDescription:"Daemon client transport preference"},{key:"daemonServerMode",names:["--daemon-server-mode"],type:"enum",enumValues:["socket","http","dual"],usageLabel:"--daemon-server-mode socket|http|dual",usageDescription:"Daemon server mode used when spawning daemon"},{key:"tenant",names:["--tenant"],type:"string",usageLabel:"--tenant <id>",usageDescription:"Tenant scope identifier for isolated daemon sessions"},{key:"sessionIsolation",names:["--session-isolation"],type:"enum",enumValues:["none","tenant"],usageLabel:"--session-isolation none|tenant",usageDescription:"Session isolation strategy (tenant prefixes session namespace)"},{key:"runId",names:["--run-id"],type:"string",usageLabel:"--run-id <id>",usageDescription:"Run identifier used for tenant lease admission checks"},{key:"leaseId",names:["--lease-id"],type:"string",usageLabel:"--lease-id <id>",usageDescription:"Lease identifier bound to tenant/run admission scope"},{key:"leaseBackend",names:["--lease-backend"],type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"],usageLabel:"--lease-backend ios-simulator|ios-instance|android-instance",usageDescription:"Lease backend for remote tenant connection admission"},{key:"force",names:["--force"],type:"boolean",usageLabel:"--force",usageDescription:"Force connection state replacement when reconnecting"},{key:"noLogin",names:["--no-login"],type:"boolean",usageLabel:"--no-login",usageDescription:"Connect: fail instead of starting implicit cloud login"},{key:"sessionLock",names:["--session-lock"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock reject|strip",usageDescription:"Lock bound-session device routing for this CLI invocation and nested batch steps"},{key:"sessionLocked",names:["--session-locked"],type:"boolean",usageLabel:"--session-locked",usageDescription:"Deprecated alias for --session-lock reject"},{key:"sessionLockConflicts",names:["--session-lock-conflicts"],type:"enum",enumValues:["reject","strip"],usageLabel:"--session-lock-conflicts reject|strip",usageDescription:"Deprecated alias for --session-lock"},{key:"platform",names:["--platform"],type:"enum",enumValues:["ios","macos","android","linux","apple"],usageLabel:"--platform ios|macos|android|linux|apple",usageDescription:"Platform to target (`apple` aliases the Apple automation backend)"},{key:"target",names:["--target"],type:"enum",enumValues:["mobile","tv","desktop"],usageLabel:"--target mobile|tv|desktop",usageDescription:"Device target class to match"},{key:"device",names:["--device"],type:"string",usageLabel:"--device <name>",usageDescription:"Device name to target"},{key:"udid",names:["--udid"],type:"string",usageLabel:"--udid <udid>",usageDescription:"iOS device UDID"},{key:"serial",names:["--serial"],type:"string",usageLabel:"--serial <serial>",usageDescription:"Android device serial"},{key:"surface",names:["--surface"],type:"enum",enumValues:rh,usageLabel:"--surface app|frontmost-app|desktop|menubar",usageDescription:"macOS session surface for open (defaults to app)"},{key:"headless",names:["--headless"],type:"boolean",usageLabel:"--headless",usageDescription:"Boot: launch Android emulator without a GUI window"},{key:"metroHost",names:["--metro-host"],type:"string",usageLabel:"--metro-host <host>",usageDescription:"Session-scoped Metro/debug host hint"},{key:"metroPort",names:["--metro-port"],type:"int",min:1,max:65535,usageLabel:"--metro-port <port>",usageDescription:"Session-scoped Metro/debug port hint"},{key:"metroProjectRoot",names:["--project-root"],type:"string",usageLabel:"--project-root <path>",usageDescription:"metro prepare: React Native project root (default: cwd)"},{key:"metroKind",names:["--kind"],type:"enum",enumValues:["auto","react-native","expo"],usageLabel:"--kind auto|react-native|expo",usageDescription:"metro prepare: detect or force the Metro launcher kind"},{key:"metroPublicBaseUrl",names:["--public-base-url"],type:"string",usageLabel:"--public-base-url <url>",usageDescription:"metro prepare: public base URL used for direct bundle hints"},{key:"metroProxyBaseUrl",names:["--proxy-base-url"],type:"string",usageLabel:"--proxy-base-url <url>",usageDescription:"metro prepare: optional bridge origin for remote Metro access"},{key:"metroBearerToken",names:["--bearer-token"],type:"string",usageLabel:"--bearer-token <token>",usageDescription:"metro prepare: host bridge bearer token (or AGENT_DEVICE_METRO_BEARER_TOKEN; falls back to AGENT_DEVICE_DAEMON_AUTH_TOKEN)"},{key:"metroPreparePort",names:["--port"],type:"int",min:1,max:65535,usageLabel:"--port <port>",usageDescription:"metro prepare: local Metro port (default: 8081)"},{key:"metroListenHost",names:["--listen-host"],type:"string",usageLabel:"--listen-host <host>",usageDescription:"metro prepare: host Metro listens on (default: 0.0.0.0)"},{key:"metroStatusHost",names:["--status-host"],type:"string",usageLabel:"--status-host <host>",usageDescription:"metro prepare: host used for local /status polling (default: 127.0.0.1)"},{key:"metroStartupTimeoutMs",names:["--startup-timeout-ms"],type:"int",min:1,usageLabel:"--startup-timeout-ms <ms>",usageDescription:"metro prepare: timeout while waiting for Metro to become ready"},{key:"metroProbeTimeoutMs",names:["--probe-timeout-ms"],type:"int",min:1,usageLabel:"--probe-timeout-ms <ms>",usageDescription:"metro prepare: timeout for /status and proxy bridge calls"},{key:"metroRuntimeFile",names:["--runtime-file"],type:"string",usageLabel:"--runtime-file <path>",usageDescription:"metro prepare: optional file path to persist the JSON result"},{key:"metroNoReuseExisting",names:["--no-reuse-existing"],type:"boolean",usageLabel:"--no-reuse-existing",usageDescription:"metro prepare: always start a fresh Metro process"},{key:"metroNoInstallDeps",names:["--no-install-deps"],type:"boolean",usageLabel:"--no-install-deps",usageDescription:"metro prepare: skip package-manager install when node_modules is missing"},{key:"bundleUrl",names:["--bundle-url"],type:"string",usageLabel:"--bundle-url <url>",usageDescription:"Session-scoped bundle URL hint"},{key:"launchUrl",names:["--launch-url"],type:"string",usageLabel:"--launch-url <url>",usageDescription:"Session-scoped deep link / launch URL hint"},{key:"iosSimulatorDeviceSet",names:["--ios-simulator-device-set"],type:"string",usageLabel:"--ios-simulator-device-set <path>",usageDescription:"Scope iOS simulator discovery/commands to this simulator device set"},{key:"androidDeviceAllowlist",names:["--android-device-allowlist"],type:"string",usageLabel:"--android-device-allowlist <serials>",usageDescription:"Comma/space separated Android serial allowlist for discovery/selection"},{key:"activity",names:["--activity"],type:"string",usageLabel:"--activity <component>",usageDescription:"Android app launch activity (package/Activity); not for URL opens"},{key:"launchConsole",names:["--launch-console"],type:"string",usageLabel:"--launch-console <path>",usageDescription:"open: capture the initial iOS simulator launch console window to a file"},{key:"header",names:["--header"],type:"string",multiple:!0,usageLabel:"--header <name:value>",usageDescription:"install-from-source: repeatable HTTP header for URL downloads"},{key:"githubActionsArtifact",names:["--github-actions-artifact"],type:"string",usageLabel:"--github-actions-artifact <owner/repo:artifact>",usageDescription:"install-from-source: GitHub Actions artifact resolved by a remote daemon"},{key:"installSource",names:[],type:"string"},{key:"session",names:["--session"],type:"string",usageLabel:"--session <name>",usageDescription:"Named session"},{key:"count",names:["--count"],type:"int",min:1,max:200,usageLabel:"--count <n>",usageDescription:"Repeat count for press/swipe series"},{key:"fps",names:["--fps"],type:"int",min:1,max:120,usageLabel:"--fps <n>",usageDescription:"Record: target frames per second (iOS physical device runner)"},{key:"quality",names:["--quality"],type:"int",min:5,max:10,usageLabel:"--quality <5-10>",usageDescription:"Record: scale recording resolution from 5 (50%) through 10 (native resolution)"},{key:"hideTouches",names:["--hide-touches"],type:"boolean",usageLabel:"--hide-touches",usageDescription:"Record: skip touch-overlay post-processing for faster raw benchmark videos"},{key:"intervalMs",names:["--interval-ms"],type:"int",min:0,max:1e4,usageLabel:"--interval-ms <ms>",usageDescription:"Delay between press iterations"},{key:"delayMs",names:["--delay-ms"],type:"int",min:0,max:1e4,usageLabel:"--delay-ms <ms>",usageDescription:"Delay between typed characters"},{key:"holdMs",names:["--hold-ms"],type:"int",min:0,max:1e4,usageLabel:"--hold-ms <ms>",usageDescription:"Press hold duration for each iteration"},{key:"jitterPx",names:["--jitter-px"],type:"int",min:0,max:100,usageLabel:"--jitter-px <n>",usageDescription:"Deterministic coordinate jitter radius for press"},{key:"pixels",names:["--pixels"],type:"int",min:1,max:1e5,usageLabel:"--pixels <n>",usageDescription:"Scroll: explicit gesture distance in pixels"},{key:"doubleTap",names:["--double-tap"],type:"boolean",usageLabel:"--double-tap",usageDescription:"Use double-tap gesture per press iteration"},{key:"clickButton",names:["--button"],type:"enum",enumValues:["primary","secondary","middle"],usageLabel:"--button primary|secondary|middle",usageDescription:"Click: choose mouse button (middle reserved for future macOS support)"},{key:"backMode",names:["--in-app"],type:"enum",enumValues:["in-app","system"],setValue:"in-app",usageLabel:"--in-app",usageDescription:"Back: use app-provided back UI when available"},{key:"backMode",names:["--system"],type:"enum",enumValues:["in-app","system"],setValue:"system",usageLabel:"--system",usageDescription:"Back: use system back input or gesture when available"},{key:"pauseMs",names:["--pause-ms"],type:"int",min:0,max:1e4,usageLabel:"--pause-ms <ms>",usageDescription:"Delay between swipe iterations"},{key:"pattern",names:["--pattern"],type:"enum",enumValues:["one-way","ping-pong"],usageLabel:"--pattern one-way|ping-pong",usageDescription:"Swipe repeat pattern"},{key:"verbose",names:["--debug","--verbose","-v"],type:"boolean",usageLabel:"--debug, --verbose, -v",usageDescription:"Enable debug diagnostics and stream daemon/runner logs"},{key:"json",names:["--json"],type:"boolean",usageLabel:"--json",usageDescription:"JSON output"},{key:"help",names:["--help","-h"],type:"boolean",usageLabel:"--help, -h",usageDescription:"Print help and exit"},{key:"version",names:["--version","-V"],type:"boolean",usageLabel:"--version, -V",usageDescription:"Print version and exit"},{key:"snapshotDiff",names:["--diff"],type:"boolean",usageLabel:"--diff",usageDescription:"Snapshot: show structural diff against the previous session baseline"},{key:"saveScript",names:["--save-script"],type:"booleanOrString",usageLabel:"--save-script [path]",usageDescription:"Save session script (.ad) on close; optional custom output path"},{key:"networkInclude",names:["--include"],type:"enum",enumValues:["summary","headers","body","all"],usageLabel:"--include summary|headers|body|all",usageDescription:"Network: include headers, bodies, or both in output"},{key:"shutdown",names:["--shutdown"],type:"boolean",usageLabel:"--shutdown",usageDescription:"close: shutdown associated simulator/emulator after ending session"},{key:"relaunch",names:["--relaunch"],type:"boolean",usageLabel:"--relaunch",usageDescription:"open: terminate app process before launching it"},{key:"restart",names:["--restart"],type:"boolean",usageLabel:"--restart",usageDescription:"logs clear: stop active stream, clear logs, then start streaming again"},{key:"retainPaths",names:["--retain-paths"],type:"boolean",usageLabel:"--retain-paths",usageDescription:"install-from-source: keep materialized artifact paths after install"},{key:"retentionMs",names:["--retention-ms"],type:"int",min:1,usageLabel:"--retention-ms <ms>",usageDescription:"install-from-source: retention TTL for materialized artifact paths"},{key:"noRecord",names:["--no-record"],type:"boolean",usageLabel:"--no-record",usageDescription:"Do not record this action"},{key:"replayUpdate",names:["--update","-u"],type:"boolean",usageLabel:"--update, -u",usageDescription:"Replay: update selectors and rewrite replay file in place"},{key:"replayMaestro",names:["--maestro"],type:"boolean",usageLabel:"--maestro",usageDescription:"Replay: treat input as a Maestro YAML compatibility flow. Supported subset: launchApp without state-reset side effects, runFlow file/inline with when.platform, onFlowStart/onFlowComplete, deterministic repeat.times, tapOn, doubleTapOn, longPressOn, inputText, pasteText, openLink, assertVisible, assertNotVisible, assertTrue literal true/false, extendedWaitUntil, scroll, absolute/percentage swipe, takeScreenshot, hideKeyboard, pressKey back/enter/home, back, waitForAnimationToEnd, stopApp/killApp, setAirplaneMode, setLocation, setOrientation, supported setPermissions targets, and startRecording/stopRecording. Unsupported syntax fails loudly with a link to https://github.com/callstackincubator/agent-device/issues/558"},{key:"replayEnv",names:["-e","--env"],type:"string",multiple:!0,usageLabel:"-e KEY=VALUE, --env KEY=VALUE",usageDescription:"Replay/Test: inject or override a ${KEY} variable for the script (repeatable)"},{key:"failFast",names:["--fail-fast"],type:"boolean",usageLabel:"--fail-fast",usageDescription:"Test: stop the suite after the first failing script"},{key:"timeoutMs",names:["--timeout"],type:"int",min:1,usageLabel:"--timeout <ms>",usageDescription:"Test: maximum wall-clock time per script attempt"},{key:"retries",names:["--retries"],type:"int",min:0,max:3,usageLabel:"--retries <n>",usageDescription:"Test: retry each failed script up to n additional times"},{key:"artifactsDir",names:["--artifacts-dir"],type:"string",usageLabel:"--artifacts-dir <path>",usageDescription:"Test: root directory for suite artifacts"},{key:"reportJunit",names:["--report-junit"],type:"string",usageLabel:"--report-junit <path>",usageDescription:"Test: write a JUnit XML report for the replay suite"},{key:"steps",names:["--steps"],type:"string",usageLabel:"--steps <json>",usageDescription:"Batch: JSON array of steps"},{key:"stepsFile",names:["--steps-file"],type:"string",usageLabel:"--steps-file <path>",usageDescription:"Batch: read steps JSON from file"},{key:"batchOnError",names:["--on-error"],type:"enum",enumValues:["stop"],usageLabel:"--on-error stop",usageDescription:"Batch: stop when a step fails"},{key:"batchMaxSteps",names:["--max-steps"],type:"int",min:1,max:1e3,usageLabel:"--max-steps <n>",usageDescription:"Batch: maximum number of allowed steps"},{key:"appsFilter",names:["--all"],type:"enum",enumValues:["user-installed","all"],setValue:"all",usageLabel:"--all",usageDescription:"Apps: include system/OEM apps"},{key:"snapshotInteractiveOnly",names:["-i"],type:"boolean",usageLabel:"-i",usageDescription:"Snapshot: interactive elements only"},{key:"snapshotCompact",names:["-c"],type:"boolean",usageLabel:"-c",usageDescription:"Snapshot: compact output (drop empty structure)"},{key:"snapshotDepth",names:["--depth","-d"],type:"int",min:0,usageLabel:"--depth, -d <depth>",usageDescription:"Snapshot: limit snapshot depth"},{key:"snapshotScope",names:["--scope","-s"],type:"string",usageLabel:"--scope, -s <scope>",usageDescription:"Snapshot: scope snapshot to label/identifier"},{key:"snapshotRaw",names:["--raw"],type:"boolean",usageLabel:"--raw",usageDescription:"Snapshot: raw node output"},{key:"snapshotForceFull",names:["--force-full"],type:"boolean",usageLabel:"--force-full",usageDescription:"Snapshot: re-emit the full tree even when unchanged"},{key:"findFirst",names:["--first"],type:"boolean",usageLabel:"--first",usageDescription:"Find: pick the first match when ambiguous"},{key:"findLast",names:["--last"],type:"boolean",usageLabel:"--last",usageDescription:"Find: pick the last match when ambiguous"},{key:"out",names:["--out"],type:"string",usageLabel:"--out <path>",usageDescription:"Output path"},{key:"overlayRefs",names:["--overlay-refs"],type:"boolean",usageLabel:"--overlay-refs",usageDescription:"Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide"},...w,{key:"baseline",names:["--baseline","-b"],type:"string",usageLabel:"--baseline, -b <path>",usageDescription:"Diff screenshot: path to baseline image file"},{key:"threshold",names:["--threshold"],type:"string",usageLabel:"--threshold <0-1>",usageDescription:"Diff screenshot: color distance threshold (default 0.1)"}],rb=new Set(["json","config","remoteConfig","stateDir","daemonBaseUrl","daemonAuthToken","daemonTransport","daemonServerMode","tenant","sessionIsolation","runId","leaseId","leaseBackend","sessionLock","sessionLocked","sessionLockConflicts","help","version","verbose","platform","target","device","udid","serial","iosSimulatorDeviceSet","androidDeviceAllowlist","session","noRecord"]),rw={boot:{helpDescription:"Ensure target device/simulator is booted and ready",summary:"Boot target device/simulator",positionalArgs:[],allowedFlags:["headless"]},...eQ,connect:{usageOverride:"connect [--remote-config <path>] [--tenant <id>] [--run-id <id>] [--lease-backend <backend>] [--force] [--no-login]",helpDescription:"Connect to a remote daemon, authenticate when needed, and save remote session state. AGENT_DEVICE_CLOUD_BASE_URL is the bridge/control-plane API origin; use AGENT_DEVICE_DAEMON_AUTH_TOKEN=adc_live_... for CI/service-token automation.",summary:"Connect to remote daemon",positionalArgs:[],allowedFlags:["force","noLogin","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","launchUrl"],skipCapabilityCheck:!0},mcp:{helpDescription:"Start the official stdio MCP discovery router. It exposes only a status tool with CLI install, verify, and starting-help guidance; device automation still runs through terminal CLI commands.",summary:"Start MCP discovery router",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},disconnect:{helpDescription:"Disconnect remote daemon state, stop owned Metro companion, and release lease",summary:"Disconnect remote daemon",positionalArgs:[],allowedFlags:["shutdown"],skipCapabilityCheck:!0},connection:{usageOverride:"connection status",listUsageOverride:"connection status",helpDescription:"Inspect active remote connection state",summary:"Inspect remote connection",positionalArgs:["status"],allowedFlags:[],skipCapabilityCheck:!0},auth:{usageOverride:"auth status|login|logout",listUsageOverride:"auth status|login|logout",helpDescription:"Manage cloud CLI authentication",summary:"Manage cloud authentication",positionalArgs:["status|login|logout"],allowedFlags:[],skipCapabilityCheck:!0},push:{helpDescription:"Simulate push notification payload delivery",summary:"Deliver push payload",positionalArgs:["bundleOrPackage","payloadOrJson"],allowedFlags:[]},...eB,devices:{helpDescription:"List available devices",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},appstate:{helpDescription:"Show foreground app/activity",positionalArgs:[],allowedFlags:[],skipCapabilityCheck:!0},metro:{usageOverride:"metro prepare (--public-base-url <url> | --proxy-base-url <url>) [--project-root <path>] [--port <port>] [--kind auto|react-native|expo]\n agent-device metro reload [--metro-host <host>] [--metro-port <port>] [--bundle-url <url>]",listUsageOverride:"metro prepare --public-base-url <url> | --proxy-base-url <url>; metro reload",helpDescription:"Prepare a local Metro runtime or ask Metro to reload connected React Native apps",summary:"Prepare Metro or reload apps",positionalArgs:["prepare|reload"],allowedFlags:["metroHost","metroPort","metroProjectRoot","metroKind","metroPublicBaseUrl","metroProxyBaseUrl","metroBearerToken","metroPreparePort","metroListenHost","metroStatusHost","metroStartupTimeoutMs","metroProbeTimeoutMs","metroRuntimeFile","metroNoReuseExisting","metroNoInstallDeps","bundleUrl"],skipCapabilityCheck:!0},clipboard:{usageOverride:"clipboard read | clipboard write <text>",listUsageOverride:"clipboard read | clipboard write <text>",helpDescription:"Read or write device clipboard text",positionalArgs:["read|write","text?"],allowsExtraPositionals:!0,allowedFlags:[]},keyboard:{usageOverride:"keyboard [status|get|dismiss]",helpDescription:"Inspect Android keyboard visibility/type or dismiss the device keyboard",summary:"Inspect or dismiss the device keyboard",positionalArgs:["action?"],allowedFlags:[]},perf:{helpDescription:"Show session performance metrics, including frame health on Android and iOS devices",summary:"Show performance metrics",positionalArgs:[],allowedFlags:[]},"react-devtools":{usageOverride:"react-devtools [...args]",listUsageOverride:"react-devtools [...args]",helpDescription:"Run pinned agent-react-devtools commands for React Native performance profiling, component trees, props/state/hooks, and render analysis",summary:"Profile React Native performance and component renders",positionalArgs:["args?"],allowsExtraPositionals:!0,allowedFlags:[],skipCapabilityCheck:!0},back:{usageOverride:"back [--in-app|--system]",helpDescription:"Navigate back with explicit app or system semantics",summary:"Go back",positionalArgs:[],allowedFlags:["backMode"]},home:{helpDescription:"Go to home screen (where supported)",summary:"Go home",positionalArgs:[],allowedFlags:[]},rotate:{usageOverride:"rotate <portrait|portrait-upside-down|landscape-left|landscape-right>",helpDescription:"Rotate device orientation on iOS and Android",summary:"Rotate device orientation",positionalArgs:["orientation"],allowedFlags:[]},"app-switcher":{helpDescription:"Open app switcher (where supported)",summary:"Open app switcher",positionalArgs:[],allowedFlags:[]},...eK,alert:{usageOverride:"alert [get|accept|dismiss|wait] [timeout]",helpDescription:"Inspect or handle platform alerts/dialogs",summary:"Inspect or handle platform alerts",positionalArgs:["action?","timeout?"],allowedFlags:[]},click:{usageOverride:"click <x y|@ref|selector>",helpDescription:"Tap/click by coordinates, snapshot ref, or selector",summary:"Tap by coordinates, ref, or selector",positionalArgs:["target"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap","clickButton",...eX]},replay:{helpDescription:"Replay a recorded session",positionalArgs:["path"],allowedFlags:["replayUpdate","replayMaestro","replayEnv"],skipCapabilityCheck:!0},test:{usageOverride:"test <path-or-glob>...",listUsageOverride:"test <path-or-glob>...",helpDescription:"Run one or more .ad scripts as a serial test suite",summary:"Run .ad test suites",positionalArgs:["pathOrGlob"],allowsExtraPositionals:!0,allowedFlags:["replayUpdate","replayEnv","failFast","timeoutMs","retries","artifactsDir","reportJunit"],skipCapabilityCheck:!0},batch:{usageOverride:"batch [--steps <json> | --steps-file <path>]",listUsageOverride:"batch --steps <json> | --steps-file <path>",helpDescription:"Execute multiple commands in one daemon request",summary:"Run multiple commands",positionalArgs:[],allowedFlags:["steps","stepsFile","batchOnError","batchMaxSteps","out"],skipCapabilityCheck:!0},press:{usageOverride:"press <x y|@ref|selector>",helpDescription:"Tap/press by coordinates, snapshot ref, or selector (supports repeated series)",summary:"Press by coordinates, ref, or selector",positionalArgs:["targetOrX","y?"],allowsExtraPositionals:!0,allowedFlags:["count","intervalMs","holdMs","jitterPx","doubleTap",...eX]},longpress:{usageOverride:"longpress <x y|@ref|selector> [durationMs]",helpDescription:"Long press a coordinate, ref, or selector (iOS and Android)",summary:"Long press a target",positionalArgs:["targetOrX","yOrDurationMs?","durationMs?"],allowsExtraPositionals:!0,allowedFlags:[...eX]},swipe:{helpDescription:"Swipe coordinates with optional repeat pattern",summary:"Swipe coordinates",positionalArgs:["x1","y1","x2","y2","durationMs?"],allowedFlags:["count","pauseMs","pattern"]},focus:{helpDescription:"Focus input at coordinates",positionalArgs:["x","y"],allowedFlags:[]},...A,fill:{usageOverride:"fill <x> <y> <text> | fill <@ref|selector> <text>",helpDescription:"Tap then type",positionalArgs:["targetOrX","yOrText","text?"],allowsExtraPositionals:!0,allowedFlags:[...eX,"delayMs"]},scroll:{usageOverride:"scroll <direction|top|bottom> [amount] [--pixels <n>]",helpDescription:"Scroll in direction, or verify hidden content and scroll toward top/bottom",summary:"Scroll in a direction or to an edge",positionalArgs:["directionOrEdge","amount?"],allowedFlags:["pixels"]},pinch:{helpDescription:"Pinch/zoom gesture (Apple simulator or macOS app session)",positionalArgs:["scale","x?","y?"],allowedFlags:[]},"trigger-app-event":{usageOverride:"trigger-app-event <event> [payloadJson]",helpDescription:"Trigger app-defined event hook via deep link template",summary:"Trigger app event hook",positionalArgs:["event","payloadJson?"],allowedFlags:[]},record:{usageOverride:"record start [path] [--fps <n>] [--quality <5-10>] [--hide-touches] | record stop",listUsageOverride:"record start [path] | record stop",helpDescription:"Start/stop screen recording",summary:"Start or stop screen recording",positionalArgs:["start|stop","path?"],allowedFlags:["fps","quality","hideTouches"]},...ej,trace:{usageOverride:"trace start <path> | trace stop <path>",listUsageOverride:"trace start <path> | trace stop <path>",helpDescription:"Start/stop trace log capture; when an artifact path is requested, pass the same positional path to start and stop",summary:"Start or stop trace capture",positionalArgs:["start|stop","path?"],allowedFlags:[],skipCapabilityCheck:!0},logs:{usageOverride:"logs path | logs start | logs stop | logs clear [--restart] | logs doctor | logs mark [message...]",helpDescription:"Session app log info, start/stop streaming, diagnostics, and markers",summary:"Manage session app logs",positionalArgs:["path|start|stop|clear|doctor|mark","message?"],allowsExtraPositionals:!0,allowedFlags:["restart"]},network:{usageOverride:"network dump [limit] [summary|headers|body|all] [--include summary|headers|body|all] | network log [limit] [summary|headers|body|all] [--include summary|headers|body|all]",helpDescription:"Dump recent HTTP(s) traffic parsed from the session app log",summary:"Show recent HTTP traffic",positionalArgs:["dump|log","limit?","include?"],allowedFlags:["networkInclude"]},settings:{usageOverride:ex,listUsageOverride:"settings [area] [options]",helpDescription:"Toggle OS settings, animation scales, appearance, and app permissions (macOS supports only settings appearance <light|dark|toggle> and settings permission <grant|reset> <accessibility|screen-recording|input-monitoring>; wifi|airplane|location|animations remain unsupported on macOS; mobile permission actions use the active session app)",summary:"Change OS settings and app permissions",positionalArgs:["setting","state","target?","mode?"],allowedFlags:[]},session:{usageOverride:"session list",helpDescription:"List active sessions",positionalArgs:["list?"],allowedFlags:[],skipCapabilityCheck:!0}},ry=new Map,rv=new Map;for(let e of rg){for(let t of e.names)ry.set(t,e);let t=rv.get(e.key);t?t.push(e):rv.set(e.key,[e])}function rk(e){return ry.get(e)}function rx(){return rg}function rA(e){if(e)return rw[e]}function rD(e,t){let a=rA(e);if(!a?.defaults)return!1;let n=!1;for(let[e,r]of Object.entries(a.defaults))void 0===t[e]&&(t[e]=r,n=!0);return n}function rI(){return Object.keys(rw)}function rR(e){let t=e.endsWith("?"),a=t?e.slice(0,-1):e;return t?`[${a}]`:`<${a}>`}let rS=(e=`agent-device <command> [args] [--json]
397
406
 
398
407
  CLI to control iOS and Android devices for AI agents.
399
- `,t=rl("Commands:",rt().map(e=>{let t=n3[e];if(!t)throw Error(`Missing command schema for ${e}`);return{name:e,schema:t,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let a=t.positionalArgs.map(a=>{var n,r,i;let s,o,l,c;return n=e,r=t,o=(s=(i=a).endsWith("?"))?i.slice(0,-1):i,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(o))||void 0!==r.usageOverride&&r.usageOverride.startsWith(`${n} ${o}`),s?l?`[${o}]`:c?o:`[${o}]`:c?o:`<${o}>`});return[e,...a].join(" ")}(e,t)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),a=ro("Flags:",rs(n5)),n=rc("Agent Quickstart:",["Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify -> close.",'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',"Plain snapshot reads state; snapshot -i is required to refresh interactive refs.","Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.","Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.","Anti-pattern: snapshot -i followed by snapshot -i | grep ...; prior refs stay valid until app state changes, and --force-full is the explicit full re-read.","Truncated text/input preview: expand first with snapshot -s @e12, not get text.","React Native apps: read help react-native for Metro, LogBox/RedBox overlays, DevTools routing, and RN-specific blockers.","Android RN/Expo Metro: adb reverse tcp:<port> tcp:<port> is harmless and helps the device reach any local Metro port.",'Expo Go/dev clients: use the provided URL when given; on iOS prefer open "Expo Go" <url>; Android URL opens infer the foreground package for logs/perf when possible.',"Install flows: install/install-from-source first, then open the installed id with --relaunch.",'Text: fill \'id="field-email"\' "qa@example.com" replaces; type appends after press.','Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.',"Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.","Run mutating commands serially against one session; parallelize only read-only commands or separate sessions.","Before taking over a shared device, run session list and reuse the active session name when one already owns the device.","Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.","After mutation: diff snapshot -i. Off-screen hints: scroll, then snapshot -i.","Raw coordinates are fallback-only: use snapshot -i -c --json rects when iOS refs no-op or child refs are missing.",'Batch JSON steps use "command", "positionals", "flags"; never "args" or "step".',"Navigation: app-owned back uses back; system back uses back --system.","Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.","Debug evidence: logs clear --restart/mark/path; trace start ./path; trace stop ./path; network dump --include headers.","Use agent-device commands in final plans; raw platform tools, pseudo commands, and helper prose are wrong.","Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood."]),r=rl("Agent Workflows:",[{label:"help workflow",description:"Normal bootstrap, exploration, and validation loop"},{label:"help debugging",description:"Logs, network, alerts, diagnostics, and traces"},{label:"help react-native",description:"React Native app automation hazards, overlays, Metro, and routing"},{label:"help react-devtools",description:"React Native performance, profiling, component tree, and renders"},{label:"help remote",description:"Remote/cloud config, tenants, leases, and local service tunnels"},{label:"help macos",description:"Desktop, frontmost-app, and menu bar surfaces"},{label:"help dogfood",description:"Exploratory QA report workflow"}]),i=rc("Configuration:",["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."]),s=rl("Environment:",[{label:"AGENT_DEVICE_SESSION",description:"Default session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"},{label:"AGENT_DEVICE_DAEMON_AUTH_TOKEN",description:"Remote daemon service/API token"},{label:"AGENT_DEVICE_CLOUD_BASE_URL",description:"Bridge/control-plane API origin for cloud auth and /api-keys"}]),o=rc("Examples:",["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"]),`${e}
408
+ `,t=rL("Commands:",rI().map(e=>{let t=rw[e];if(!t)throw Error(`Missing command schema for ${e}`);return{name:e,schema:t,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let a=t.positionalArgs.map(a=>{var n,r,i;let s,o,l,c;return n=e,r=t,o=(s=(i=a).endsWith("?"))?i.slice(0,-1):i,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(o))||void 0!==r.usageOverride&&r.usageOverride.startsWith(`${n} ${o}`),s?l?`[${o}]`:c?o:`[${o}]`:c?o:`<${o}>`});return[e,...a].join(" ")}(e,t)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),a=rO("Flags:",rN(rb)),n=rP("Agent Quickstart:",["Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify -> close.",'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',"Plain snapshot reads state; snapshot -i refreshes current interactive refs only.","Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.","Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.","Anti-pattern: snapshot -i followed by snapshot -i | grep ...; prior refs stay valid until app state changes, and --force-full is the explicit full re-read.","Truncated text/input preview: expand first with snapshot -s @e12, not get text.","React Native apps: read help react-native for Metro, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.","Android RN/Expo Metro: adb reverse tcp:<port> tcp:<port> is harmless and helps the device reach any local Metro port.",'Expo Go/dev clients: use the provided URL when given; on iOS prefer open "Expo Go" <url>; Android URL opens infer the foreground package for logs/perf when possible.',"Install flows: install/install-from-source first, then open the installed id with --relaunch.",'Text: fill \'id="field-email"\' "qa@example.com" replaces; type appends after press.','Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.',"Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.","Run mutating commands serially against one session; parallelize only read-only commands or separate sessions.","Before taking over a shared device, run session list and reuse the active session name when one already owns the device.","Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.","After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known.","Raw coordinates are fallback-only: use snapshot -i -c --json rects when iOS refs no-op or child refs are missing.",'Batch JSON steps use "command", "positionals", "flags"; never "args" or "step".',"Navigation: app-owned back uses back; system back uses back --system.","Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.","Debug evidence: logs clear --restart/mark/path; trace start ./path; trace stop ./path; network dump --include headers.","Use agent-device commands in final plans; raw platform tools, pseudo commands, and helper prose are wrong.","Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood."]),r=rL("Agent Workflows:",[{label:"help workflow",description:"Normal bootstrap, exploration, and validation loop"},{label:"help debugging",description:"Logs, network, alerts, diagnostics, and traces"},{label:"help react-native",description:"React Native app automation hazards, overlays, Metro, and routing"},{label:"help react-devtools",description:"React Native performance, profiling, component tree, and renders"},{label:"help remote",description:"Remote/cloud config, tenants, leases, and local service tunnels"},{label:"help macos",description:"Desktop, frontmost-app, and menu bar surfaces"},{label:"help dogfood",description:"Exploratory QA report workflow"}]),i=rP("Configuration:",["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."]),s=rL("Environment:",[{label:"AGENT_DEVICE_SESSION",description:"Default session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"},{label:"AGENT_DEVICE_DAEMON_AUTH_TOKEN",description:"Remote daemon service/API token"},{label:"AGENT_DEVICE_CLOUD_BASE_URL",description:"Bridge/control-plane API origin for cloud auth and /api-keys"}]),o=rP("Examples:",["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"]),`${e}
400
409
  ${t}
401
410
 
402
411
  ${a}
@@ -410,15 +419,15 @@ ${i}
410
419
  ${s}
411
420
 
412
421
  ${o}
413
- `);function ri(){return rr}function rs(e){return n2.filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function ro(e,t){return rl(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function rl(e,t){if(0===t.length)return`${e}
414
- (none)`;let a=Math.max(...t.map(e=>e.label.length))+2,n=[e];for(let e of t)n.push(` ${e.label.padEnd(a)}${e.description}`);return n.join("\n")}function rc(e,t){return 0===t.length?`${e}
415
- (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}function rd(e){var t,a;let n,r=(n=n1[e])?`${n.body}
422
+ `);function rM(){return rS}function rN(e){return rg.filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function rO(e,t){return rL(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function rL(e,t){if(0===t.length)return`${e}
423
+ (none)`;let a=Math.max(...t.map(e=>e.label.length))+2,n=[e];for(let e of t)n.push(` ${e.label.padEnd(a)}${e.description}`);return n.join("\n")}function rP(e,t){return 0===t.length?`${e}
424
+ (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}function rE(e){var t,a;let n,r=(n=rf[e])?`${n.body}
416
425
 
417
426
  Related:
418
427
  agent-device help command list and global flags
419
428
  agent-device help <command> command-specific flags
420
429
  agent-device help workflow normal app automation loop
421
- `:null;if(r)return r;let i=n9(e);if(!i)return null;let s=(t=e,(a=i).usageOverride?a.usageOverride:[t,...a.positionalArgs.map(rn),...a.allowedFlags.flatMap(e=>(n8.get(e)??[]).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`)].join(" ")),o=rs(new Set(i.allowedFlags)),l=rs(n5),c=[];return o.length>0&&c.push(ro("Command flags:",o)),c.push(ro("Global flags:",l)),`agent-device ${s}
430
+ `:null;if(r)return r;let i=rA(e);if(!i)return null;let s=(t=e,(a=i).usageOverride?a.usageOverride:[t,...a.positionalArgs.map(rR),...a.allowedFlags.flatMap(e=>(rv.get(e)??[]).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`)].join(" ")),o=rN(new Set(i.allowedFlags)),l=rN(rb),c=[];return o.length>0&&c.push(rO("Command flags:",o)),c.push(rO("Global flags:",l)),`agent-device ${s}
422
431
 
423
432
  ${i.helpDescription}
424
433
 
@@ -426,4 +435,4 @@ Usage:
426
435
  agent-device ${s}
427
436
 
428
437
  ${c.join("\n\n")}
429
- `}export{eN as CAPTURE_COMMAND_CAPABILITIES,n5 as GLOBAL_FLAG_KEYS,eE as SELECTOR_COMMAND_CAPABILITIES,e$ as SESSION_LIFECYCLE_COMMAND_CAPABILITIES,ev as SETTINGS_INVALID_ARGS_MESSAGE,re as applyCommandDefaults,rd as buildCommandUsageText,ea as buildMobileSnapshotPresentation,tP as buildSnapshotDisplayLines,ri as buildUsageText,nJ as createAgentDevice,eF as decodePng,en as deriveMobileSnapshotHiddenContentHints,et as displayNodeLabel,t3 as evaluateIsPredicate,eA as findMistargetedTypeRefToken,tE as formatSnapshotLine,rt as getCliCommandNames,n9 as getCommandSchema,n6 as getFlagDefinition,n7 as getFlagDefinitions,ex as getUnsupportedMacOsSettingMessage,ek as isMacOsSettingSupported,ra as isStrictFlagModeEnabled,t5 as isSupportedPredicate,nQ as localCommandPolicy,Z as normalizeSnapshotTree,eI as parseDeviceRotation,n0 as parseSessionSurface,eD as requireIntInRange,ah as resolveRectCenter};
438
+ `}export{eq as CAPTURE_COMMAND_CAPABILITIES,rb as GLOBAL_FLAG_KEYS,eV as REACT_NATIVE_COMMAND_CAPABILITIES,ez as SELECTOR_COMMAND_CAPABILITIES,eZ as SESSION_LIFECYCLE_COMMAND_CAPABILITIES,eA as SETTINGS_INVALID_ARGS_MESSAGE,rD as applyCommandDefaults,rE as buildCommandUsageText,er as buildMobileSnapshotPresentation,tH as buildSnapshotDisplayLines,rM as buildUsageText,eS as captureScrollEdgeState,rd as createAgentDevice,e2 as decodePng,ei as deriveMobileSnapshotHiddenContentHints,t4 as detectReactNativeOverlay,en as displayNodeLabel,ab as evaluateIsPredicate,eR as findMistargetedTypeRefToken,eN as formatScrollEdgeMessage,tJ as formatSnapshotLine,rI as getCliCommandNames,rA as getCommandSchema,rk as getFlagDefinition,rx as getFlagDefinitions,eI as getUnsupportedMacOsSettingMessage,ee as inferVerticalScrollIndicatorDirections,eD as isMacOsSettingSupported,e0 as isReactNativeCollapsedWarningLabel,ag as isSupportedPredicate,Z as isSystemScrollIndicatorLabel,ru as localCommandPolicy,et as normalizeSnapshotTree,e_ as parseDeviceRotation,rm as parseSessionSurface,eU as requireIntInRange,t8 as resolveReactNativeOverlayDismissTarget,aU as resolveRectCenter,eM as runScrollEdgePasses};