agent-device 0.3.0 → 0.3.1

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 CHANGED
@@ -96,6 +96,7 @@ Notes:
96
96
  - If XCTest returns 0 nodes (e.g., foreground app changed), agent-device falls back to AX when available.
97
97
 
98
98
  Flags:
99
+ - `--version, -V` print version and exit
99
100
  - `--platform ios|android`
100
101
  - `--device <name>`
101
102
  - `--udid <udid>` (iOS)
@@ -183,6 +184,11 @@ App state:
183
184
  - Built-in retries cover transient runner connection failures, AX snapshot hiccups, and Android UI dumps.
184
185
  - For snapshot issues (missing elements), compare with `--raw` flag for unaltered output and scope with `-s "<label>"`.
185
186
 
187
+ Boot diagnostics:
188
+ - Boot failures include normalized reason codes in `error.details.reason` (JSON mode) and verbose logs.
189
+ - Reason codes: `BOOT_TIMEOUT`, `DEVICE_UNAVAILABLE`, `DEVICE_OFFLINE`, `PERMISSION_DENIED`, `TOOL_MISSING`, `BOOT_COMMAND_FAILED`, `UNKNOWN`.
190
+ - Android boot waits fail fast for permission/tooling issues and do not always collapse into timeout errors.
191
+
186
192
  ## App resolution
187
193
  - Bundle/package identifiers are accepted directly (e.g., `com.apple.Preferences`).
188
194
  - Human-readable names are resolved when possible (e.g., `Settings`).
@@ -199,6 +205,14 @@ App state:
199
205
  pnpm test
200
206
  ```
201
207
 
208
+ Useful local checks:
209
+
210
+ ```bash
211
+ pnpm typecheck
212
+ pnpm test:unit
213
+ pnpm test:smoke
214
+ ```
215
+
202
216
  ## Build
203
217
 
204
218
  ```bash
@@ -208,6 +222,7 @@ pnpm build
208
222
  Environment selectors:
209
223
  - `ANDROID_DEVICE=Pixel_9_Pro_XL` or `ANDROID_SERIAL=emulator-5554`
210
224
  - `IOS_DEVICE="iPhone 17 Pro"` or `IOS_UDID=<udid>`
225
+ - `AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS=<ms>` to adjust iOS simulator boot timeout (default: `120000`, minimum: `5000`).
211
226
 
212
227
  Test screenshots are written to:
213
228
  - `test/screenshots/android-settings.png`
