agent-device 0.11.3 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -8
- package/dist/src/168.js +3 -0
- package/dist/src/bin.js +68 -61
- package/dist/src/daemon.js +44 -41
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +1 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +4 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/AppIcon.appiconset/logo-tinted.jpg +0 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/Assets.xcassets/Contents.json +6 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +16 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +21 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +1 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +9 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +63 -17
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +4 -1
- package/ios-runner/README.md +1 -1
- package/ios-runner/RUNNER_PROTOCOL.md +4 -0
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +8 -1
- package/skills/agent-device/references/bootstrap-install.md +2 -0
- package/skills/agent-device/references/debugging.md +15 -0
- package/skills/agent-device/references/exploration.md +76 -6
- package/dist/src/916.js +0 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
If you know Vercel's [agent-browser](https://github.com/vercel-labs/agent-browser), this project applies the same broad idea to mobile apps and devices.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
[](./website/docs/public/agent-device-contacts.mp4)
|
|
16
16
|
|
|
17
17
|
## Project Goals
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ If you know Vercel's [agent-browser](https://github.com/vercel-labs/agent-browse
|
|
|
24
24
|
## Core Ideas
|
|
25
25
|
|
|
26
26
|
- Sessions: open a target once, interact within that session, then close it cleanly.
|
|
27
|
-
- Snapshots: inspect the current accessibility tree in a compact form and get
|
|
27
|
+
- Snapshots: inspect the current accessibility tree in a compact form and get current-screen refs for exploration.
|
|
28
28
|
- Refs vs selectors: use refs for discovery, use selectors for durable replay and assertions.
|
|
29
29
|
- Tests: run deterministic `.ad` scripts as a light e2e test suite.
|
|
30
30
|
- Replay scripts: save `.ad` flows with `--save-script`, replay one script with `replay`, or run a folder/glob as a serial suite with `test`.
|
|
@@ -36,22 +36,26 @@ If you know Vercel's [agent-browser](https://github.com/vercel-labs/agent-browse
|
|
|
36
36
|
The canonical loop is:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
+
agent-device apps --platform ios
|
|
39
40
|
agent-device open SampleApp --platform ios
|
|
40
41
|
agent-device snapshot -i
|
|
41
42
|
agent-device press @e3
|
|
42
43
|
agent-device diff snapshot -i
|
|
43
44
|
agent-device fill @e5 "test"
|
|
44
|
-
agent-device
|
|
45
|
+
agent-device press @e5
|
|
46
|
+
agent-device type " more" --delay-ms 80
|
|
45
47
|
agent-device close
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
In practice, most work follows the same pattern:
|
|
49
51
|
|
|
50
|
-
1. `
|
|
51
|
-
2. `
|
|
52
|
-
3. `
|
|
53
|
-
4. `
|
|
54
|
-
|
|
52
|
+
1. Discover the exact app id with `apps` if the package or bundle name is uncertain.
|
|
53
|
+
2. `open` a target app or URL.
|
|
54
|
+
3. `snapshot -i` to inspect the current screen.
|
|
55
|
+
4. `press`, `fill`, `scroll`, `get`, or `wait` using refs or selectors. On iOS and Android, default snapshot text follows the same visible-first contract: refs shown in default output are actionable now, while hidden content is surfaced as scroll/list discovery hints instead of tappable off-screen refs.
|
|
56
|
+
Use `rotate <orientation>` when a flow needs a deterministic portrait or landscape state on mobile targets.
|
|
57
|
+
5. `diff snapshot` or re-snapshot after UI changes.
|
|
58
|
+
6. `close` when the session is finished.
|
|
55
59
|
|
|
56
60
|
In non-JSON mode, core mutating commands print a short success acknowledgment so agents and humans can distinguish successful actions from dropped or silent no-ops.
|
|
57
61
|
|
|
@@ -74,6 +78,10 @@ For agents:
|
|
|
74
78
|
npm install -g agent-device
|
|
75
79
|
```
|
|
76
80
|
|
|
81
|
+
`agent-device` now performs a lightweight background upgrade check for interactive CLI runs and, when a newer package is available, suggests a global reinstall command. Updating the package also refreshes the bundled `skills/` shipped with the CLI.
|
|
82
|
+
|
|
83
|
+
Set `AGENT_DEVICE_NO_UPDATE_NOTIFIER=1` to disable the notice.
|
|
84
|
+
|
|
77
85
|
On macOS, `agent-device` includes a local `agent-device-macos-helper` source package that is built on demand for desktop permission checks, alert handling, and helper-backed desktop snapshot surfaces. Release distribution should use a signed/notarized helper build; source checkouts fall back to a local Swift build.
|
|
78
86
|
|
|
79
87
|
## Contributing
|
package/dist/src/168.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{AsyncLocalStorage as e}from"node:async_hooks";import t from"node:crypto";import n from"node:fs";import r from"node:os";import i from"node:path";import{fileURLToPath as o}from"node:url";import{spawn as a,spawnSync as s}from"node:child_process";import{PNG as l}from"pngjs";let u=new e,d=/(token|secret|password|authorization|cookie|api[_-]?key|access[_-]?key|private[_-]?key)/i,c=/(bearer\s+[a-z0-9._-]+|(?:api[_-]?key|token|secret|password)\s*[=:]\s*\S+)/i;function f(){return t.randomBytes(8).toString("hex")}async function p(e,n){let r={...e,diagnosticId:`${Date.now().toString(36)}-${t.randomBytes(4).toString("hex")}`,events:[]};return await u.run(r,n)}function m(){let e=u.getStore();return e?{diagnosticId:e.diagnosticId,requestId:e.requestId,session:e.session,command:e.command,debug:e.debug}:{}}function h(e){let t=u.getStore();if(!t)return;let r={ts:new Date().toISOString(),level:e.level??"info",phase:e.phase,session:t.session,requestId:t.requestId,command:t.command,durationMs:e.durationMs,data:e.data?v(e.data):void 0};if(t.events.push(r),!t.debug)return;let i=`[agent-device][diag] ${JSON.stringify(r)}
|
|
2
|
+
`;try{t.logPath&&n.appendFile(t.logPath,i,()=>{}),t.traceLogPath&&n.appendFile(t.traceLogPath,i,()=>{}),t.logPath||t.traceLogPath||process.stderr.write(i)}catch{}}async function g(e,t,n){let r=Date.now();try{let i=await t();return h({level:"info",phase:e,durationMs:Date.now()-r,data:n}),i}catch(t){throw h({level:"error",phase:e,durationMs:Date.now()-r,data:{...n??{},error:t instanceof Error?t.message:String(t)}}),t}}function w(e={}){let t=u.getStore();if(!t||!e.force&&!t.debug||0===t.events.length)return null;try{let e=(t.session??"default").replace(/[^a-zA-Z0-9._-]/g,"_"),o=new Date().toISOString().slice(0,10),a=i.join(r.homedir(),".agent-device","logs",e,o);n.mkdirSync(a,{recursive:!0});let s=new Date().toISOString().replace(/[:.]/g,"-"),l=i.join(a,`${s}-${t.diagnosticId}.ndjson`),u=t.events.map(e=>JSON.stringify(v(e)));return n.writeFileSync(l,`${u.join("\n")}
|
|
3
|
+
`),t.events=[],l}catch{return null}}function v(e){return function e(t,n,r){if(null==t)return t;if("string"==typeof t){var i=t,o=r;let e=i.trim();if(!e)return i;if(o&&d.test(o)||c.test(e))return"[REDACTED]";let n=function(e){try{let t=new URL(e);return t.search&&(t.search="?REDACTED"),(t.username||t.password)&&(t.username="REDACTED",t.password="REDACTED"),t.toString()}catch{return null}}(e);return n||(e.length>400?`${e.slice(0,200)}...<truncated>`:e)}if("object"!=typeof t)return t;if(n.has(t))return"[Circular]";if(n.add(t),Array.isArray(t))return t.map(t=>e(t,n));let a={};for(let[r,i]of Object.entries(t)){if(d.test(r)){a[r]="[REDACTED]";continue}a[r]=e(i,n,r)}return a}(e,new WeakSet)}class b extends Error{code;details;cause;constructor(e,t,n,r){super(t),this.code=e,this.details=n,this.cause=r}}function S(e){return e instanceof b?e:e instanceof Error?new b("UNKNOWN",e.message,void 0,e):new b("UNKNOWN","Unknown error",{err:e})}function I(e,t={}){let n=S(e),r=n.details?v(n.details):void 0,i=r&&"string"==typeof r.hint?r.hint:void 0,o=(r&&"string"==typeof r.diagnosticId?r.diagnosticId:void 0)??t.diagnosticId,a=(r&&"string"==typeof r.logPath?r.logPath:void 0)??t.logPath,s=i??function(e){switch(e){case"INVALID_ARGS":return"Check command arguments and run --help for usage examples.";case"SESSION_NOT_FOUND":return"Run open first or pass an explicit device selector.";case"TOOL_MISSING":return"Install required platform tooling and ensure it is available in PATH.";case"DEVICE_NOT_FOUND":return"Verify the target device is booted/connected and selectors match.";case"APP_NOT_INSTALLED":return"Run apps to discover the exact installed package or bundle id, or install the app before open.";case"UNSUPPORTED_OPERATION":return"This command is not available for the selected platform/device.";case"COMMAND_FAILED":default:return"Retry with --debug and inspect diagnostics log for details.";case"UNAUTHORIZED":return"Refresh daemon metadata and retry the command."}}(n.code),l=function(e){if(!e)return;let t={...e};return delete t.hint,delete t.diagnosticId,delete t.logPath,Object.keys(t).length>0?t:void 0}(r),u=function(e,t,n){if("COMMAND_FAILED"!==e||n?.processExitError!==!0)return t;let r=function(e){let t=[/^an error was encountered processing the command/i,/^underlying error\b/i,/^simulator device failed to complete the requested operation/i];for(let n of e.split("\n")){let e=n.trim();if(e&&!t.some(t=>t.test(e)))return e.length>200?`${e.slice(0,200)}...`:e}return null}("string"==typeof n?.stderr?n.stderr:"");return r||t}(n.code,n.message,r);return{code:n.code,message:u,hint:s,diagnosticId:o,logPath:a,details:l}}let y="<wifi|airplane|location> <on|off>",x="appearance <light|dark|toggle>",A="faceid <match|nonmatch|enroll|unenroll>",$="touchid <match|nonmatch|enroll|unenroll>",N="fingerprint <match|nonmatch>",E="permission <grant|deny|reset> <camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri> [full|limited]",D="permission <grant|reset> <accessibility|screen-recording|input-monitoring>",M=`macOS supports only settings ${x} and settings ${D}. wifi|airplane|location remain unsupported on macOS.`,L=`settings ${y} | settings ${x} | settings ${A} | settings ${$} | settings ${N} | settings ${E} | settings ${D}`,T=`settings requires ${y}, ${x}, ${A}, ${$}, ${N}, ${E}, or ${D}`;function O(e){let t=e.trim().toLowerCase();return"appearance"===t||"permission"===t}function C(e){return`Unsupported macOS setting: ${e}. ${M}`}let _=["app","frontmost-app","desktop","menubar"];function k(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 ${_.join("|")}.`)}function R(e){var t;let n,r=P(e.label),i=P(e.value),o=P(e.identifier),a=(t=o)&&!/^[\w.]+:id\/[\w.-]+$/i.test(t)&&!/^_?NS:\d+$/i.test(t)?o:"";return(n=F(e.type??"")).includes("textfield")||n.includes("securetextfield")||n.includes("searchfield")||n.includes("edittext")||n.includes("textview")||n.includes("textarea")?i||r||a:r||i||a}function P(e){return"string"==typeof e?e.trim():""}function F(e){let t=e.trim().replace(/XCUIElementType/gi,"").replace(/^AX/,"").toLowerCase(),n=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==n&&(t=t.slice(n+1)),t}function B(e,t={}){let n=[],r=[];for(let i of e){let e=i.depth??0,o=i.label?.trim()||i.value?.trim()||i.identifier?.trim()||"",a=G(i.type??"Element");if("group"===a&&!o)continue;for(;n.length>0&&e<=n[n.length-1];)n.pop();let s=n.length;n.push(e),r.push({node:i,depth:s,type:a,text:z(i,s,!1,a,t)})}return r}function z(e,t,n,r,i={}){var o,a,s,l,u;let d,c,f=r??G(e.type??"Element"),p=(d=R(e),{text:d,isLargeSurface:c=function(e,t){if("text-view"===t||"text-field"===t||"search"===t)return!0;let n=F(e.type??""),r=`${e.role??""} ${e.subrole??""}`.toLowerCase();return n.includes("textview")||n.includes("textarea")||n.includes("textfield")||n.includes("securetextfield")||n.includes("searchfield")||n.includes("edittext")||r.includes("text area")||r.includes("text field")}(e,f),shouldSummarize:c&&!!(o=d)&&(o.length>80||/[\r\n]/.test(o))}),m=(a=e,s=f,l=i,u=p,l.summarizeTextSurfaces&&u.shouldSummarize&&function(e,t,n){let r=P(e.label);if(r&&r!==n)return r;let i=P(e.identifier);if(i&&!U(i)&&i!==n)return i;switch(t){case"text":case"text-view":return"Text view";case"text-field":return"Text field";case"search":return"Search field";default:return""}}(a,s,u.text)||j(a,s)),h=" ".repeat(t),g=e.ref?`@${e.ref}`:"",w=(function(e,t,n,r){let i,o=[];if(!1===e.enabled&&o.push("disabled"),!n.summarizeTextSurfaces||(!0===e.selected&&o.push("selected"),V(t)&&o.push("editable"),function(e,t){if("scroll-area"===t)return!0;let n=(e.type??"").toLowerCase(),r=`${e.role??""} ${e.subrole??""}`.toLowerCase();return n.includes("scroll")||r.includes("scroll")}(e,t)&&o.push("scrollable"),!r.shouldSummarize))return o;return o.push(`preview:"${((i=r.text.replace(/\s+/g," ").trim()).length<=48?i:`${i.slice(0,45)}...`).replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`),o.push("truncated"),[...new Set(o)]})(e,f,i,p).map(e=>` [${e}]`).join(""),v=m?` "${m}"`:"";return n?`${h}${g} [${f}]${w}`.trimEnd():`${h}${g} [${f}]${v}${w}`.trimEnd()}function j(e,t){var n,r;let i,o=e.label?.trim();if(o&&(n=t,r=o,("scroll-area"===n||"list"===n||"collection"===n||"table"===n)&&(i=r.trim().toLowerCase())&&/^(vertical|horizontal)\s+scroll\s+bar(?:,?\s*\d+\s+pages?)?$/.test(i)))return"";let a=e.value?.trim();if(V(t)){if(a)return a;if(o)return o}else if(o)return o;if(a)return a;let s=e.identifier?.trim();return!s||U(s)&&("group"===t||"image"===t||"list"===t||"collection"===t)?"":s}function G(e){let t=e.replace(/XCUIElementType/gi,"").toLowerCase(),n=e.includes(".")&&(e.startsWith("android.")||e.startsWith("androidx.")||e.startsWith("com."));switch(t.includes(".")&&(t=t.replace(/^android\.widget\./,"").replace(/^android\.view\./,"").replace(/^android\.webkit\./,"").replace(/^androidx\./,"").replace(/^com\.google\.android\./,"").replace(/^com\.android\./,""),n&&t.includes(".")&&(t=t.slice(t.lastIndexOf(".")+1))),t){case"application":return"application";case"navigationbar":return"navigation-bar";case"tabbar":return"tab-bar";case"button":case"imagebutton":return"button";case"link":return"link";case"cell":return"cell";case"statictext":case"checkedtextview":return"text";case"textfield":case"edittext":return"text-field";case"textview":return n?"text":"text-view";case"textarea":return"text-view";case"switch":return"switch";case"slider":return"slider";case"image":case"imageview":return"image";case"webview":return"webview";case"framelayout":case"linearlayout":case"relativelayout":case"constraintlayout":case"viewgroup":case"view":case"group":return"group";case"listview":case"recyclerview":return"list";case"collectionview":return"collection";case"searchfield":return"search";case"segmentedcontrol":return"segmented-control";case"window":return"window";case"checkbox":return"checkbox";case"radio":return"radio";case"menuitem":return"menu-item";case"toolbar":return"toolbar";case"scrollarea":case"scrollview":case"nestedscrollview":return"scroll-area";case"table":return"table";default:return t||"element"}}function V(e){return"text-field"===e||"text-view"===e||"search"===e}function U(e){return/^[\w.]+:id\/[\w.-]+$/i.test(e)}function q(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function H(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function W(e,t){return e.find(e=>e.ref===t)??null}function J(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function K(e,t){let n=J(t),r=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)}),i=r.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),o=Q(i.map(e=>e.rect).filter(e=>Z(e,n.x,n.y)));if(o)return o;let a=Q(i.map(e=>e.rect));if(a)return a;let s=Q(r.map(e=>e.rect).filter(e=>Z(e,n.x,n.y)));return s||null}function X(e,t){let n=Math.max(1,t.height),r=t.y,i=t.y+n,o=r+.25*n,a=i-.25*n,s=e.y+e.height/2;return s<o?Math.ceil(o-s):s>a?Math.ceil(s-a):0}function Z(e,t,n){return t>=e.x&&t<=e.x+e.width&&n>=e.y&&n<=e.y+e.height}function Q(e){let t=null,n=-1;for(let r of e){let e=r.width*r.height;e>n&&(t=r,n=e)}return t}function Y(e,t,n,r){return Math.max(e,n)<=Math.min(t,r)}function ee(e){let t=new Map;for(let[n,r]of e.entries())t.set(r.index,n);let n=[],r=[];for(let[i,o]of e.entries()){let e=Math.max(0,o.depth??0);for(;r.length>0&&e<=r[r.length-1].depth;)r.pop();let a="number"==typeof o.parentIndex?t.get(o.parentIndex):void 0,s="number"==typeof a&&a<i?a:r[r.length-1]?.index;n.push({...o,index:i,depth:e,parentIndex:s}),r.push({depth:e,index:i})}return n}function et(e){return new Map(e.map(e=>[e.index,e]))}function en(e){let t=`${e??""}`.toLowerCase();return t.includes("scroll")||t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")||t.includes("collectionview")||"table"===t}function er(e){return!!en(e.type)||`${e.role??""} ${e.subrole??""}`.toLowerCase().includes("scroll")}function ei(e){if(0===e.length)return{nodes:e,hiddenCount:0,summaryLines:[]};let t=et(e),n=new Set,r=[];for(let i of e){if(eo(i,e,t)){!function(e,t,n){let r=e,i=new Set;for(;r&&!i.has(r.index);)i.add(r.index),t.add(r.index),r="number"==typeof r.parentIndex?n.get(r.parentIndex):void 0}(i,n,t);continue}r.push(i)}let i=function(e,t,n,r){let i=new Map,o=new Set;for(let e of t){if(!e.rect)continue;let t=eu(e,n,r);if(!t?.rect)continue;let a=es(e.rect,t.rect);if(!a)continue;let s=i.get(t.index)??new Set;s.add(a),i.set(t.index,s),o.add(e.index)}return function(e,t,n,r){for(let i of e){let e=function(e){let t=function(e,t){if(!(e?.trim().toLowerCase()??"").includes("vertical scroll bar"))return null;let n=function(e){if(!e)return null;let t=/^(\d{1,3})%$/.exec(e.trim());if(!t)return null;let n=Number(t[1]);return Number.isFinite(n)?Math.max(0,Math.min(100,n)):null}(t);return null===n?null:n<=1?{above:!1,below:!0}:n>=99?{above:!0,below:!1}:{above:!0,below:!0}}(e.label,e.value);if(!t)return null;let n=new Set;return t.above&&n.add("above"),t.below&&n.add("below"),n.size>0?n:null}(i);if(!e||0===e.size)continue;let o=eu(i,t,n);if(!o)continue;let a=r.get(o.index)??new Set;for(let t of e)a.add(t);r.set(o.index,a)}}(e,n,r,i),{directionsByContainer:i,coveredNodeIndexes:o}}(e,r,n,t),o=0===n.size?e:e.filter(e=>n.has(e.index));return{nodes:o.map(e=>(function(e,t){let n=t.get(e.index);if(!n||0===n.size)return e;let r=!!(!0===e.hiddenContentAbove||n.has("above"))||void 0,i=!!(!0===e.hiddenContentBelow||n.has("below"))||void 0;return{...e,hiddenContentAbove:r,hiddenContentBelow:i}})(e,i.directionsByContainer)),hiddenCount:0===n.size?0:e.length-o.length,summaryLines:function(e,t,n){let r=new Map;for(let i of e){let e=function(e,t,n){if(!e.rect)return null;let r=ea(e,t,n);return r?es(e.rect,r):null}(i,t,n);if(!e)continue;let o=r.get(e)??[];o.push(i),r.set(e,o)}return["above","below"].flatMap(e=>{let t=r.get(e);if(!t||0===t.length)return[];let n=(function(e){let t=new Set,n=[];for(let r of e){let e=el(r);!e||t.has(e)||(t.add(e),n.push(e))}return n})(t).slice(0,3).map(e=>`"${e}"`),i=1===t.length?"interactive item":"interactive items",o=n.length>0?`: ${n.join(", ")}`:"";return[`[off-screen ${e}] ${t.length} ${i}${o}`]})}(r.filter(e=>!i.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")||!!el(e)}(e)),e,t)}}function eo(e,t,n=et(t)){var r;if(!e.rect)return!0;let i=ea(e,t,n);return!i||(r=e.rect,Y(r.x,r.x+r.width,i.x,i.x+i.width)&&Y(r.y,r.y+r.height,i.y,i.y+i.height))}function ea(e,t,n=et(t)){let r=function(e,t){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),n.rect&&er(n))return n.rect;n="number"==typeof n.parentIndex?t.get(n.parentIndex):void 0}return null}(e,n);return r||K(t,e.rect??{x:0,y:0,width:0,height:0})}function es(e,t){return e.y+e.height<=t.y?"above":e.y>=t.y+t.height?"below":null}function el(e){return e.label?.trim()||e.value?.trim()||e.identifier?.trim()||""}function eu(e,t,n){let r="number"==typeof e.parentIndex?n.get(e.parentIndex):void 0,i=new Set;for(;r&&!i.has(r.index);){if(i.add(r.index),t.has(r.index)&&er(r))return r;r="number"==typeof r.parentIndex?n.get(r.parentIndex):void 0}return null}function ed(){try{let e=ec();return JSON.parse(n.readFileSync(i.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}function ec(){let e=i.dirname(o(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=i.join(t,"package.json");if(n.existsSync(e))return t;t=i.dirname(t)}return e}function ef(e){return e?{message:e}:{}}function ep(e,t){return t?{...e,message:t}:e}function em(e){return"string"==typeof e?.message&&e.message.length>0?e.message:null}async function eh(e,t,n={}){return new Promise((r,i)=>{let o=a(e,t,{cwd:n.cwd,env:n.env,stdio:["pipe","pipe","pipe"],detached:n.detached}),s="",l=n.binaryStdout?Buffer.alloc(0):void 0,u="",d=!1,c=eI(n.timeoutMs),f=c?setTimeout(()=>{d=!0,o.kill("SIGKILL")},c):null;n.binaryStdout||o.stdout.setEncoding("utf8"),o.stderr.setEncoding("utf8"),void 0!==n.stdin&&o.stdin.write(n.stdin),o.stdin.end(),o.stdout.on("data",e=>{n.binaryStdout?l=Buffer.concat([l??Buffer.alloc(0),Buffer.isBuffer(e)?e:Buffer.from(e)]):s+=e}),o.stderr.on("data",e=>{u+=e}),o.on("error",n=>{(f&&clearTimeout(f),"ENOENT"===n.code)?i(new b("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):i(new b("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),o.on("close",o=>{f&&clearTimeout(f);let a=o??1;d&&c?i(new b("COMMAND_FAILED",`${e} timed out after ${c}ms`,{cmd:e,args:t,stdout:s,stderr:u,exitCode:a,timeoutMs:c})):0===a||n.allowFailure?r({stdout:s,stderr:u,exitCode:a,stdoutBuffer:l}):i(new b("COMMAND_FAILED",`${e} exited with code ${a}`,{cmd:e,args:t,stdout:s,stderr:u,exitCode:a,processExitError:!0}))})})}async function eg(e){try{var t;let{shell:n,args:r}=(t=e,"win32"===process.platform?{shell:"cmd.exe",args:["/c","where",t]}:{shell:"bash",args:["-lc",`command -v ${t}`]}),i=await eh(n,r,{allowFailure:!0});return 0===i.exitCode&&i.stdout.trim().length>0}catch{return!1}}function ew(e,t,n={}){let r=s(e,t,{cwd:n.cwd,env:n.env,stdio:["pipe","pipe","pipe"],encoding:n.binaryStdout?void 0:"utf8",input:n.stdin,timeout:eI(n.timeoutMs)});if(r.error){let i=r.error.code;if("ETIMEDOUT"===i)throw new b("COMMAND_FAILED",`${e} timed out after ${eI(n.timeoutMs)}ms`,{cmd:e,args:t,timeoutMs:eI(n.timeoutMs)},r.error);if("ENOENT"===i)throw new b("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},r.error);throw new b("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},r.error)}let i=n.binaryStdout?Buffer.isBuffer(r.stdout)?r.stdout:Buffer.from(r.stdout??""):void 0,o=n.binaryStdout?"":"string"==typeof r.stdout?r.stdout:(r.stdout??"").toString(),a="string"==typeof r.stderr?r.stderr:(r.stderr??"").toString(),l=r.status??1;if(0!==l&&!n.allowFailure)throw new b("COMMAND_FAILED",`${e} exited with code ${l}`,{cmd:e,args:t,stdout:o,stderr:a,exitCode:l,processExitError:!0});return{stdout:o,stderr:a,exitCode:l,stdoutBuffer:i}}function ev(e,t,n={}){let r=a(e,t,{cwd:n.cwd,env:n.env,stdio:n.stdio??"ignore",detached:!0});return r.unref(),r.pid??0}async function eb(e,t,n={}){return new Promise((r,i)=>{let o=a(e,t,{cwd:n.cwd,env:n.env,stdio:["pipe","pipe","pipe"],detached:n.detached});n.onSpawn?.(o);let s="",l="",u=n.binaryStdout?Buffer.alloc(0):void 0,d=!1,c=eI(n.timeoutMs),f=c?setTimeout(()=>{d=!0,o.kill("SIGKILL")},c):null;n.binaryStdout||o.stdout.setEncoding("utf8"),o.stderr.setEncoding("utf8"),void 0!==n.stdin&&o.stdin.write(n.stdin),o.stdin.end(),o.stdout.on("data",e=>{if(n.binaryStdout){u=Buffer.concat([u??Buffer.alloc(0),Buffer.isBuffer(e)?e:Buffer.from(e)]);return}let t=String(e);s+=t,n.onStdoutChunk?.(t)}),o.stderr.on("data",e=>{let t=String(e);l+=t,n.onStderrChunk?.(t)}),o.on("error",n=>{(f&&clearTimeout(f),"ENOENT"===n.code)?i(new b("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):i(new b("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),o.on("close",o=>{f&&clearTimeout(f);let a=o??1;d&&c?i(new b("COMMAND_FAILED",`${e} timed out after ${c}ms`,{cmd:e,args:t,stdout:s,stderr:l,exitCode:a,timeoutMs:c})):0===a||n.allowFailure?r({stdout:s,stderr:l,exitCode:a,stdoutBuffer:u}):i(new b("COMMAND_FAILED",`${e} exited with code ${a}`,{cmd:e,args:t,stdout:s,stderr:l,exitCode:a,processExitError:!0}))})})}function eS(e,t,n={}){let r=a(e,t,{cwd:n.cwd,env:n.env,stdio:["ignore","pipe","pipe"],detached:n.detached}),i="",o="";r.stdout.setEncoding("utf8"),r.stderr.setEncoding("utf8"),r.stdout.on("data",e=>{i+=e}),r.stderr.on("data",e=>{o+=e});let s=new Promise((a,s)=>{r.on("error",n=>{"ENOENT"===n.code?s(new b("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):s(new b("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),r.on("close",r=>{let l=r??1;0===l||n.allowFailure?a({stdout:i,stderr:o,exitCode:l}):s(new b("COMMAND_FAILED",`${e} exited with code ${l}`,{cmd:e,args:t,stdout:i,stderr:o,exitCode:l,processExitError:!0}))})});return{child:r,wait:s}}function eI(e){if(!Number.isFinite(e))return;let t=Math.floor(e);if(!(t<=0))return t}let ey=[/(^|[/\s"'=])dist\/src\/daemon\.js($|[\s"'])/,/(^|[/\s"'=])src\/daemon\.ts($|[\s"'])/];function ex(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch(e){return"EPERM"===e.code}}function eA(e){if(!Number.isInteger(e)||e<=0)return null;try{let t=ew("ps",["-p",String(e),"-o","lstart="],{allowFailure:!0,timeoutMs:1e3});if(0!==t.exitCode)return null;let n=t.stdout.trim();return n.length>0?n:null}catch{return null}}function e$(e){if(!Number.isInteger(e)||e<=0)return null;try{let t=ew("ps",["-p",String(e),"-o","command="],{allowFailure:!0,timeoutMs:1e3});if(0!==t.exitCode)return null;let n=t.stdout.trim();return n.length>0?n:null}catch{return null}}function eN(e,t){let n;if(!ex(e))return!1;if(t){let n=eA(e);if(!n||n!==t)return!1}let r=e$(e);return!!r&&!!(n=r.toLowerCase().replaceAll("\\","/")).includes("agent-device")&&ey.some(e=>e.test(n))}function eE(e,t){try{return process.kill(e,t),!0}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return!1;throw t}}async function eD(e,t){if(!ex(e))return!0;let n=Date.now();for(;Date.now()-n<t;)if(await new Promise(e=>setTimeout(e,50)),!ex(e))return!0;return!ex(e)}async function eM(e,t){!eN(e,t.expectedStartTime)||!eE(e,"SIGTERM")||await eD(e,t.termTimeoutMs)||eE(e,"SIGKILL")&&await eD(e,t.killTimeoutMs)}function eL(e){return e?.HOME?.trim()||r.homedir()}function eT(e,t={}){return"~"===e?eL(t.env):e.startsWith("~/")?i.join(eL(t.env),e.slice(2)):e}function eO(e,t={}){let n=eT(e,t);return i.isAbsolute(n)?n:i.resolve(t.cwd??process.cwd(),n)}function eC(e){let t,n=(t=(e??"").trim())?eO(t):i.join(eT("~"),".agent-device");return{baseDir:n,infoPath:i.join(n,"daemon.json"),lockPath:i.join(n,"daemon.lock"),logPath:i.join(n,"daemon.log"),sessionsDir:i.join(n,"sessions")}}function e_(e){let t=(e??"").trim().toLowerCase();return"http"===t?"http":"dual"===t?"dual":"socket"}function ek(e){let t=(e??"").trim().toLowerCase();return"auto"===t?"auto":"socket"===t?"socket":"http"===t?"http":"auto"}function eR(e){return"tenant"===(e??"").trim().toLowerCase()?"tenant":"none"}function eP(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}let eF=100,eB=new Set(["batch","replay"]),ez=new Set(["command","positionals","flags","runtime"]);function ej(e){let t;try{t=JSON.parse(e)}catch{throw new b("INVALID_ARGS","Batch steps must be valid JSON.")}if(!Array.isArray(t)||0===t.length)throw new b("INVALID_ARGS","Batch steps must be a non-empty JSON array.");return t}function eG(e,t){if(!Array.isArray(e)||0===e.length)throw new b("INVALID_ARGS","batch requires a non-empty batchSteps array.");if(e.length>t)throw new b("INVALID_ARGS",`batch has ${e.length} steps; max allowed is ${t}.`);let n=[];for(let t=0;t<e.length;t+=1){let r=e[t];if(!r||"object"!=typeof r)throw new b("INVALID_ARGS",`Invalid batch step at index ${t}.`);let i=Object.keys(r).filter(e=>!ez.has(e));if(i.length>0){let e=i.map(e=>`"${e}"`).join(", ");throw new b("INVALID_ARGS",`Batch step ${t+1} has unknown field(s): ${e}. Allowed fields: command, positionals, flags, runtime.`)}let o="string"==typeof r.command?r.command.trim().toLowerCase():"";if(!o)throw new b("INVALID_ARGS",`Batch step ${t+1} requires command.`);if(eB.has(o))throw new b("INVALID_ARGS",`Batch step ${t+1} cannot run ${o}.`);if(void 0!==r.positionals&&!Array.isArray(r.positionals))throw new b("INVALID_ARGS",`Batch step ${t+1} positionals must be an array.`);let a=r.positionals??[];if(a.some(e=>"string"!=typeof e))throw new b("INVALID_ARGS",`Batch step ${t+1} positionals must contain only strings.`);if(void 0!==r.flags&&("object"!=typeof r.flags||Array.isArray(r.flags)||!r.flags))throw new b("INVALID_ARGS",`Batch step ${t+1} flags must be an object.`);if(void 0!==r.runtime&&("object"!=typeof r.runtime||Array.isArray(r.runtime)||!r.runtime))throw new b("INVALID_ARGS",`Batch step ${t+1} runtime must be an object.`);n.push({command:o,positionals:a,flags:r.flags??{},runtime:r.runtime})}return n}function eV(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function eU(e,t,n){return{deviceId:t,deviceName:n,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function eq(e,t={}){let n=t.includeAndroidSerial??!0;return{platform:e.platform,target:e.target,device:e.name,id:e.id,..."ios"===e.platform?{device_udid:e.ios?.udid??e.id,ios_simulator_device_set:e.ios?.simulatorSetPath??null}:{},..."android"===e.platform&&n?{serial:e.android?.serial??e.id}:{}}}function eH(e){return{name:e.name,...eq(e.device,{includeAndroidSerial:!1}),createdAt:e.createdAt}}function eW(e){return{platform:e.platform,id:e.id,name:e.name,kind:e.kind,target:e.target,..."boolean"==typeof e.booted?{booted:e.booted}:{}}}function eJ(e){let t=e.created?"Created":"Reused",n=e.booted?" (booted)":"";return ep({udid:e.udid,device:e.device,runtime:e.runtime,ios_simulator_device_set:e.iosSimulatorDeviceSet??null,created:e.created,booted:e.booted},`${t}: ${e.device} ${e.udid}${n}`)}function eK(e){return e.bundleId??e.package??e.app}function eX(e){return ep({app:e.app,appPath:e.appPath,platform:e.platform,...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.package?{package:e.package}:{}},`Installed: ${eK(e)}`)}function eZ(e){return e.appName??e.bundleId??e.packageName??e.launchTarget}function eQ(e){return ep({launchTarget:e.launchTarget,...e.appName?{appName:e.appName}:{},...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.packageName?{package:e.packageName}:{},...e.installablePath?{installablePath:e.installablePath}:{},...e.archivePath?{archivePath:e.archivePath}:{},...e.materializationId?{materializationId:e.materializationId}:{},...e.materializationExpiresAt?{materializationExpiresAt:e.materializationExpiresAt}:{}},`Installed: ${eZ(e)}`)}function eY(e){let t=e.appName??e.appBundleId??e.session;return ep({session:e.session,...e.appName?{appName:e.appName}:{},...e.appBundleId?{appBundleId:e.appBundleId}:{},...e.startup?{startup:e.startup}:{},...e.runtime?{runtime:e.runtime}:{},...e.device?eq(e.device):{}},t?`Opened: ${t}`:"Opened")}function e0(e){return{session:e.session,...e.shutdown?{shutdown:e.shutdown}:{},...ef(e.session?`Closed: ${e.session}`:"Closed")}}function e1(e){return{nodes:e.nodes,truncated:e.truncated,...e.appName?{appName:e.appName}:{},...e.appBundleId?{appBundleId:e.appBundleId}:{},...e.visibility?{visibility:e.visibility}:{},...e.warnings&&e.warnings.length>0?{warnings:e.warnings}:{}}}function e8(e,t){try{return l.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)})}}export{b as AppError,eF as DEFAULT_BATCH_MAX_STEPS,_ as SESSION_SURFACES,T as SETTINGS_INVALID_ARGS_MESSAGE,L as SETTINGS_USAGE_OVERRIDE,S as asAppError,q as attachRefs,eV as buildAppIdentifiers,eU as buildDeviceIdentifiers,ei as buildMobileSnapshotPresentation,B as buildSnapshotDisplayLines,J as centerOfRect,Z as containsPoint,f as createRequestId,e8 as decodePng,j as displayLabel,X as distanceFromSafeViewportBand,h as emitDiagnostic,eT as expandUserHomePath,R as extractReadableText,W as findNodeByRef,ec as findProjectRoot,w as flushDiagnosticsToSessionFile,G as formatRole,z as formatSnapshotLine,m as getDiagnosticsMeta,C as getUnsupportedMacOsSettingMessage,eN as isAgentDeviceDaemonProcess,O as isMacOsSettingSupported,eo as isNodeVisibleInEffectiveViewport,ex as isProcessAlive,en as isScrollableType,I as normalizeError,H as normalizeRef,ee as normalizeSnapshotTree,eP as normalizeTenantId,ej as parseBatchStepsJson,k as parseSessionSurface,Q as pickLargestRect,em as readCommandMessage,e$ as readProcessCommand,eA as readProcessStartTime,ed as readVersion,eC as resolveDaemonPaths,e_ as resolveDaemonServerMode,ek as resolveDaemonTransportPreference,eK as resolveDeployResultTarget,ea as resolveEffectiveViewportRect,eZ as resolveInstallFromSourceResultTarget,eR as resolveSessionIsolationMode,eO as resolveUserPath,K as resolveViewportRect,eh as runCmd,eS as runCmdBackground,ev as runCmdDetached,eb as runCmdStreaming,ew as runCmdSync,e0 as serializeCloseResult,eX as serializeDeployResult,eW as serializeDevice,eJ as serializeEnsureSimulatorResult,eQ as serializeInstallFromSourceResult,eY as serializeOpenResult,eH as serializeSessionListEntry,e1 as serializeSnapshotResult,eM as stopProcessForTakeover,ef as successText,eG as validateAndNormalizeBatchSteps,eg as whichCmd,g as withDiagnosticTimer,p as withDiagnosticsScope,ep as withSuccessText};
|