@@ -0,0 +1 @@
1
+ import e,{promises as t}from"node:fs";import n from"node:path";import{fileURLToPath as o,pathToFileURL as r}from"node:url";import{spawn as i}from"node:child_process";function d(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class s extends Error{constructor(e,t,n,o){super(t),d(this,"code",void 0),d(this,"details",void 0),d(this,"cause",void 0),this.code=e,this.details=n,this.cause=o}}function a(e){return e instanceof s?e:e instanceof Error?new s("UNKNOWN",e.message,void 0,e):new s("UNKNOWN","Unknown error",{err:e})}function u(){try{let t=c();return JSON.parse(e.readFileSync(n.join(t,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}function c(){let t=n.dirname(o(import.meta.url)),r=t;for(let t=0;t<6;t+=1){let t=n.join(r,"package.json");if(e.existsSync(t))return r;r=n.dirname(r)}return t}async function f(e,t,n={}){return new Promise((o,r)=>{let d=i(e,t,{cwd:n.cwd,env:n.env,stdio:["pipe","pipe","pipe"]}),a="",u=n.binaryStdout?Buffer.alloc(0):void 0,c="";n.binaryStdout||d.stdout.setEncoding("utf8"),d.stderr.setEncoding("utf8"),void 0!==n.stdin&&d.stdin.write(n.stdin),d.stdin.end(),d.stdout.on("data",e=>{n.binaryStdout?u=Buffer.concat([u??Buffer.alloc(0),Buffer.isBuffer(e)?e:Buffer.from(e)]):a+=e}),d.stderr.on("data",e=>{c+=e}),d.on("error",n=>{"ENOENT"===n.code?r(new s("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):r(new s("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),d.on("close",i=>{let d=i??1;0===d||n.allowFailure?o({stdout:a,stderr:c,exitCode:d,stdoutBuffer:u}):r(new s("COMMAND_FAILED",`${e} exited with code ${d}`,{cmd:e,args:t,stdout:a,stderr:c,exitCode:d}))})})}async function l(e){try{var t;let{shell:n,args:o}=(t=e,"win32"===process.platform?{shell:"cmd.exe",args:["/c","where",t]}:{shell:"bash",args:["-lc",`command -v ${t}`]}),r=await f(n,o,{allowFailure:!0});return 0===r.exitCode&&r.stdout.trim().length>0}catch{return!1}}function p(e,t,n={}){i(e,t,{cwd:n.cwd,env:n.env,stdio:"ignore",detached:!0}).unref()}async function w(e,t,n={}){return new Promise((o,r)=>{let d=i(e,t,{cwd:n.cwd,env:n.env,stdio:["pipe","pipe","pipe"]}),a="",u="",c=n.binaryStdout?Buffer.alloc(0):void 0;n.binaryStdout||d.stdout.setEncoding("utf8"),d.stderr.setEncoding("utf8"),void 0!==n.stdin&&d.stdin.write(n.stdin),d.stdin.end(),d.stdout.on("data",e=>{if(n.binaryStdout){c=Buffer.concat([c??Buffer.alloc(0),Buffer.isBuffer(e)?e:Buffer.from(e)]);return}let t=String(e);a+=t,n.onStdoutChunk?.(t)}),d.stderr.on("data",e=>{let t=String(e);u+=t,n.onStderrChunk?.(t)}),d.on("error",n=>{"ENOENT"===n.code?r(new s("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):r(new s("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),d.on("close",i=>{let d=i??1;0===d||n.allowFailure?o({stdout:a,stderr:u,exitCode:d,stdoutBuffer:c}):r(new s("COMMAND_FAILED",`${e} exited with code ${d}`,{cmd:e,args:t,stdout:a,stderr:u,exitCode:d}))})})}function m(e,t,n={}){let o=i(e,t,{cwd:n.cwd,env:n.env,stdio:["ignore","pipe","pipe"]}),r="",d="";o.stdout.setEncoding("utf8"),o.stderr.setEncoding("utf8"),o.stdout.on("data",e=>{r+=e}),o.stderr.on("data",e=>{d+=e});let a=new Promise((i,a)=>{o.on("error",n=>{"ENOENT"===n.code?a(new s("TOOL_MISSING",`${e} not found in PATH`,{cmd:e},n)):a(new s("COMMAND_FAILED",`Failed to run ${e}`,{cmd:e,args:t},n))}),o.on("close",o=>{let u=o??1;0===u||n.allowFailure?i({stdout:r,stderr:d,exitCode:u}):a(new s("COMMAND_FAILED",`${e} exited with code ${u}`,{cmd:e,args:t,stdout:r,stderr:d,exitCode:u}))})});return{child:o,wait:a}}export{default as node_net}from"node:net";export{default as node_os}from"node:os";export{a as asAppError,s as errors_AppError,o as fileURLToPath,c as findProjectRoot,e as node_fs,n as node_path,r as pathToFileURL,t as promises,u as readVersion,f as runCmd,m as runCmdBackground,p as runCmdDetached,w as runCmdStreaming,l as whichCmd};
package/dist/src/bin.js CHANGED
@@ -1,8 +1,9 @@
1
- import{node_path as e,fileURLToPath as t,asAppError as r,pathToFileURL as n,runCmdDetached as a,node_fs as i,node_os as s,node_net as o,errors_AppError as l}from"./861.js";function c(e){process.stdout.write(`${JSON.stringify(e,null,2)}
2
- `)}function d(e){let t=e.details?`
1
+ import{node_path as e,asAppError as t,pathToFileURL as r,runCmdDetached as i,node_fs as n,node_os as s,node_net as a,errors_AppError as o,readVersion as l,findProjectRoot as c}from"./274.js";function d(e){process.stdout.write(`${JSON.stringify(e,null,2)}
2
+ `)}function u(e){let t=e.details?`
3
3
  ${JSON.stringify(e.details,null,2)}`:"";process.stderr.write(`Error (${e.code}): ${e.message}${t}
4
- `)}function u(e,t,r){let n=p(e.type??"Element"),a=function(e,t){var r,n;let a=e.label?.trim(),i=e.value?.trim();if("text-field"===(r=t)||"text-view"===r||"search"===r){if(i)return i;if(a)return a}else if(a)return a;if(i)return i;let s=e.identifier?.trim();return!s||(n=s,/^[\w.]+:id\/[\w.-]+$/i.test(n)&&("group"===t||"image"===t||"list"===t||"collection"===t))?"":s}(e,n),i=" ".repeat(t),s=e.ref?`@${e.ref}`:"",o=[!1===e.enabled?"disabled":null].filter(Boolean).join(", "),l=o?` [${o}]`:"",c=a?` "${a}"`:"";return r?`${i}${s} [${n}]${l}`.trimEnd():`${i}${s} [${n}]${c}${l}`.trimEnd()}function p(e){let t=e.replace(/XCUIElementType/gi,"").toLowerCase(),r=e.includes(".")&&(e.startsWith("android.")||e.startsWith("androidx.")||e.startsWith("com."));switch(t.startsWith("ax")&&(t=t.replace(/^ax/,"")),t.includes(".")&&(t=t.replace(/^android\.widget\./,"").replace(/^android\.view\./,"").replace(/^android\.webkit\./,"").replace(/^androidx\./,"").replace(/^com\.google\.android\./,"").replace(/^com\.android\./,"")),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 r?"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"}}let f=e.join(s.homedir(),".agent-device"),m=e.join(f,"daemon.json"),h=function(){let e=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS;if(!e)return 6e4;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):6e4}();async function w(e){let t=await y(),r={...e,token:t.token};return await x(t,r)}async function y(){let t=g(),r=function(){try{let t=$();return JSON.parse(i.readFileSync(e.join(t,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}();if(t&&t.version===r&&await v(t))return t;t&&(t.version!==r||!await v(t))&&i.existsSync(m)&&i.unlinkSync(m),await b();let n=Date.now();for(;Date.now()-n<5e3;){let e=g();if(e&&await v(e))return e;await new Promise(e=>setTimeout(e,100))}throw new l("COMMAND_FAILED","Failed to start daemon",{infoPath:m,hint:"Run pnpm build, or delete ~/.agent-device/daemon.json if stale."})}function g(){if(!i.existsSync(m))return null;try{let e=JSON.parse(i.readFileSync(m,"utf8"));if(!e.port||!e.token)return null;return e}catch{return null}}async function v(e){return new Promise(t=>{let r=o.createConnection({host:"127.0.0.1",port:e.port},()=>{r.destroy(),t(!0)});r.on("error",()=>{t(!1)})})}async function b(){let t=$(),r=e.join(t,"dist","src","daemon.js"),n=e.join(t,"src","daemon.ts"),s=i.existsSync(r);if(!s&&!i.existsSync(n))throw new l("COMMAND_FAILED","Daemon entry not found",{distPath:r,srcPath:n});let o=s?[r]:["--experimental-strip-types",n];a(process.execPath,o)}async function x(e,t){return new Promise((r,n)=>{let a=o.createConnection({host:"127.0.0.1",port:e.port},()=>{a.write(`${JSON.stringify(t)}
5
- `)}),i=setTimeout(()=>{a.destroy(),n(new l("COMMAND_FAILED","Daemon request timed out",{timeoutMs:h}))},h),s="";a.setEncoding("utf8"),a.on("data",e=>{let t=(s+=e).indexOf("\n");if(-1===t)return;let o=s.slice(0,t).trim();if(o)try{let e=JSON.parse(o);a.end(),clearTimeout(i),r(e)}catch(e){clearTimeout(i),n(e)}}),a.on("error",e=>{clearTimeout(i),n(e)})})}function $(){let r=e.dirname(t(import.meta.url)),n=r;for(let t=0;t<6;t+=1){let t=e.join(n,"package.json");if(i.existsSync(t))return n;n=e.dirname(n)}return r}async function S(t){let n=function(e){let t={json:!1,help:!1},r=[];for(let n=0;n<e.length;n+=1){let a=e[n];if("--json"===a){t.json=!0;continue}if("--help"===a||"-h"===a){t.help=!0;continue}if("--verbose"===a||"-v"===a){t.verbose=!0;continue}if("-i"===a){t.snapshotInteractiveOnly=!0;continue}if("-c"===a){t.snapshotCompact=!0;continue}if("--raw"===a){t.snapshotRaw=!0;continue}if("--no-record"===a){t.noRecord=!0;continue}if("--save-script"===a){t.saveScript=!0;continue}if("--update"===a||"-u"===a){t.replayUpdate=!0;continue}if("--user-installed"===a){t.appsFilter="user-installed";continue}if("--all"===a){t.appsFilter="all";continue}if("--metadata"===a){t.appsMetadata=!0;continue}if(a.startsWith("--backend")){let r=a.includes("=")?a.split("=")[1]:e[n+1];if(a.includes("=")||(n+=1),"ax"!==r&&"xctest"!==r)throw new l("INVALID_ARGS",`Invalid backend: ${r}`);t.snapshotBackend=r;continue}if(a.startsWith("--")){let[r,i]=a.split("="),s=i??e[n+1];switch(!i&&(n+=1),r){case"--platform":if("ios"!==s&&"android"!==s)throw new l("INVALID_ARGS",`Invalid platform: ${s}`);t.platform=s;break;case"--depth":{let e=Number(s);if(!Number.isFinite(e)||e<0)throw new l("INVALID_ARGS",`Invalid depth: ${s}`);t.snapshotDepth=Math.floor(e);break}case"--scope":t.snapshotScope=s;break;case"--device":t.device=s;break;case"--udid":t.udid=s;break;case"--serial":t.serial=s;break;case"--out":t.out=s;break;case"--session":t.session=s;break;case"--activity":t.activity=s;break;default:throw new l("INVALID_ARGS",`Unknown flag: ${r}`)}continue}if("-d"===a){let r=e[n+1];n+=1;let a=Number(r);if(!Number.isFinite(a)||a<0)throw new l("INVALID_ARGS",`Invalid depth: ${r}`);t.snapshotDepth=Math.floor(a);continue}if("-s"===a){let r=e[n+1];n+=1,t.snapshotScope=r;continue}r.push(a)}return{command:r.shift()??null,positionals:r,flags:t}}(t);(n.flags.help||!n.command)&&(process.stdout.write(`agent-device <command> [args] [--json]
4
+ `)}function p(e,t,r){let i=f(e.type??"Element"),n=function(e,t){var r,i;let n=e.label?.trim(),s=e.value?.trim();if("text-field"===(r=t)||"text-view"===r||"search"===r){if(s)return s;if(n)return n}else if(n)return n;if(s)return s;let a=e.identifier?.trim();return!a||(i=a,/^[\w.]+:id\/[\w.-]+$/i.test(i)&&("group"===t||"image"===t||"list"===t||"collection"===t))?"":a}(e,i),s=" ".repeat(t),a=e.ref?`@${e.ref}`:"",o=[!1===e.enabled?"disabled":null].filter(Boolean).join(", "),l=o?` [${o}]`:"",c=n?` "${n}"`:"";return r?`${s}${a} [${i}]${l}`.trimEnd():`${s}${a} [${i}]${c}${l}`.trimEnd()}function f(e){let t=e.replace(/XCUIElementType/gi,"").toLowerCase(),r=e.includes(".")&&(e.startsWith("android.")||e.startsWith("androidx.")||e.startsWith("com."));switch(t.startsWith("ax")&&(t=t.replace(/^ax/,"")),t.includes(".")&&(t=t.replace(/^android\.widget\./,"").replace(/^android\.view\./,"").replace(/^android\.webkit\./,"").replace(/^androidx\./,"").replace(/^com\.google\.android\./,"").replace(/^com\.android\./,"")),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 r?"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"}}let m=e.join(s.homedir(),".agent-device"),h=e.join(m,"daemon.json"),w=function(){let e=process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS;if(!e)return 6e4;let t=Number(e);return Number.isFinite(t)?Math.max(1e3,Math.floor(t)):6e4}();async function y(e){let t=await v(),r={...e,token:t.token};return await $(t,r)}async function v(){let e=g(),t=l();if(e&&e.version===t&&await b(e))return e;e&&(e.version!==t||!await b(e))&&n.existsSync(h)&&n.unlinkSync(h),await x();let r=Date.now();for(;Date.now()-r<5e3;){let e=g();if(e&&await b(e))return e;await new Promise(e=>setTimeout(e,100))}throw new o("COMMAND_FAILED","Failed to start daemon",{infoPath:h,hint:"Run pnpm build, or delete ~/.agent-device/daemon.json if stale."})}function g(){if(!n.existsSync(h))return null;try{let e=JSON.parse(n.readFileSync(h,"utf8"));if(!e.port||!e.token)return null;return e}catch{return null}}async function b(e){return new Promise(t=>{let r=a.createConnection({host:"127.0.0.1",port:e.port},()=>{r.destroy(),t(!0)});r.on("error",()=>{t(!1)})})}async function x(){let t=c(),r=e.join(t,"dist","src","daemon.js"),s=e.join(t,"src","daemon.ts"),a=n.existsSync(r);if(!a&&!n.existsSync(s))throw new o("COMMAND_FAILED","Daemon entry not found",{distPath:r,srcPath:s});let l=a?[r]:["--experimental-strip-types",s];i(process.execPath,l)}async function $(e,t){return new Promise((r,i)=>{let n=a.createConnection({host:"127.0.0.1",port:e.port},()=>{n.write(`${JSON.stringify(t)}
5
+ `)}),s=setTimeout(()=>{n.destroy(),i(new o("COMMAND_FAILED","Daemon request timed out",{timeoutMs:w}))},w),l="";n.setEncoding("utf8"),n.on("data",e=>{let t=(l+=e).indexOf("\n");if(-1===t)return;let a=l.slice(0,t).trim();if(a)try{let e=JSON.parse(a);n.end(),clearTimeout(s),r(e)}catch(e){clearTimeout(s),i(e)}}),n.on("error",e=>{clearTimeout(s),i(e)})})}async function S(r){let i=function(e){let t={json:!1,help:!1,version:!1},r=[];for(let i=0;i<e.length;i+=1){let n=e[i];if("--json"===n){t.json=!0;continue}if("--help"===n||"-h"===n){t.help=!0;continue}if("--version"===n||"-V"===n){t.version=!0;continue}if("--verbose"===n||"-v"===n){t.verbose=!0;continue}if("-i"===n){t.snapshotInteractiveOnly=!0;continue}if("-c"===n){t.snapshotCompact=!0;continue}if("--raw"===n){t.snapshotRaw=!0;continue}if("--no-record"===n){t.noRecord=!0;continue}if("--save-script"===n){t.saveScript=!0;continue}if("--update"===n||"-u"===n){t.replayUpdate=!0;continue}if("--user-installed"===n){t.appsFilter="user-installed";continue}if("--all"===n){t.appsFilter="all";continue}if("--metadata"===n){t.appsMetadata=!0;continue}if(n.startsWith("--backend")){let r=n.includes("=")?n.split("=")[1]:e[i+1];if(n.includes("=")||(i+=1),"ax"!==r&&"xctest"!==r)throw new o("INVALID_ARGS",`Invalid backend: ${r}`);t.snapshotBackend=r;continue}if(n.startsWith("--")){let[r,s]=n.split("="),a=s??e[i+1];switch(!s&&(i+=1),r){case"--platform":if("ios"!==a&&"android"!==a)throw new o("INVALID_ARGS",`Invalid platform: ${a}`);t.platform=a;break;case"--depth":{let e=Number(a);if(!Number.isFinite(e)||e<0)throw new o("INVALID_ARGS",`Invalid depth: ${a}`);t.snapshotDepth=Math.floor(e);break}case"--scope":t.snapshotScope=a;break;case"--device":t.device=a;break;case"--udid":t.udid=a;break;case"--serial":t.serial=a;break;case"--out":t.out=a;break;case"--session":t.session=a;break;case"--activity":t.activity=a;break;default:throw new o("INVALID_ARGS",`Unknown flag: ${r}`)}continue}if("-d"===n){let r=e[i+1];i+=1;let n=Number(r);if(!Number.isFinite(n)||n<0)throw new o("INVALID_ARGS",`Invalid depth: ${r}`);t.snapshotDepth=Math.floor(n);continue}if("-s"===n){let r=e[i+1];i+=1,t.snapshotScope=r;continue}r.push(n)}return{command:r.shift()??null,positionals:r,flags:t}}(r);i.flags.version&&(process.stdout.write(`${l()}
6
+ `),process.exit(0)),(i.flags.help||!i.command)&&(process.stdout.write(`agent-device <command> [args] [--json]
6
7
 
7
8
  CLI to control iOS and Android devices for AI agents.
8
9
 
@@ -68,31 +69,32 @@ Flags:
68
69
  --update, -u Replay: update selectors and rewrite replay file in place
69
70
  --user-installed Apps: list user-installed packages (Android only)
70
71
  --all Apps: list all packages (Android only)
72
+ --version, -V Print version and exit
71
73
 
72
- `),process.exit(+!n.flags.help));let{command:a,positionals:o,flags:f}=n,m=f.session??process.env.AGENT_DEVICE_SESSION??"default",h=f.verbose&&!f.json?function(){try{let t=e.join(s.homedir(),".agent-device","daemon.log"),r=0,n=!1,a=setInterval(()=>{if(n||!i.existsSync(t))return;let e=i.statSync(t);if(e.size<=r)return;let a=i.openSync(t,"r"),s=Buffer.alloc(e.size-r);i.readSync(a,s,0,s.length,r),i.closeSync(a),r=e.size,s.length>0&&process.stdout.write(s.toString("utf8"))},200);return()=>{n=!0,clearInterval(a)}}catch{return null}}():null;try{if("session"===a){let e=o[0]??"list";if("list"!==e)throw new l("INVALID_ARGS","session only supports list");let t=await w({session:m,command:"session_list",positionals:[],flags:{}});if(!t.ok)throw new l(t.error.code,t.error.message);f.json?c({success:!0,data:t.data??{}}):process.stdout.write(`${JSON.stringify(t.data??{},null,2)}
73
- `),h&&h();return}let e=await w({session:m,command:a,positionals:o,flags:f});if(e.ok){if(f.json){c({success:!0,data:e.data??{}}),h&&h();return}if("snapshot"===a){process.stdout.write(function(e,t={}){let r=e.nodes,n=Array.isArray(r)?r:[],a=!!e.truncated,i="string"==typeof e.appName?e.appName:void 0,s="string"==typeof e.appBundleId?e.appBundleId:void 0,o=[];i&&o.push(`Page: ${i}`),s&&o.push(`App: ${s}`);let l=`Snapshot: ${n.length} nodes${a?" (truncated)":""}`,c=o.length>0?`${o.join("\n")}
74
- `:"";if(0===n.length)return`${c}${l}
75
- `;if(t.raw){let e=n.map(e=>JSON.stringify(e));return`${c}${l}
74
+ `),process.exit(+!i.flags.help));let{command:a,positionals:c,flags:m}=i,h=m.session??process.env.AGENT_DEVICE_SESSION??"default",w=m.verbose&&!m.json?function(){try{let t=e.join(s.homedir(),".agent-device","daemon.log"),r=0,i=!1,a=setInterval(()=>{if(i||!n.existsSync(t))return;let e=n.statSync(t);if(e.size<=r)return;let s=n.openSync(t,"r"),a=Buffer.alloc(e.size-r);n.readSync(s,a,0,a.length,r),n.closeSync(s),r=e.size,a.length>0&&process.stdout.write(a.toString("utf8"))},200);return()=>{i=!0,clearInterval(a)}}catch{return null}}():null;try{if("session"===a){let e=c[0]??"list";if("list"!==e)throw new o("INVALID_ARGS","session only supports list");let t=await y({session:h,command:"session_list",positionals:[],flags:{}});if(!t.ok)throw new o(t.error.code,t.error.message);m.json?d({success:!0,data:t.data??{}}):process.stdout.write(`${JSON.stringify(t.data??{},null,2)}
75
+ `),w&&w();return}let e=await y({session:h,command:a,positionals:c,flags:m});if(e.ok){if(m.json){d({success:!0,data:e.data??{}}),w&&w();return}if("snapshot"===a){process.stdout.write(function(e,t={}){let r=e.nodes,i=Array.isArray(r)?r:[],n=!!e.truncated,s="string"==typeof e.appName?e.appName:void 0,a="string"==typeof e.appBundleId?e.appBundleId:void 0,o=[];s&&o.push(`Page: ${s}`),a&&o.push(`App: ${a}`);let l=`Snapshot: ${i.length} nodes${n?" (truncated)":""}`,c=o.length>0?`${o.join("\n")}
76
+ `:"";if(0===i.length)return`${c}${l}
77
+ `;if(t.raw){let e=i.map(e=>JSON.stringify(e));return`${c}${l}
76
78
  ${e.join("\n")}
77
- `}if(t.flatten){let e=n.map(e=>u(e,0,!1));return`${c}${l}
79
+ `}if(t.flatten){let e=i.map(e=>p(e,0,!1));return`${c}${l}
78
80
  ${e.join("\n")}
79
- `}let d=[],f=[];for(let e of n){let t=e.depth??0;for(;d.length>0&&t<=d[d.length-1];)d.pop();let r=e.label?.trim()||e.value?.trim()||e.identifier?.trim()||"",n="group"===p(e.type??"Element")&&!r;n&&d.push(t);let a=n?t:Math.max(0,t-d.length);f.push(u(e,a,n))}return`${c}${l}
80
- ${f.join("\n")}
81
- `}(e.data??{},{raw:f.snapshotRaw,flatten:f.snapshotInteractiveOnly})),h&&h();return}if("get"===a){let t=o[0];if("text"===t){let t=e.data?.text??"";process.stdout.write(`${t}
82
- `),h&&h();return}if("attrs"===t){let t=e.data?.node??{};process.stdout.write(`${JSON.stringify(t,null,2)}
83
- `),h&&h();return}}if("find"===a){let t=e.data;if("string"==typeof t?.text){process.stdout.write(`${t.text}
84
- `),h&&h();return}if("boolean"==typeof t?.found){process.stdout.write(`Found: ${t.found}
85
- `),h&&h();return}if(t?.node){process.stdout.write(`${JSON.stringify(t.node,null,2)}
86
- `),h&&h();return}}if("is"===a){let t=e.data?.predicate??"assertion";process.stdout.write(`Passed: is ${t}
87
- `),h&&h();return}if("click"===a){let t=e.data?.ref??"",r=e.data?.x,n=e.data?.y;t&&"number"==typeof r&&"number"==typeof n&&process.stdout.write(`Clicked @${t} (${r}, ${n})
88
- `),h&&h();return}if(e.data&&"object"==typeof e.data){let t=e.data;if("devices"===a){let e=(Array.isArray(t.devices)?t.devices:[]).map(e=>{let t=e?.name??e?.id??"unknown",r=e?.platform??"unknown",n=e?.kind?` ${e.kind}`:"",a="boolean"==typeof e?.booted?` booted=${e.booted}`:"";return`${t} (${r}${n})${a}`});process.stdout.write(`${e.join("\n")}
89
- `),h&&h();return}if("apps"===a){let e=(Array.isArray(t.apps)?t.apps:[]).map(e=>{if("string"==typeof e)return e;if(e&&"object"==typeof e){let t=e.bundleId??e.package,r=e.name??e.label;return r&&t?`${r} (${t})`:t&&"boolean"==typeof e.launchable?`${t} (launchable=${e.launchable})`:t?String(t):JSON.stringify(e)}return String(e)});process.stdout.write(`${e.join("\n")}
90
- `),h&&h();return}if("appstate"===a){let e=t?.platform,r=t?.appBundleId,n=t?.appName,a=t?.source,i=t?.package,s=t?.activity;if("ios"===e){process.stdout.write(`Foreground app: ${n??r}
81
+ `}let d=[],u=[];for(let e of i){let t=e.depth??0;for(;d.length>0&&t<=d[d.length-1];)d.pop();let r=e.label?.trim()||e.value?.trim()||e.identifier?.trim()||"",i="group"===f(e.type??"Element")&&!r;i&&d.push(t);let n=i?t:Math.max(0,t-d.length);u.push(p(e,n,i))}return`${c}${l}
82
+ ${u.join("\n")}
83
+ `}(e.data??{},{raw:m.snapshotRaw,flatten:m.snapshotInteractiveOnly})),w&&w();return}if("get"===a){let t=c[0];if("text"===t){let t=e.data?.text??"";process.stdout.write(`${t}
84
+ `),w&&w();return}if("attrs"===t){let t=e.data?.node??{};process.stdout.write(`${JSON.stringify(t,null,2)}
85
+ `),w&&w();return}}if("find"===a){let t=e.data;if("string"==typeof t?.text){process.stdout.write(`${t.text}
86
+ `),w&&w();return}if("boolean"==typeof t?.found){process.stdout.write(`Found: ${t.found}
87
+ `),w&&w();return}if(t?.node){process.stdout.write(`${JSON.stringify(t.node,null,2)}
88
+ `),w&&w();return}}if("is"===a){let t=e.data?.predicate??"assertion";process.stdout.write(`Passed: is ${t}
89
+ `),w&&w();return}if("click"===a){let t=e.data?.ref??"",r=e.data?.x,i=e.data?.y;t&&"number"==typeof r&&"number"==typeof i&&process.stdout.write(`Clicked @${t} (${r}, ${i})
90
+ `),w&&w();return}if(e.data&&"object"==typeof e.data){let t=e.data;if("devices"===a){let e=(Array.isArray(t.devices)?t.devices:[]).map(e=>{let t=e?.name??e?.id??"unknown",r=e?.platform??"unknown",i=e?.kind?` ${e.kind}`:"",n="boolean"==typeof e?.booted?` booted=${e.booted}`:"";return`${t} (${r}${i})${n}`});process.stdout.write(`${e.join("\n")}
91
+ `),w&&w();return}if("apps"===a){let e=(Array.isArray(t.apps)?t.apps:[]).map(e=>{if("string"==typeof e)return e;if(e&&"object"==typeof e){let t=e.bundleId??e.package,r=e.name??e.label;return r&&t?`${r} (${t})`:t&&"boolean"==typeof e.launchable?`${t} (launchable=${e.launchable})`:t?String(t):JSON.stringify(e)}return String(e)});process.stdout.write(`${e.join("\n")}
92
+ `),w&&w();return}if("appstate"===a){let e=t?.platform,r=t?.appBundleId,i=t?.appName,n=t?.source,s=t?.package,a=t?.activity;if("ios"===e){process.stdout.write(`Foreground app: ${i??r}
91
93
  `),r&&process.stdout.write(`Bundle: ${r}
92
- `),a&&process.stdout.write(`Source: ${a}
93
- `),h&&h();return}if("android"===e){process.stdout.write(`Foreground app: ${i??"unknown"}
94
- `),s&&process.stdout.write(`Activity: ${s}
95
- `),h&&h();return}}}h&&h();return}throw new l(e.error.code,e.error.message,e.error.details)}catch(t){let e=r(t);if(f.json)c({success:!1,error:{code:e.code,message:e.message,details:e.details}});else if(d(e),f.verbose)try{let e=await import("node:fs"),t=await import("node:os"),r=(await import("node:path")).join(t.homedir(),".agent-device","daemon.log");if(e.existsSync(r)){let t=e.readFileSync(r,"utf8").split("\n"),n=t.slice(Math.max(0,t.length-200)).join("\n");n.trim().length>0&&process.stderr.write(`
94
+ `),n&&process.stdout.write(`Source: ${n}
95
+ `),w&&w();return}if("android"===e){process.stdout.write(`Foreground app: ${s??"unknown"}
96
+ `),a&&process.stdout.write(`Activity: ${a}
97
+ `),w&&w();return}}}w&&w();return}throw new o(e.error.code,e.error.message,e.error.details)}catch(r){let e=t(r);if(m.json)d({success:!1,error:{code:e.code,message:e.message,details:e.details}});else if(u(e),m.verbose)try{let e=await import("node:fs"),t=await import("node:os"),r=(await import("node:path")).join(t.homedir(),".agent-device","daemon.log");if(e.existsSync(r)){let t=e.readFileSync(r,"utf8").split("\n"),i=t.slice(Math.max(0,t.length-200)).join("\n");i.trim().length>0&&process.stderr.write(`
96
98
  [daemon log]
97
- ${n}
98
- `)}}catch{}h&&h(),process.exit(1)}}n(process.argv[1]??"").href===import.meta.url&&S(process.argv.slice(2)).catch(e=>{d(r(e)),process.exit(1)}),S(process.argv.slice(2));
99
+ ${i}
100
+ `)}}catch{}w&&w(),process.exit(1)}}r(process.argv[1]??"").href===import.meta.url&&S(process.argv.slice(2)).catch(e=>{u(t(e)),process.exit(1)}),S(process.argv.slice(2));