agent-device 0.16.13 → 0.16.14

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 (21) hide show
  1. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.13.apk → agent-device-android-multitouch-helper-0.16.14.apk} +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.16.14.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.16.13.manifest.json → agent-device-android-multitouch-helper-0.16.14.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.16.13.apk → agent-device-android-snapshot-helper-0.16.14.apk} +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.14.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.16.13.manifest.json → agent-device-android-snapshot-helper-0.16.14.manifest.json} +6 -6
  7. package/dist/src/1352.js +1 -1
  8. package/dist/src/2415.js +25 -25
  9. package/dist/src/5792.js +1 -1
  10. package/dist/src/args.js +10 -9
  11. package/dist/src/find.js +1 -1
  12. package/dist/src/interaction.js +1 -1
  13. package/dist/src/lease.js +1 -1
  14. package/dist/src/react-native.js +1 -1
  15. package/dist/src/record-trace.js +3 -3
  16. package/dist/src/session.js +11 -11
  17. package/dist/src/snapshot.js +2 -2
  18. package/package.json +1 -1
  19. package/server.json +2 -2
  20. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.16.13.apk.sha256 +0 -1
  21. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.16.13.apk.sha256 +0 -1
package/dist/src/5792.js CHANGED
@@ -1 +1 @@
1
- let e={alert:"alert",appState:"appstate",appSwitcher:"app-switcher",apps:"apps",back:"back",batch:"batch",boot:"boot",click:"click",close:"close",clipboard:"clipboard",devices:"devices",diff:"diff",fill:"fill",find:"find",focus:"focus",gesture:"gesture",get:"get",home:"home",install:"install",installFromSource:"install-from-source",is:"is",keyboard:"keyboard",logs:"logs",longPress:"longpress",network:"network",open:"open",perf:"perf",prepare:"prepare",press:"press",push:"push",record:"record",reactNative:"react-native",reinstall:"reinstall",replay:"replay",rotate:"rotate",scroll:"scroll",screenshot:"screenshot",settings:"settings",snapshot:"snapshot",swipe:"swipe",test:"test",trace:"trace",triggerAppEvent:"trigger-app-event",type:"type",wait:"wait"},t={installSource:"install_source",leaseAllocate:"lease_allocate",leaseHeartbeat:"lease_heartbeat",leaseRelease:"lease_release",releaseMaterializedPaths:"release_materialized_paths",runtime:"runtime",sessionList:"session_list"},s={auth:"auth",connect:"connect",connection:"connection",disconnect:"disconnect",mcp:"mcp",metro:"metro",reactDevtools:"react-devtools",session:"session"},a="gesture requires one of: pan, fling, swipe, pinch, rotate, transform",r=[e.devices,e.boot,e.apps,e.open,e.close,e.install,e.reinstall,e.installFromSource,e.push,e.triggerAppEvent,e.snapshot,e.screenshot,e.diff,e.wait,e.alert,e.settings,e.click,e.press,e.longPress,e.swipe,e.focus,e.type,e.fill,e.scroll,e.get,e.gesture,e.is,e.find,e.perf,e.logs,e.network,e.record,e.trace,e.test,e.appState,e.back,e.home,e.rotate,e.appSwitcher,e.keyboard,e.clipboard,e.reactNative],o=l(s.auth,s.connect,s.connection,s.disconnect,s.mcp,s.reactDevtools,e.prepare);l(s.auth,s.connect,s.connection,s.disconnect,s.mcp,s.metro,s.reactDevtools,s.session,e.appState,e.prepare,e.batch,e.devices,e.gesture,e.replay,e.test,e.trace);let i={inventory:l(t.sessionList,e.devices,e.apps),state:l(e.boot,e.appState),observability:l(e.perf,e.logs,e.network),replay:l(e.replay,e.test),snapshot:l(e.snapshot,e.diff,e.wait,e.alert,e.settings),replayScopedAction:l(e.alert,e.back,e.click,e.clipboard,e.diff,e.fill,e.find,e.gesture,e.get,e.home,e.is,e.keyboard,e.longPress,"pinch",e.press,e.record,e.reactNative,e.rotate,e.screenshot,e.scroll,e.settings,e.snapshot,e.swipe,e.type,e.wait),androidBlockingDialogGuardedAction:l(e.back,e.click,e.fill,e.focus,e.gesture,e.home,e.keyboard,e.longPress,"fling","pan","pinch",e.press,e.rotate,"rotate-gesture",e.scroll,e.swipe,"transform-gesture",e.type),selectorValidationExempt:l(t.sessionList,e.devices,t.releaseMaterializedPaths),leaseAdmissionExempt:l(t.sessionList,e.devices,t.releaseMaterializedPaths,t.leaseAllocate,t.leaseHeartbeat,t.leaseRelease),leaseHandler:l(t.leaseAllocate,t.leaseHeartbeat,t.leaseRelease),sessionHandler:l(t.installSource,t.releaseMaterializedPaths,t.sessionList,e.appState,e.apps,e.batch,e.boot,e.clipboard,e.close,e.devices,e.install,e.keyboard,e.logs,e.network,e.open,e.perf,e.prepare,e.push,e.reinstall,e.replay,e.test,e.triggerAppEvent,t.runtime),reactNativeHandler:l(e.reactNative),recordTraceHandler:l(e.record,e.trace),findHandler:l(e.find),interactionHandler:l(e.click,e.fill,e.get,e.is,e.longPress,e.press,e.type)};function l(...e){return new Set(e)}function n(){return[...Object.values(e),...Object.values(s)].sort()}function c(t){return Object.values(e).includes(t)||t===s.metro||t===s.session}function p(){return n().filter(e=>!o.has(e))}export{r as BATCH_COMMAND_NAMES,i as DAEMON_COMMAND_GROUPS,a as GESTURE_SUBCOMMAND_ERROR,t as INTERNAL_COMMANDS,e as PUBLIC_COMMANDS,c as isClientBackedCliCommandName,n as listCliCommandNames,p as listMcpExposedCommandNames};
1
+ let e={alert:"alert",appState:"appstate",appSwitcher:"app-switcher",apps:"apps",back:"back",batch:"batch",boot:"boot",click:"click",close:"close",clipboard:"clipboard",devices:"devices",diff:"diff",fill:"fill",find:"find",focus:"focus",gesture:"gesture",get:"get",home:"home",install:"install",installFromSource:"install-from-source",is:"is",keyboard:"keyboard",logs:"logs",longPress:"longpress",network:"network",open:"open",perf:"perf",prepare:"prepare",press:"press",push:"push",record:"record",reactNative:"react-native",reinstall:"reinstall",replay:"replay",rotate:"rotate",scroll:"scroll",screenshot:"screenshot",settings:"settings",snapshot:"snapshot",swipe:"swipe",test:"test",trace:"trace",triggerAppEvent:"trigger-app-event",type:"type",wait:"wait"},t={installSource:"install_source",leaseAllocate:"lease_allocate",leaseHeartbeat:"lease_heartbeat",leaseRelease:"lease_release",releaseMaterializedPaths:"release_materialized_paths",runtime:"runtime",sessionList:"session_list"},s={auth:"auth",connect:"connect",connection:"connection",disconnect:"disconnect",mcp:"mcp",metro:"metro",reactDevtools:"react-devtools",session:"session"},a="gesture requires one of: pan, fling, swipe, pinch, rotate, transform",r=[e.devices,e.boot,e.apps,e.open,e.close,e.install,e.reinstall,e.installFromSource,e.push,e.triggerAppEvent,e.snapshot,e.screenshot,e.diff,e.wait,e.alert,e.settings,e.click,e.press,e.longPress,e.swipe,e.focus,e.type,e.fill,e.scroll,e.get,e.gesture,e.is,e.find,e.perf,e.logs,e.network,e.record,e.trace,e.test,e.appState,e.back,e.home,e.rotate,e.appSwitcher,e.keyboard,e.clipboard,e.reactNative],o=n(s.auth,s.connect,s.connection,s.disconnect,s.mcp,s.reactDevtools,e.prepare);function n(...e){return new Set(e)}function c(){return[...Object.values(e),...Object.values(s)].sort()}function i(t){return Object.values(e).includes(t)||t===s.metro||t===s.session}function l(){return c().filter(e=>!o.has(e))}n(s.auth,s.connect,s.connection,s.disconnect,s.mcp,s.metro,s.reactDevtools,s.session,e.appState,e.prepare,e.batch,e.devices,e.gesture,e.replay,e.test,e.trace);export{r as BATCH_COMMAND_NAMES,a as GESTURE_SUBCOMMAND_ERROR,t as INTERNAL_COMMANDS,e as PUBLIC_COMMANDS,i as isClientBackedCliCommandName,c as listCliCommandNames,l as listMcpExposedCommandNames};
package/dist/src/args.js CHANGED
@@ -1,4 +1,4 @@
1
- import{listCliCommandNames as e}from"./5792.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a,GLOBAL_FLAG_KEYS as s,getFlagDefinition as n,getFlagDefinitions as r}from"./1352.js";import{parseSourceValue as i,buildPrimaryEnvVarName as l}from"./1010.js";import{AppError as d}from"./9152.js";function c(e,t){for(let[o,a]of Object.entries(t))void 0!==a&&(e[o]=a);return e}let p=[{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 physical-device",description:"Connected phone/tablet setup and iOS signing prerequisites"},{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"}],u=["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: direct Android localhost URL opens with a port auto-configure host reachability.",'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.","Implicit default sessions are scoped to the current worktree; use --session only when intentionally sharing a named session.","Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.","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" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.',"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."],f=["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."],h=[{label:"AGENT_DEVICE_SESSION",description:"Explicit 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"}],g=["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"],m={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
1
+ import{listCliCommandNames as e}from"./5792.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a,GLOBAL_FLAG_KEYS as s,getFlagDefinition as n,getFlagDefinitions as r}from"./1352.js";import{parseSourceValue as i,buildPrimaryEnvVarName as l}from"./1010.js";import{AppError as c}from"./9152.js";function d(e,t){for(let[o,a]of Object.entries(t))void 0!==a&&(e[o]=a);return e}let p=[{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 physical-device",description:"Connected phone/tablet setup and iOS signing prerequisites"},{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"}],u=["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: direct Android localhost URL opens with a port auto-configure host reachability.",'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.","Implicit default sessions are scoped to the current worktree; use --session only when intentionally sharing a named session.","Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.","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" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.',"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."],f=["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."],h=[{label:"AGENT_DEVICE_SESSION",description:"Explicit 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"}],g=["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"],m={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
 
@@ -27,7 +27,8 @@ Bootstrap:
27
27
  agent-device prepare ios-runner --platform ios --timeout 240000
28
28
  If app id is unknown, plan devices, apps, then open <discovered-app-id>. Discovery is not enough when the task asks to open/start the app.
29
29
  Install arguments are app/package id then artifact path. If the task says install, use install; use reinstall only when explicitly requested. Fresh runtime state is open --relaunch after install.
30
- In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner and proves it can answer a lightweight command before the first snapshot pays that setup cost.
30
+ In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner, health-checks it with a lightweight command, and retries one stuck/non-connecting runner launch before the first snapshot pays that setup cost.
31
+ CI may cache ~/.agent-device/ios-runner/derived with an exact key that includes the agent-device package and Xcode version. Avoid broad restore-key fallbacks; prepare ios-runner already recovers bad restored runner artifacts and one retryable non-connecting runner launch.
31
32
  Do not open artifact paths or invent package ids. If apps lookup misses the target and no URL/artifact is provided, ask or stop.
32
33
 
33
34
  Snapshots and refs:
@@ -445,10 +446,10 @@ Rules:
445
446
  Never delete screenshots, videos, traces, or report artifacts during a session.
446
447
  Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function v(e){let t=e.endsWith("?"),o=t?e.slice(0,-1):e;return t?`[${o}]`:`<${o}>`}function w(e){return r().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function b(e,t){return y(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function y(e,t){if(0===t.length)return`${e}
447
448
  (none)`;let o=Math.max(...t.map(e=>e.label.length))+2,a=[e];for(let e of t)a.push(` ${e.label.padEnd(o)}${e.description}`);return a.join("\n")}function k(e,t){return 0===t.length?`${e}
448
- (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),I=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),A=function(){let o=new Map;for(let e of r()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of s)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:I.has(e)?[]:[l(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(A.map(e=>[e.key,e]));function S(e){return R.get(e)}function N(e){return A.filter(t=>t.config.enabled&&t.supportsCommand(e))}function U(e,t){return S(e)?.supportsCommand(t)??!1}function E(e,t,o,a){return i(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function D(e){let t={json:!1,help:!1,version:!1},a=null,s=[],r=[],i=!0;for(let p=0;p<e.length;p+=1){var l,c;let u=e[p];if(i&&"--"===u){i=!1;continue}if(!i){a?s.push(u):a=M(u);continue}let f=u.startsWith("--"),h=u.startsWith("-")&&u.length>1;if(!f&&!h){a?s.push(u):a=M(u);continue}let[g,m]=f?O(u):[u,void 0],v=n(g);if(l=a,c=v,"react-devtools"===l&&(!c||!U(c.key,l))){s.push(u);continue}if(!v){if(function(e,t,a){var s;if(s=a,!/^-\d+(\.\d+)?$/.test(s)||!e)return!1;let n=o(e);if(!n||n.allowsExtraPositionals)return!0;let r=n.positionalArgs??[];return 0!==r.length&&(t.length<r.length||r.some(e=>e.includes("?")))}(a,s,u)){a?s.push(u):a=u;continue}throw new d("INVALID_ARGS",`Unknown flag: ${g}`)}let w=function(e,t,o,a){if(void 0!==e.setValue){if(void 0!==o)throw new d("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==o)throw new d("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==o){if(0===o.trim().length)throw new d("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:o,consumeNext:!1}}return void 0===a||L(a)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let s=o??a;if(void 0===s||void 0===o&&L(s))throw new d("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:s,consumeNext:void 0===o};if("enum"===e.type){if(!e.enumValues?.includes(s))throw new d("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:s,consumeNext:void 0===o}}let n=Number(s);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new d("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:Math.floor(n),consumeNext:void 0===o}}(v,g,m,e[p+1]);w.consumeNext&&(p+=1);let b=t[v.key];if(v.multiple){let e=Array.isArray(b)?[...b,w.value]:void 0===b?[w.value]:[b,w.value];t[v.key]=e}else t[v.key]=w.value;r.push({key:v.key,token:g})}return{command:a,positionals:s,flags:t,warnings:[],providedFlags:r}}function C(e,t){let o=t?.strictFlags??!0,s=[...e.warnings],n=c({json:!1,help:!1,version:!1},t?.defaultFlags??{});c(n,e.flags);let r=e.providedFlags.filter(t=>!U(t.key,e.command));if(r.length>0){var i,l;let t=r.map(e=>e.token),a=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(o)throw new d("INVALID_ARGS",a);for(let e of(s.push(a),r))delete n[e.key]}for(let t of Object.keys(n))void 0!==n[t]&&(U(t,e.command)||delete n[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new d("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),a(e.command,n),"batch"===e.command&&1!=+!!n.steps+ +!!n.stepsFile)throw new d("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...o}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:o,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:n,warnings:s})}function O(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function _(e){return e.replace(/^-+/,"")}function L(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?O(e):[e,void 0];return void 0!==n(t)}function T(){let o,a,n,r,i,l,d,c;return o=`agent-device <command> [args] [--json]
449
+ (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),I=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),A=function(){let o=new Map;for(let e of r()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of s)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:I.has(e)?[]:[l(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(A.map(e=>[e.key,e]));function S(e){return R.get(e)}function N(e){return A.filter(t=>t.config.enabled&&t.supportsCommand(e))}function U(e,t){return S(e)?.supportsCommand(t)??!1}function E(e,t,o,a){return i(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function D(e){let t={json:!1,help:!1,version:!1},a=null,s=[],r=[],i=!0;for(let p=0;p<e.length;p+=1){var l,d;let u=e[p];if(i&&"--"===u){i=!1;continue}if(!i){a?s.push(u):a=M(u);continue}let f=u.startsWith("--"),h=u.startsWith("-")&&u.length>1;if(!f&&!h){a?s.push(u):a=M(u);continue}let[g,m]=f?O(u):[u,void 0],v=n(g);if(l=a,d=v,"react-devtools"===l&&(!d||!U(d.key,l))){s.push(u);continue}if(!v){if(function(e,t,a){var s;if(s=a,!/^-\d+(\.\d+)?$/.test(s)||!e)return!1;let n=o(e);if(!n||n.allowsExtraPositionals)return!0;let r=n.positionalArgs??[];return 0!==r.length&&(t.length<r.length||r.some(e=>e.includes("?")))}(a,s,u)){a?s.push(u):a=u;continue}throw new c("INVALID_ARGS",`Unknown flag: ${g}`)}let w=function(e,t,o,a){if(void 0!==e.setValue){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==o){if(0===o.trim().length)throw new c("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:o,consumeNext:!1}}return void 0===a||L(a)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let s=o??a;if(void 0===s||void 0===o&&L(s))throw new c("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:s,consumeNext:void 0===o};if("enum"===e.type){if(!e.enumValues?.includes(s))throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:s,consumeNext:void 0===o}}let n=Number(s);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:Math.floor(n),consumeNext:void 0===o}}(v,g,m,e[p+1]);w.consumeNext&&(p+=1);let b=t[v.key];if(v.multiple){let e=Array.isArray(b)?[...b,w.value]:void 0===b?[w.value]:[b,w.value];t[v.key]=e}else t[v.key]=w.value;r.push({key:v.key,token:g})}return{command:a,positionals:s,flags:t,warnings:[],providedFlags:r}}function C(e,t){let o=t?.strictFlags??!0,s=[...e.warnings],n=d({json:!1,help:!1,version:!1},t?.defaultFlags??{});d(n,e.flags);let r=e.providedFlags.filter(t=>!U(t.key,e.command));if(r.length>0){var i,l;let t=r.map(e=>e.token),a=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(o)throw new c("INVALID_ARGS",a);for(let e of(s.push(a),r))delete n[e.key]}for(let t of Object.keys(n))void 0!==n[t]&&(U(t,e.command)||delete n[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new c("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),a(e.command,n),"batch"===e.command&&1!=+!!n.steps+ +!!n.stepsFile)throw new c("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...o}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:o,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:n,warnings:s})}function O(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function _(e){return e.replace(/^-+/,"")}function L(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?O(e):[e,void 0];return void 0!==n(t)}function T(){let o,a,n,r,i,l,c,d;return o=`agent-device <command> [args] [--json]
449
450
 
450
451
  CLI to control iOS and Android devices for AI agents.
451
- `,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,d;return a=e,s=t,i=(r=(n=o).endsWith("?"))?n.slice(0,-1):n,d=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${a} ${i}`),r?l?`[${i}]`:d?i:`[${i}]`:d?i:`<${i}>`});return[e,...o].join(" ")}(e,o)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),n=b("Flags:",w(s)),r=k("Agent Quickstart:",u),i=y("Agent Workflows:",p),l=k("Configuration:",f),d=y("Environment:",h),c=k("Examples:",g),`${o}
452
+ `,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,c;return a=e,s=t,i=(r=(n=o).endsWith("?"))?n.slice(0,-1):n,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${a} ${i}`),r?l?`[${i}]`:c?i:`[${i}]`:c?i:`<${i}>`});return[e,...o].join(" ")}(e,o)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),n=b("Flags:",w(s)),r=k("Agent Quickstart:",u),i=y("Agent Workflows:",p),l=k("Configuration:",f),c=y("Environment:",h),d=k("Examples:",g),`${o}
452
453
  ${a}
453
454
 
454
455
  ${n}
@@ -459,21 +460,21 @@ ${i}
459
460
 
460
461
  ${l}
461
462
 
462
- ${d}
463
-
464
463
  ${c}
464
+
465
+ ${d}
465
466
  `}function F(e){return function(e){var t,a;let n,i=(n=m[e])?`${n.body}
466
467
 
467
468
  Related:
468
469
  agent-device help command list and global flags
469
470
  agent-device help <command> command-specific flags
470
471
  agent-device help workflow normal app automation loop
471
- `:null;if(i)return i;let l=o(e);if(!l)return null;let d=(t=e,(a=l).usageOverride?a.usageOverride:[t,...(a.positionalArgs??[]).map(v),...(a.allowedFlags??[]).flatMap(e=>{var t;return(t=e,r().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),c=w(new Set(l.allowedFlags??[])),p=w(s),u=[];return c.length>0&&u.push(b("Command flags:",c)),u.push(b("Global flags:",p)),`agent-device ${d}
472
+ `:null;if(i)return i;let l=o(e);if(!l)return null;let c=(t=e,(a=l).usageOverride?a.usageOverride:[t,...(a.positionalArgs??[]).map(v),...(a.allowedFlags??[]).flatMap(e=>{var t;return(t=e,r().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=w(new Set(l.allowedFlags??[])),p=w(s),u=[];return d.length>0&&u.push(b("Command flags:",d)),u.push(b("Global flags:",p)),`agent-device ${c}
472
473
 
473
474
  ${l.helpDescription}
474
475
 
475
476
  Usage:
476
- agent-device ${d}
477
+ agent-device ${c}
477
478
 
478
479
  ${u.join("\n\n")}
479
- `}(M(e))}function M(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,C as finalizeParsedArgs,N as getConfigurableOptionSpecs,S as getOptionSpec,c as mergeDefinedFlags,E as parseOptionValueFromSource,D as parseRawArgs,F as usageForCommand};
480
+ `}(M(e))}function M(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,C as finalizeParsedArgs,N as getConfigurableOptionSpecs,S as getOptionSpec,d as mergeDefinedFlags,E as parseOptionValueFromSource,D as parseRawArgs,F as usageForCommand};
package/dist/src/find.js CHANGED
@@ -1 +1 @@
1
- import{context_contextFromFlags as t,setSessionSnapshot as e,captureSnapshot as r,dispatchCommand as n,errorResponse as o,ensureDeviceReady as a,getActiveAndroidSnapshotFreshness as i,resolveTargetDevice as s,stripInternalInteractionFlags as l}from"./2415.js";import{findBestMatchesByLocator as c,parseFindArgs as f}from"./7556.js";import{dispatchFindReadOnlyViaRuntime as u,readTextForNode as d}from"./selector-runtime.js";import{PUBLIC_COMMANDS as _}from"./5792.js";import{centerOfRect as p}from"./4057.js";import{resolveActionableTouchResolution as g,resolveActionableTouchNode as m}from"./9533.js";import{sleep as h}from"./4829.js";import{extractNodeText as A}from"./940.js";let w={[_.find]:!0};async function S(t){var n,d;let{req:_,sessionName:h,logPath:w,sessionStore:S,invoke:F}=t,E=_.command;if("find"!==E)return null;let P=_.positionals??[];if(0===P.length)return o("INVALID_ARGS","find requires a locator or text");let{locator:U,query:L,action:v,value:H,timeoutMs:O}=f(P);if(!L)return o("INVALID_ARGS","find requires a value");if(_.flags?.findFirst&&_.flags?.findLast)return o("INVALID_ARGS","find accepts only one of --first or --last");let b=await u({req:_,sessionName:h,logPath:w,sessionStore:S});if(b)return b;let $=S.get(h),q="exists"===(n=v)||"wait"===n||"get_text"===n||"get_attrs"===n;if(!$&&!q)return o("SESSION_NOT_FOUND","No active session. Run open first.");let G=$?.device??await s(_.flags??{});$||await a(G);let B="click"===(d=v)||"focus"===d||"fill"===d||"type"===d,V="role"===U||B?void 0:L,T=0,j=null,z=async()=>{let t=Date.now();if(j&&t-T<750&&!i($))return{nodes:j};let{snapshot:n}=await r({device:G,session:$,flags:{..._.flags,snapshotInteractiveOnly:B,snapshotCompact:B},outPath:_.flags?.out,logPath:w,snapshotScope:V}),o=n.nodes;return T=t,j=o,$&&(e($,n),S.set(h,$)),{nodes:o,truncated:n.truncated,backend:n.backend}},J={req:_,sessionName:h,logPath:w,sessionStore:S,invoke:F,session:$,device:G,command:E,locator:U,query:L,publicFlags:{...l(_.flags)??{}}};if("wait"===v)return N(J,z,U,L,O);let{nodes:Q}=await z(),W=function(t){let{nodes:e,locator:r,query:n,requiresRect:a,flags:i}=t,s=c(e,r,n,{requireRect:a});if(a&&(s.matches=function(t,e){var r,n;let o=e[0]?.rect;if(!o)return t;let a=t.filter(t=>{if(!t.rect)return!1;let e=p(t.rect);return e.x>=o.x&&e.x<=o.x+o.width&&e.y>=o.y&&e.y<=o.y+o.height});return r=a.length>0?a:t,n=e,r.length<2?r:r.map((t,e)=>{var r,o;let a;return{node:t,index:e,score:(r=t,"semantic-target"===(a=g(o=n,r)).reason&&a.node.rect||"same-rect-descendant"===a.reason&&a.node.rect?4:"hittable-ancestor"===a.reason&&a.node.rect&&!C(a.node,o[0])?2:r.hittable&&r.rect&&!C(r,o[0])?3:+!!r.rect)}}).sort((t,e)=>e.score!==t.score?e.score-t.score:y(t.node)-y(e.node)||t.index-e.index).map(t=>t.node)}(s.matches,e)),a&&s.matches.length>1)if(i?.findFirst)s.matches=[s.matches[0]];else{if(!i?.findLast){var l,f,u;let t;return{ok:!1,response:(l=s.matches,f=r,u=n,t=l.slice(0,8).map(t=>{let e=A(t)||t.label||t.identifier||t.type||"";return`@${t.ref}${e?`(${e})`:""}`}),o("AMBIGUOUS_MATCH",`find matched ${l.length} elements for ${f} "${u}". Use a more specific locator or selector.`,{locator:f,query:u,matches:l.length,candidates:t}))}}s.matches=[s.matches[s.matches.length-1]]}let d=s.matches[0]??null;return d?{ok:!0,node:d}:{ok:!1,response:o("COMMAND_FAILED","find did not match any element")}}({nodes:Q,locator:U,query:L,requiresRect:B,flags:_.flags});if(!W.ok)return W.response;let X=W.node,Y=B?m(Q,X):X,Z=`@${Y.ref}`,tt={node:X,resolvedNode:Y,ref:Z,nodes:Q,actionFlags:{..._.flags??{},noRecord:!0}},te={exists:()=>k(J),get_text:()=>x(J,tt),get_attrs:()=>I(J,tt),click:()=>M(J,tt),fill:()=>D(J,tt,H),focus:()=>R(J,tt),type:()=>K(J,tt,H)}[v];return te?te():null}function y(t){return t.rect?t.rect.width*t.rect.height:1/0}function C(t,e){if(!e?.rect||!t.rect)return!1;let r=t.type?.toLowerCase()??"";return(!!r.includes("application")||!!r.includes("window"))&&t.rect.x===e.rect.x&&t.rect.y===e.rect.y&&t.rect.width===e.rect.width&&t.rect.height===e.rect.height}async function N(t,e,r,n,a){let{req:i,sessionStore:s,session:l,command:f,publicFlags:u}=t,d=a??1e4,_=Date.now();for(;Date.now()-_<d;){let{nodes:t}=await e();if(c(t,r,n,{requireRect:!1}).matches[0])return l&&s.recordAction(l,{command:f,positionals:i.positionals??[],flags:u,result:{found:!0,waitedMs:Date.now()-_}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-_}};await h(300)}return o("COMMAND_FAILED","find wait timed out")}async function k(t){let{req:e,sessionStore:r,session:n,command:o,publicFlags:a}=t;return n&&r.recordAction(n,{command:o,positionals:e.positionals??[],flags:a,result:{found:!0}}),{ok:!0,data:{found:!0}}}async function x(e,r){let{req:n,sessionStore:o,session:a,command:i,device:s,logPath:l,publicFlags:c}=e,f=await d({device:s,node:r.node,flags:n.flags,appBundleId:a?.appBundleId,traceOutPath:a?.trace?.outPath,surface:a?.surface,contextFromFlags:(e,r,n)=>t(l,e,r,n)});return a&&o.recordAction(a,{command:i,positionals:n.positionals??[],flags:c,result:{ref:r.ref,action:"get text",text:f}}),{ok:!0,data:{ref:r.ref,text:f,node:r.node}}}async function I(t,e){let{req:r,sessionStore:n,session:o,command:a,publicFlags:i}=t;return o&&n.recordAction(o,{command:a,positionals:r.positionals??[],flags:i,result:{ref:e.ref,action:"get attrs"}}),{ok:!0,data:{ref:e.ref,node:e.node}}}async function M(t,e){let{req:r,sessionName:n,sessionStore:o,session:a,invoke:i,command:s,locator:l,query:c,publicFlags:f}=t,u=await i({token:r.token,session:n,command:"click",positionals:[e.ref],flags:e.actionFlags});if(!u.ok)return u;let d=e.resolvedNode.rect?p(e.resolvedNode.rect):e.node.rect?p(e.node.rect):null,_={ref:e.ref,locator:l,query:c};return d&&(_.x=d.x,_.y=d.y),a&&o.recordAction(a,{command:s,positionals:r.positionals??[],flags:f,result:{ref:e.ref,action:"click",locator:l,query:c}}),{ok:!0,data:_}}async function D(t,e,r){let{req:n,sessionName:a,sessionStore:i,session:s,invoke:l,command:c,publicFlags:f}=t;if(!r)return o("INVALID_ARGS","find fill requires text");let u=await l({token:n.token,session:a,command:"fill",positionals:[e.ref,r],flags:e.actionFlags});return u.ok&&s&&i.recordAction(s,{command:c,positionals:n.positionals??[],flags:f,result:{ref:e.ref,action:"fill"}}),u}async function R(t,e){let r=await F(t,e);return r.ok&&E(t,e,"focus"),r}async function K(e,r,a){let{req:i,device:s,logPath:l,session:c}=e;if(!a)return o("INVALID_ARGS","find type requires text");let f=await F(e,r);if(!f.ok)return f;let u=await n(s,"type",[a],i.flags?.out,{...t(l,i.flags,c?.appBundleId,c?.trace?.outPath)});return E(e,r,"type"),{ok:!0,data:u??{ref:r.ref}}}async function F(e,r){let{req:a,device:i,logPath:s,session:l}=e,c=r.node.rect?p(r.node.rect):null;return c?{ok:!0,data:await n(i,"focus",[String(c.x),String(c.y)],a.flags?.out,{...t(s,a.flags,l?.appBundleId,l?.trace?.outPath)})??{ref:r.ref}}:o("COMMAND_FAILED","matched element has no bounds")}function E(t,e,r){let{req:n,sessionStore:o,session:a,command:i,publicFlags:s}=t;a&&o.recordAction(a,{command:i,positionals:n.positionals??[],flags:s,result:{ref:e.ref,action:r}})}export{parseFindArgs}from"./7556.js";export{w as FIND_COMMAND_HANDLERS,S as handleFindCommands};
1
+ import{context_contextFromFlags as t,setSessionSnapshot as e,captureSnapshot as r,dispatchCommand as n,errorResponse as o,ensureDeviceReady as a,getActiveAndroidSnapshotFreshness as i,resolveTargetDevice as s,stripInternalInteractionFlags as l}from"./2415.js";import{findBestMatchesByLocator as c,parseFindArgs as f}from"./7556.js";import{dispatchFindReadOnlyViaRuntime as u,readTextForNode as d}from"./selector-runtime.js";import{centerOfRect as p}from"./4057.js";import{resolveActionableTouchResolution as _,resolveActionableTouchNode as g}from"./9533.js";import{sleep as m}from"./4829.js";import{extractNodeText as h}from"./940.js";async function A(t){var n,d;let{req:m,sessionName:A,logPath:R,sessionStore:K,invoke:F}=t,P=m.command;if("find"!==P)return null;let E=m.positionals??[];if(0===E.length)return o("INVALID_ARGS","find requires a locator or text");let{locator:U,query:v,action:L,value:H,timeoutMs:O}=f(E);if(!v)return o("INVALID_ARGS","find requires a value");if(m.flags?.findFirst&&m.flags?.findLast)return o("INVALID_ARGS","find accepts only one of --first or --last");let b=await u({req:m,sessionName:A,logPath:R,sessionStore:K});if(b)return b;let $=K.get(A),q="exists"===(n=L)||"wait"===n||"get_text"===n||"get_attrs"===n;if(!$&&!q)return o("SESSION_NOT_FOUND","No active session. Run open first.");let G=$?.device??await s(m.flags??{});$||await a(G);let B="click"===(d=L)||"focus"===d||"fill"===d||"type"===d,V="role"===U||B?void 0:v,T=0,j=null,z=async()=>{let t=Date.now();if(j&&t-T<750&&!i($))return{nodes:j};let{snapshot:n}=await r({device:G,session:$,flags:{...m.flags,snapshotInteractiveOnly:B,snapshotCompact:B},outPath:m.flags?.out,logPath:R,snapshotScope:V}),o=n.nodes;return T=t,j=o,$&&(e($,n),K.set(A,$)),{nodes:o,truncated:n.truncated,backend:n.backend}},J={req:m,sessionName:A,logPath:R,sessionStore:K,invoke:F,session:$,device:G,command:P,locator:U,query:v,publicFlags:{...l(m.flags)??{}}};if("wait"===L)return S(J,z,U,v,O);let{nodes:Q}=await z(),W=function(t){let{nodes:e,locator:r,query:n,requiresRect:a,flags:i}=t,s=c(e,r,n,{requireRect:a});if(a&&(s.matches=function(t,e){var r,n;let o=e[0]?.rect;if(!o)return t;let a=t.filter(t=>{if(!t.rect)return!1;let e=p(t.rect);return e.x>=o.x&&e.x<=o.x+o.width&&e.y>=o.y&&e.y<=o.y+o.height});return r=a.length>0?a:t,n=e,r.length<2?r:r.map((t,e)=>{var r,o;let a;return{node:t,index:e,score:(r=t,"semantic-target"===(a=_(o=n,r)).reason&&a.node.rect||"same-rect-descendant"===a.reason&&a.node.rect?4:"hittable-ancestor"===a.reason&&a.node.rect&&!y(a.node,o[0])?2:r.hittable&&r.rect&&!y(r,o[0])?3:+!!r.rect)}}).sort((t,e)=>e.score!==t.score?e.score-t.score:w(t.node)-w(e.node)||t.index-e.index).map(t=>t.node)}(s.matches,e)),a&&s.matches.length>1)if(i?.findFirst)s.matches=[s.matches[0]];else{if(!i?.findLast){var l,f,u;let t;return{ok:!1,response:(l=s.matches,f=r,u=n,t=l.slice(0,8).map(t=>{let e=h(t)||t.label||t.identifier||t.type||"";return`@${t.ref}${e?`(${e})`:""}`}),o("AMBIGUOUS_MATCH",`find matched ${l.length} elements for ${f} "${u}". Use a more specific locator or selector.`,{locator:f,query:u,matches:l.length,candidates:t}))}}s.matches=[s.matches[s.matches.length-1]]}let d=s.matches[0]??null;return d?{ok:!0,node:d}:{ok:!1,response:o("COMMAND_FAILED","find did not match any element")}}({nodes:Q,locator:U,query:v,requiresRect:B,flags:m.flags});if(!W.ok)return W.response;let X=W.node,Y=B?g(Q,X):X,Z=`@${Y.ref}`,tt={node:X,resolvedNode:Y,ref:Z,nodes:Q,actionFlags:{...m.flags??{},noRecord:!0}},te={exists:()=>k(J),get_text:()=>C(J,tt),get_attrs:()=>x(J,tt),click:()=>N(J,tt),fill:()=>I(J,tt,H),focus:()=>M(J,tt),type:()=>D(J,tt,H)}[L];return te?te():null}function w(t){return t.rect?t.rect.width*t.rect.height:1/0}function y(t,e){if(!e?.rect||!t.rect)return!1;let r=t.type?.toLowerCase()??"";return(!!r.includes("application")||!!r.includes("window"))&&t.rect.x===e.rect.x&&t.rect.y===e.rect.y&&t.rect.width===e.rect.width&&t.rect.height===e.rect.height}async function S(t,e,r,n,a){let{req:i,sessionStore:s,session:l,command:f,publicFlags:u}=t,d=a??1e4,p=Date.now();for(;Date.now()-p<d;){let{nodes:t}=await e();if(c(t,r,n,{requireRect:!1}).matches[0])return l&&s.recordAction(l,{command:f,positionals:i.positionals??[],flags:u,result:{found:!0,waitedMs:Date.now()-p}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-p}};await m(300)}return o("COMMAND_FAILED","find wait timed out")}async function k(t){let{req:e,sessionStore:r,session:n,command:o,publicFlags:a}=t;return n&&r.recordAction(n,{command:o,positionals:e.positionals??[],flags:a,result:{found:!0}}),{ok:!0,data:{found:!0}}}async function C(e,r){let{req:n,sessionStore:o,session:a,command:i,device:s,logPath:l,publicFlags:c}=e,f=await d({device:s,node:r.node,flags:n.flags,appBundleId:a?.appBundleId,traceOutPath:a?.trace?.outPath,surface:a?.surface,contextFromFlags:(e,r,n)=>t(l,e,r,n)});return a&&o.recordAction(a,{command:i,positionals:n.positionals??[],flags:c,result:{ref:r.ref,action:"get text",text:f}}),{ok:!0,data:{ref:r.ref,text:f,node:r.node}}}async function x(t,e){let{req:r,sessionStore:n,session:o,command:a,publicFlags:i}=t;return o&&n.recordAction(o,{command:a,positionals:r.positionals??[],flags:i,result:{ref:e.ref,action:"get attrs"}}),{ok:!0,data:{ref:e.ref,node:e.node}}}async function N(t,e){let{req:r,sessionName:n,sessionStore:o,session:a,invoke:i,command:s,locator:l,query:c,publicFlags:f}=t,u=await i({token:r.token,session:n,command:"click",positionals:[e.ref],flags:e.actionFlags});if(!u.ok)return u;let d=e.resolvedNode.rect?p(e.resolvedNode.rect):e.node.rect?p(e.node.rect):null,_={ref:e.ref,locator:l,query:c};return d&&(_.x=d.x,_.y=d.y),a&&o.recordAction(a,{command:s,positionals:r.positionals??[],flags:f,result:{ref:e.ref,action:"click",locator:l,query:c}}),{ok:!0,data:_}}async function I(t,e,r){let{req:n,sessionName:a,sessionStore:i,session:s,invoke:l,command:c,publicFlags:f}=t;if(!r)return o("INVALID_ARGS","find fill requires text");let u=await l({token:n.token,session:a,command:"fill",positionals:[e.ref,r],flags:e.actionFlags});return u.ok&&s&&i.recordAction(s,{command:c,positionals:n.positionals??[],flags:f,result:{ref:e.ref,action:"fill"}}),u}async function M(t,e){let r=await R(t,e);return r.ok&&K(t,e,"focus"),r}async function D(e,r,a){let{req:i,device:s,logPath:l,session:c}=e;if(!a)return o("INVALID_ARGS","find type requires text");let f=await R(e,r);if(!f.ok)return f;let u=await n(s,"type",[a],i.flags?.out,{...t(l,i.flags,c?.appBundleId,c?.trace?.outPath)});return K(e,r,"type"),{ok:!0,data:u??{ref:r.ref}}}async function R(e,r){let{req:a,device:i,logPath:s,session:l}=e,c=r.node.rect?p(r.node.rect):null;return c?{ok:!0,data:await n(i,"focus",[String(c.x),String(c.y)],a.flags?.out,{...t(s,a.flags,l?.appBundleId,l?.trace?.outPath)})??{ref:r.ref}}:o("COMMAND_FAILED","matched element has no bounds")}function K(t,e,r){let{req:n,sessionStore:o,session:a,command:i,publicFlags:s}=t;a&&o.recordAction(a,{command:i,positionals:n.positionals??[],flags:s,result:{ref:e.ref,action:r}})}export{parseFindArgs}from"./7556.js";export{A as handleFindCommands};
@@ -1 +1 @@
1
- import{__webpack_require__ as e}from"./rslib-runtime.js";import{createDaemonRuntimeSessionStore as t,setSessionSnapshot as r,dispatchCommand as a,getClickButtonValidationError as n,ensureAndroidBlockingSystemDialogReady as s,isCommandSupportedOnDevice as o,buttonTag as i,resolveClickButton as l,errorResponse as c,recoverAndroidBlockingSystemDialog as u,getActiveAndroidSnapshotFreshness as f}from"./2415.js";import{createAgentDevice as d}from"./9533.js";import{asAppError as p,normalizeError as g,AppError as m}from"./9152.js";import{dispatchGetViaRuntime as S,isAndroidEscapeError as k,createDaemonRuntimePolicy as _,assertAndroidPressStayedInApp as y,dispatchIsViaRuntime as h,isDirectIosSelectorFallbackError as w,refSnapshotFlagGuardResponse as b,readSimpleIosSelectorTarget as N}from"./selector-runtime.js";import{readInteractionTargetFromPositionals as v,readFillTargetFromPositionals as x}from"./8502.js";import{interaction_snapshot_captureSnapshotForSession as F,readSnapshotNodesReferenceFrame as P,resolveDirectTouchReferenceFrameSafely as R,buildTouchVisualizationResult as M,finalizeTouchInteraction as O}from"./9471.js";import{emitDiagnostic as C}from"./7599.js";import{PUBLIC_COMMANDS as I}from"./5792.js";import{successText as A}from"./1998.js";var E={};function q(e,t){return"macos"!==e.device.platform||"desktop"!==e.surface&&"menubar"!==e.surface||"menubar"===e.surface&&("click"===t||"press"===t)?null:c("UNSUPPORTED_OPERATION",`${t} is not supported on macOS ${e.surface} sessions yet. Open an app session to act, or use the ${e.surface} surface to inspect.`)}function D(e){let n=e.sessionStore.get(e.sessionName);if(!n)throw new m("SESSION_NOT_FOUND","No active session. Run open first.");return d({backend:function(e){let{req:t,session:r}=e;return{platform:r.device.platform,captureSnapshot:async(a,n)=>({snapshot:await e.captureSnapshotForSession(r,t.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:n?.interactiveOnly===!0})}),tap:async(n,s)=>U(await a(r.device,"press",[String(s.x),String(s.y)],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),fill:async(n,s,o)=>U(await a(r.device,"fill",[String(s.x),String(s.y),o],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),longPress:async(n,s,o)=>U(await a(r.device,"longpress",[String(s.x),String(s.y),...o?.durationMs===void 0?[]:[String(o.durationMs)]],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),typeText:async(n,s)=>U(await a(r.device,"type",[s],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath)))}}({...e,session:n}),..._("interaction commands",{plural:!0}),sessions:t({sessionName:e.sessionName,getSession:()=>n,recordOptions:{includeSnapshot:!0},setRecord:t=>{t.snapshot&&(r(n,t.snapshot),e.sessionStore.set(e.sessionName,n))}})})}function U(e){return e&&"object"==typeof e?e:void 0}function T(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}function H(e,t){let r=T(e);if(r)return{ok:!0,target:{kind:"point",x:r.x,y:r.y}};let a=e[0]??"";if(a.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:a,fallbackLabel:v(e).label??""}};let n=e.join(" ").trim();return n?{ok:!0,target:{kind:"selector",selector:n}}:{ok:!1,response:c("INVALID_ARGS",`${t} requires @ref, selector expression, or x y coordinates`)}}function K(e){return"ref"===e.kind?{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),refLabel:e.refLabel,selectorChain:e.selectorChain}:"selector"===e.kind?{selector:e.target?.kind==="selector"?e.target.selector:void 0,selectorChain:e.selectorChain,refLabel:e.refLabel}:{}}function L(e){return e?.startsWith("@")?e.slice(1):e}async function j(e){switch(e.req.command){case"press":return await B(e,"press");case"click":return await B(e,"click");case"longpress":return await B(e,"longpress");case"fill":return await X(e);default:return null}}async function B(e,t){let r,{req:a,sessionName:s,sessionStore:u}=e,f=u.get(s);if(!f)return c("SESSION_NOT_FOUND","No active session. Run open first.");let d="click"===t?"click":t,p="longpress"===t?"longpress":"press",g=q(f,d);if(g)return g;if(!o(p,f.device))return c("UNSUPPORTED_OPERATION",`${p} is not supported on this device`);let m=l(a.flags),S=i(m);if("longpress"!==t&&"primary"!==m){let e=n({commandLabel:d,platform:f.device.platform,button:m,count:a.flags?.count,intervalMs:a.flags?.intervalMs,holdMs:a.flags?.holdMs,jitterPx:a.flags?.jitterPx,doubleTap:a.flags?.doubleTap});if(e)return c(e.code,e.message,e.details)}let k="longpress"===t?function(e){var t,r,a;let n,s=T(e);if(s){return{ok:!0,target:{kind:"point",x:s.x,y:s.y},...void 0===(t=e[2])?{}:{durationMs:Number(t)}}}let o=(n=(r=e).at(-1),r.length>1&&void 0!==(a=n)&&""!==a.trim()&&Number.isFinite(Number(a))?{targetPositionals:r.slice(0,-1),duration:{durationMs:Number(n)}}:{targetPositionals:r,duration:{}}),i=H(o.targetPositionals,"longpress");return i.ok?{ok:!0,target:i.target,...o.duration}:i}(a.positionals??[]):H(a.positionals??[],d);if(!k.ok)return k.response;if("ref"===k.target.kind){let n=e.refSnapshotFlagGuardResponse("longpress"===t?"longpress":"press",a.flags);if(n)return n;r=await J(e,f)}let _=function(e){var t;let{session:r,commandLabel:a,target:n,flags:s}=e;if("click"!==a||"selector"!==n.kind||(t=s,t?.count!==void 0||t?.intervalMs!==void 0||t?.holdMs!==void 0||t?.jitterPx!==void 0||t?.doubleTap!==void 0||t?.clickButton!==void 0&&"primary"!==t.clickButton))return null;let o=N({session:r,selectorExpression:n.selector});return o?{...o,...s?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:f,commandLabel:d,target:k.target,flags:a.flags});if(_){let t=await $(e,f,_);if(t)return t}let h="longpress"===t?k.durationMs:void 0;return await z(e,{androidFreshnessBaseline:r,run:async e=>await G({runtime:e,command:t,target:k.target,sessionName:s,requestId:a.meta?.requestId,clickButton:m,flags:a.flags,durationMs:h}),afterRun:async e=>{var t;await y(f,(t=k.target,"point"===t.kind?"coordinate tap":"ref"===e.kind&&e.target?.kind==="ref"?e.target.ref:"selector"===e.kind&&e.target?.kind==="selector"?e.target.selector:"target"))},buildPayloads:async r=>{var a;let n="durationMs"in(a=r)?a.durationMs:void 0,s=await W({params:e,session:f,result:r,extra:"longpress"===t?{...void 0!==n?{durationMs:n}:{},gesture:"longpress"}:S});return{result:s,responseData:s}}})}async function G(e){let{runtime:t,command:r,target:a,sessionName:n,requestId:s,flags:o}=e;if("longpress"===r)return await t.interactions.longPress(a,{session:n,requestId:s,durationMs:e.durationMs});let i={session:n,requestId:s,button:e.clickButton,count:o?.count,intervalMs:o?.intervalMs,holdMs:o?.holdMs,jitterPx:o?.jitterPx,doubleTap:o?.doubleTap};return"click"===r?await t.interactions.click(a,i):await t.interactions.press(a,i)}async function W(e){let{params:t,session:r,result:a,extra:n}=e,s="point"===a.kind?await R({session:r,flags:t.req.flags,sessionStore:t.sessionStore,contextFromFlags:t.contextFromFlags,captureSnapshotForSession:t.captureSnapshotForSession}):P(r.snapshot?.nodes??[]);return M({data:a.backendResult,fallbackX:a.point.x,fallbackY:a.point.y,referenceFrame:s,extra:{...K(a),...n}})}async function $(e,t,r){return await V({params:e,session:t,selector:r,command:"press",positionals:[],extra:{selector:r.raw},fallbackPhase:"ios_direct_selector_tap_fallback"})}async function V(e){let{params:t,session:r,selector:n,command:s,positionals:o,extra:i,fallbackPhase:l}=e,c=Date.now();try{var u,f;let e,l,d=await a(r.device,s,o,t.req.flags?.out,{...t.contextFromFlags(t.req.flags,r.appBundleId,r.trace?.outPath),directElementSelector:n,surface:r.surface})??{},p=Date.now(),g=(u=d,e="number"==typeof u.x?u.x:void 0,l="number"==typeof u.y?u.y:void 0,void 0!==e&&void 0!==l?{x:e,y:l}:{x:0,y:0}),m=M({data:d,fallbackX:g.x,fallbackY:g.y,referenceFrame:(f=d,"number"==typeof f.referenceWidth&&"number"==typeof f.referenceHeight?{referenceWidth:f.referenceWidth,referenceHeight:f.referenceHeight}:void 0),extra:{...i,...function(e,t){if(!e.allowNonHittableCoordinateFallback)return{};let r="tapped via non-hittable coordinate fallback"===t.message;return{maestroNonHittableCoordinateFallbackAllowed:!0,maestroNonHittableCoordinateFallbackUsed:r,...r?{maestroFallbackReason:"non-hittable-coordinate"}:{}}}(n,d)}});return O({session:r,sessionStore:t.sessionStore,command:t.req.command,positionals:t.req.positionals??[],retryPositionals:Q(g),flags:t.req.flags,result:m,responseData:m,actionStartedAt:c,actionFinishedAt:p})}catch(e){if(!w(e))return{ok:!1,error:g(e)};return C({level:"debug",phase:l,data:{selector:n.raw,error:e instanceof Error?e.message:String(e)}}),null}}async function X(e){let{req:t,sessionName:r,sessionStore:a}=e,n=a.get(r);if(n){let e=q(n,"fill");if(e)return e}if(n&&!o("fill",n.device))return c("UNSUPPORTED_OPERATION","fill is not supported on this device");if(!n)return c("SESSION_NOT_FOUND","No active session. Run open first.");let s=function(e){let t=e[0]??"";if(t.startsWith("@")){var r;let a=x(e).text;return a?{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:(r=e).length>=3&&r[1]?.trim()||""},text:a}:{ok:!1,response:c("INVALID_ARGS","fill requires text after ref")}}let a=T(e);if(a){let t=e.slice(2).join(" ");return t?{ok:!0,target:{kind:"point",x:a.x,y:a.y},text:t}:{ok:!1,response:c("INVALID_ARGS","fill requires text after coordinates")}}let n=x(e);return"selector"!==n.kind?{ok:!1,response:c("INVALID_ARGS","fill requires x y text, @ref text, or selector text")}:n.text.trim()?{ok:!0,target:{kind:"selector",selector:n.target.selector},text:n.text}:{ok:!1,response:c("INVALID_ARGS","fill requires text after selector")}}(t.positionals??[]);if(!s.ok)return s.response;if("ref"===s.target.kind){let r=e.refSnapshotFlagGuardResponse("fill",t.flags);if(r)return r;await J(e,n)}let i=function(e){let{session:t,target:r,flags:a}=e;if("selector"!==r.kind)return null;let n=N({session:t,selectorExpression:r.selector});return n?{...n,...a?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:n,target:s.target,flags:t.flags});if(i){let t=await Y(e,n,i,s.text);if(t)return t}return await z(e,{run:async e=>await e.interactions.fill(s.target,s.text,{session:r,requestId:t.meta?.requestId,delayMs:t.flags?.delayMs}),buildPayloads:e=>{let t="point"===e.kind?void 0:P(n.snapshot?.nodes??[]),r=M({data:e.backendResult,fallbackX:e.point.x,fallbackY:e.point.y,referenceFrame:t,extra:{...K(e),text:s.text}});e.warning&&(r.warning=e.warning);let a="ref"===e.kind?{...e.backendResult??{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),x:e.point.x,y:e.point.y}}:r;return e.warning&&(a.warning=e.warning),{result:r,responseData:a}}})}async function Y(e,t,r,a){return await V({params:e,session:t,selector:r,command:"fill",positionals:[a],extra:{selector:r.raw,text:a},fallbackPhase:"ios_direct_selector_fill_fallback"})}async function z(e,t){let r=e.sessionStore.get(e.sessionName);if(!r)return c("SESSION_NOT_FOUND","No active session. Run open first.");let a=D(e),n=Date.now();try{let o=await s({session:r,command:e.req.command,phase:"before-command"}),i=await t.run(a);await t.afterRun?.(i),await s({session:r,command:e.req.command,phase:"after-command"});let l=Date.now(),{result:c,responseData:u}=await t.buildPayloads(i);return"recovered"===o.status&&(c.warning=o.warning,u.warning=o.warning),O({session:r,sessionStore:e.sessionStore,command:e.req.command,positionals:e.req.positionals??[],retryPositionals:function(e,t){if("click"===e||"press"===e)return Q(t.point)}(e.req.command,i),flags:e.req.flags,result:c,responseData:u,actionStartedAt:n,actionFinishedAt:l,androidFreshnessBaseline:t.androidFreshnessBaseline})}catch(t){let e=p(t);if(k(e))throw e;return{ok:!1,error:g(t)}}}async function J(e,t){if(!f(t))return;let r=t.snapshot?.comparisonSafe===!0?t.snapshot:void 0;try{await e.captureSnapshotForSession(t,e.req.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:!0,androidFreshnessMode:"ref-refresh"})}catch(t){C({level:"warn",phase:"android_ref_snapshot_refresh_failed",data:{command:e.req.command,error:t instanceof Error?t.message:String(t)}})}return r}function Q(e){return[String(e.x),String(e.y)]}e.r(E),e.d(E,{INTERACTION_COMMAND_HANDLERS:()=>Z,handleInteractionCommands:()=>ee});let Z={[I.click]:!0,[I.fill]:!0,[I.get]:!0,[I.is]:!0,[I.longPress]:!0,[I.press]:!0,[I.type]:!0};async function ee(e){let t=await j({...e,captureSnapshotForSession:F,refSnapshotFlagGuardResponse:b});if(t)return t;switch(e.req.command){case I.type:return await et({...e,captureSnapshotForSession:F});case"get":return await S(e);case"is":return await h(e);default:return null}}async function et(e){let{sessionName:t,sessionStore:r}=e,a=r.get(t);if(!a)return c("SESSION_NOT_FOUND","No active session. Run open first.");if(!o(I.type,a.device))return c("UNSUPPORTED_OPERATION","type is not supported on this device");let n=await er(a);return n||await ea(e,a)}async function er(e){return"android"===e.device.platform&&e.recording&&"failed"===await u({session:e})?c("COMMAND_FAILED","Android system dialog blocked the recording session"):null}async function ea(e,t){let{req:r,sessionName:a,sessionStore:n}=e,o=(r.positionals??[]).join(" "),i=D(e),l=Date.now();try{let e=await s({session:t,command:r.command,phase:"before-command"}),c=await i.interactions.typeText(o,{session:a,requestId:r.meta?.requestId,delayMs:r.flags?.delayMs});await s({session:t,command:r.command,phase:"after-command"});let u=Date.now(),f={...c.backendResult??{},text:c.text,delayMs:c.delayMs,...A(c.message??`Typed ${Array.from(c.text).length} chars`)};return"recovered"===e.status&&(f.warning=e.warning),O({session:t,sessionStore:n,command:r.command,positionals:r.positionals??[],flags:r.flags,result:f,responseData:f,actionStartedAt:l,actionFinishedAt:u})}catch(e){return{ok:!1,error:g(e)}}}export{E as interaction_namespaceObject};
1
+ import{__webpack_require__ as e}from"./rslib-runtime.js";import{createDaemonRuntimeSessionStore as t,setSessionSnapshot as r,dispatchCommand as a,getClickButtonValidationError as n,ensureAndroidBlockingSystemDialogReady as o,isCommandSupportedOnDevice as s,buttonTag as i,resolveClickButton as l,errorResponse as c,recoverAndroidBlockingSystemDialog as u,getActiveAndroidSnapshotFreshness as f}from"./2415.js";import{createAgentDevice as d}from"./9533.js";import{asAppError as p,normalizeError as g,AppError as m}from"./9152.js";import{dispatchGetViaRuntime as S,isAndroidEscapeError as k,createDaemonRuntimePolicy as _,assertAndroidPressStayedInApp as y,dispatchIsViaRuntime as h,isDirectIosSelectorFallbackError as w,refSnapshotFlagGuardResponse as b,readSimpleIosSelectorTarget as N}from"./selector-runtime.js";import{readInteractionTargetFromPositionals as v,readFillTargetFromPositionals as x}from"./8502.js";import{interaction_snapshot_captureSnapshotForSession as F,readSnapshotNodesReferenceFrame as P,resolveDirectTouchReferenceFrameSafely as R,buildTouchVisualizationResult as M,finalizeTouchInteraction as O}from"./9471.js";import{emitDiagnostic as C}from"./7599.js";import{PUBLIC_COMMANDS as I}from"./5792.js";import{successText as A}from"./1998.js";var E={};function q(e,t){return"macos"!==e.device.platform||"desktop"!==e.surface&&"menubar"!==e.surface||"menubar"===e.surface&&("click"===t||"press"===t)?null:c("UNSUPPORTED_OPERATION",`${t} is not supported on macOS ${e.surface} sessions yet. Open an app session to act, or use the ${e.surface} surface to inspect.`)}function U(e){let n=e.sessionStore.get(e.sessionName);if(!n)throw new m("SESSION_NOT_FOUND","No active session. Run open first.");return d({backend:function(e){let{req:t,session:r}=e;return{platform:r.device.platform,captureSnapshot:async(a,n)=>({snapshot:await e.captureSnapshotForSession(r,t.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:n?.interactiveOnly===!0})}),tap:async(n,o)=>D(await a(r.device,"press",[String(o.x),String(o.y)],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),fill:async(n,o,s)=>D(await a(r.device,"fill",[String(o.x),String(o.y),s],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),longPress:async(n,o,s)=>D(await a(r.device,"longpress",[String(o.x),String(o.y),...s?.durationMs===void 0?[]:[String(s.durationMs)]],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),typeText:async(n,o)=>D(await a(r.device,"type",[o],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath)))}}({...e,session:n}),..._("interaction commands",{plural:!0}),sessions:t({sessionName:e.sessionName,getSession:()=>n,recordOptions:{includeSnapshot:!0},setRecord:t=>{t.snapshot&&(r(n,t.snapshot),e.sessionStore.set(e.sessionName,n))}})})}function D(e){return e&&"object"==typeof e?e:void 0}function T(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}function H(e,t){let r=T(e);if(r)return{ok:!0,target:{kind:"point",x:r.x,y:r.y}};let a=e[0]??"";if(a.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:a,fallbackLabel:v(e).label??""}};let n=e.join(" ").trim();return n?{ok:!0,target:{kind:"selector",selector:n}}:{ok:!1,response:c("INVALID_ARGS",`${t} requires @ref, selector expression, or x y coordinates`)}}function K(e){return"ref"===e.kind?{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),refLabel:e.refLabel,selectorChain:e.selectorChain}:"selector"===e.kind?{selector:e.target?.kind==="selector"?e.target.selector:void 0,selectorChain:e.selectorChain,refLabel:e.refLabel}:{}}function L(e){return e?.startsWith("@")?e.slice(1):e}async function j(e){switch(e.req.command){case"press":return await B(e,"press");case"click":return await B(e,"click");case"longpress":return await B(e,"longpress");case"fill":return await X(e);default:return null}}async function B(e,t){let r,{req:a,sessionName:o,sessionStore:u}=e,f=u.get(o);if(!f)return c("SESSION_NOT_FOUND","No active session. Run open first.");let d="click"===t?"click":t,p="longpress"===t?"longpress":"press",g=q(f,d);if(g)return g;if(!s(p,f.device))return c("UNSUPPORTED_OPERATION",`${p} is not supported on this device`);let m=l(a.flags),S=i(m);if("longpress"!==t&&"primary"!==m){let e=n({commandLabel:d,platform:f.device.platform,button:m,count:a.flags?.count,intervalMs:a.flags?.intervalMs,holdMs:a.flags?.holdMs,jitterPx:a.flags?.jitterPx,doubleTap:a.flags?.doubleTap});if(e)return c(e.code,e.message,e.details)}let k="longpress"===t?function(e){var t,r,a;let n,o=T(e);if(o){return{ok:!0,target:{kind:"point",x:o.x,y:o.y},...void 0===(t=e[2])?{}:{durationMs:Number(t)}}}let s=(n=(r=e).at(-1),r.length>1&&void 0!==(a=n)&&""!==a.trim()&&Number.isFinite(Number(a))?{targetPositionals:r.slice(0,-1),duration:{durationMs:Number(n)}}:{targetPositionals:r,duration:{}}),i=H(s.targetPositionals,"longpress");return i.ok?{ok:!0,target:i.target,...s.duration}:i}(a.positionals??[]):H(a.positionals??[],d);if(!k.ok)return k.response;if("ref"===k.target.kind){let n=e.refSnapshotFlagGuardResponse("longpress"===t?"longpress":"press",a.flags);if(n)return n;r=await J(e,f)}let _=function(e){var t;let{session:r,commandLabel:a,target:n,flags:o}=e;if("click"!==a||"selector"!==n.kind||(t=o,t?.count!==void 0||t?.intervalMs!==void 0||t?.holdMs!==void 0||t?.jitterPx!==void 0||t?.doubleTap!==void 0||t?.clickButton!==void 0&&"primary"!==t.clickButton))return null;let s=N({session:r,selectorExpression:n.selector});return s?{...s,...o?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:f,commandLabel:d,target:k.target,flags:a.flags});if(_){let t=await $(e,f,_);if(t)return t}let h="longpress"===t?k.durationMs:void 0;return await z(e,{androidFreshnessBaseline:r,run:async e=>await G({runtime:e,command:t,target:k.target,sessionName:o,requestId:a.meta?.requestId,clickButton:m,flags:a.flags,durationMs:h}),afterRun:async e=>{var t;await y(f,(t=k.target,"point"===t.kind?"coordinate tap":"ref"===e.kind&&e.target?.kind==="ref"?e.target.ref:"selector"===e.kind&&e.target?.kind==="selector"?e.target.selector:"target"))},buildPayloads:async r=>{var a;let n="durationMs"in(a=r)?a.durationMs:void 0,o=await W({params:e,session:f,result:r,extra:"longpress"===t?{...void 0!==n?{durationMs:n}:{},gesture:"longpress"}:S});return{result:o,responseData:o}}})}async function G(e){let{runtime:t,command:r,target:a,sessionName:n,requestId:o,flags:s}=e;if("longpress"===r)return await t.interactions.longPress(a,{session:n,requestId:o,durationMs:e.durationMs});let i={session:n,requestId:o,button:e.clickButton,count:s?.count,intervalMs:s?.intervalMs,holdMs:s?.holdMs,jitterPx:s?.jitterPx,doubleTap:s?.doubleTap};return"click"===r?await t.interactions.click(a,i):await t.interactions.press(a,i)}async function W(e){let{params:t,session:r,result:a,extra:n}=e,o="point"===a.kind?await R({session:r,flags:t.req.flags,sessionStore:t.sessionStore,contextFromFlags:t.contextFromFlags,captureSnapshotForSession:t.captureSnapshotForSession}):P(r.snapshot?.nodes??[]);return M({data:a.backendResult,fallbackX:a.point.x,fallbackY:a.point.y,referenceFrame:o,extra:{...K(a),...n}})}async function $(e,t,r){return await V({params:e,session:t,selector:r,command:"press",positionals:[],extra:{selector:r.raw},fallbackPhase:"ios_direct_selector_tap_fallback"})}async function V(e){let{params:t,session:r,selector:n,command:o,positionals:s,extra:i,fallbackPhase:l}=e,c=Date.now();try{var u,f;let e,l,d=await a(r.device,o,s,t.req.flags?.out,{...t.contextFromFlags(t.req.flags,r.appBundleId,r.trace?.outPath),directElementSelector:n,surface:r.surface})??{},p=Date.now(),g=(u=d,e="number"==typeof u.x?u.x:void 0,l="number"==typeof u.y?u.y:void 0,void 0!==e&&void 0!==l?{x:e,y:l}:{x:0,y:0}),m=M({data:d,fallbackX:g.x,fallbackY:g.y,referenceFrame:(f=d,"number"==typeof f.referenceWidth&&"number"==typeof f.referenceHeight?{referenceWidth:f.referenceWidth,referenceHeight:f.referenceHeight}:void 0),extra:{...i,...function(e,t){if(!e.allowNonHittableCoordinateFallback)return{};let r="tapped via non-hittable coordinate fallback"===t.message;return{maestroNonHittableCoordinateFallbackAllowed:!0,maestroNonHittableCoordinateFallbackUsed:r,...r?{maestroFallbackReason:"non-hittable-coordinate"}:{}}}(n,d)}});return O({session:r,sessionStore:t.sessionStore,command:t.req.command,positionals:t.req.positionals??[],retryPositionals:Q(g),flags:t.req.flags,result:m,responseData:m,actionStartedAt:c,actionFinishedAt:p})}catch(e){if(!w(e))return{ok:!1,error:g(e)};return C({level:"debug",phase:l,data:{selector:n.raw,error:e instanceof Error?e.message:String(e)}}),null}}async function X(e){let{req:t,sessionName:r,sessionStore:a}=e,n=a.get(r);if(n){let e=q(n,"fill");if(e)return e}if(n&&!s("fill",n.device))return c("UNSUPPORTED_OPERATION","fill is not supported on this device");if(!n)return c("SESSION_NOT_FOUND","No active session. Run open first.");let o=function(e){let t=e[0]??"";if(t.startsWith("@")){var r;let a=x(e).text;return a?{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:(r=e).length>=3&&r[1]?.trim()||""},text:a}:{ok:!1,response:c("INVALID_ARGS","fill requires text after ref")}}let a=T(e);if(a){let t=e.slice(2).join(" ");return t?{ok:!0,target:{kind:"point",x:a.x,y:a.y},text:t}:{ok:!1,response:c("INVALID_ARGS","fill requires text after coordinates")}}let n=x(e);return"selector"!==n.kind?{ok:!1,response:c("INVALID_ARGS","fill requires x y text, @ref text, or selector text")}:n.text.trim()?{ok:!0,target:{kind:"selector",selector:n.target.selector},text:n.text}:{ok:!1,response:c("INVALID_ARGS","fill requires text after selector")}}(t.positionals??[]);if(!o.ok)return o.response;if("ref"===o.target.kind){let r=e.refSnapshotFlagGuardResponse("fill",t.flags);if(r)return r;await J(e,n)}let i=function(e){let{session:t,target:r,flags:a}=e;if("selector"!==r.kind)return null;let n=N({session:t,selectorExpression:r.selector});return n?{...n,...a?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:n,target:o.target,flags:t.flags});if(i){let t=await Y(e,n,i,o.text);if(t)return t}return await z(e,{run:async e=>await e.interactions.fill(o.target,o.text,{session:r,requestId:t.meta?.requestId,delayMs:t.flags?.delayMs}),buildPayloads:e=>{let t="point"===e.kind?void 0:P(n.snapshot?.nodes??[]),r=M({data:e.backendResult,fallbackX:e.point.x,fallbackY:e.point.y,referenceFrame:t,extra:{...K(e),text:o.text}});e.warning&&(r.warning=e.warning);let a="ref"===e.kind?{...e.backendResult??{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),x:e.point.x,y:e.point.y}}:r;return e.warning&&(a.warning=e.warning),{result:r,responseData:a}}})}async function Y(e,t,r,a){return await V({params:e,session:t,selector:r,command:"fill",positionals:[a],extra:{selector:r.raw,text:a},fallbackPhase:"ios_direct_selector_fill_fallback"})}async function z(e,t){let r=e.sessionStore.get(e.sessionName);if(!r)return c("SESSION_NOT_FOUND","No active session. Run open first.");let a=U(e),n=Date.now();try{let s=await o({session:r,command:e.req.command,phase:"before-command"}),i=await t.run(a);await t.afterRun?.(i),await o({session:r,command:e.req.command,phase:"after-command"});let l=Date.now(),{result:c,responseData:u}=await t.buildPayloads(i);return"recovered"===s.status&&(c.warning=s.warning,u.warning=s.warning),O({session:r,sessionStore:e.sessionStore,command:e.req.command,positionals:e.req.positionals??[],retryPositionals:function(e,t){if("click"===e||"press"===e)return Q(t.point)}(e.req.command,i),flags:e.req.flags,result:c,responseData:u,actionStartedAt:n,actionFinishedAt:l,androidFreshnessBaseline:t.androidFreshnessBaseline})}catch(t){let e=p(t);if(k(e))throw e;return{ok:!1,error:g(t)}}}async function J(e,t){if(!f(t))return;let r=t.snapshot?.comparisonSafe===!0?t.snapshot:void 0;try{await e.captureSnapshotForSession(t,e.req.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:!0,androidFreshnessMode:"ref-refresh"})}catch(t){C({level:"warn",phase:"android_ref_snapshot_refresh_failed",data:{command:e.req.command,error:t instanceof Error?t.message:String(t)}})}return r}function Q(e){return[String(e.x),String(e.y)]}async function Z(e){let t=await j({...e,captureSnapshotForSession:F,refSnapshotFlagGuardResponse:b});if(t)return t;switch(e.req.command){case I.type:return await ee({...e,captureSnapshotForSession:F});case"get":return await S(e);case"is":return await h(e);default:return null}}async function ee(e){let{sessionName:t,sessionStore:r}=e,a=r.get(t);if(!a)return c("SESSION_NOT_FOUND","No active session. Run open first.");if(!s(I.type,a.device))return c("UNSUPPORTED_OPERATION","type is not supported on this device");let n=await et(a);return n||await er(e,a)}async function et(e){return"android"===e.device.platform&&e.recording&&"failed"===await u({session:e})?c("COMMAND_FAILED","Android system dialog blocked the recording session"):null}async function er(e,t){let{req:r,sessionName:a,sessionStore:n}=e,s=(r.positionals??[]).join(" "),i=U(e),l=Date.now();try{let e=await o({session:t,command:r.command,phase:"before-command"}),c=await i.interactions.typeText(s,{session:a,requestId:r.meta?.requestId,delayMs:r.flags?.delayMs});await o({session:t,command:r.command,phase:"after-command"});let u=Date.now(),f={...c.backendResult??{},text:c.text,delayMs:c.delayMs,...A(c.message??`Typed ${Array.from(c.text).length} chars`)};return"recovered"===e.status&&(f.warning=e.warning),O({session:t,sessionStore:n,command:r.command,positionals:r.positionals??[],flags:r.flags,result:f,responseData:f,actionStartedAt:l,actionFinishedAt:u})}catch(e){return{ok:!1,error:g(e)}}}e.r(E),e.d(E,{handleInteractionCommands:()=>Z});export{E as interaction_namespaceObject};
package/dist/src/lease.js CHANGED
@@ -1 +1 @@
1
- import{INTERNAL_COMMANDS as e}from"./5792.js";import{resolveLeaseScope as a}from"./2415.js";let t={[e.leaseAllocate]:!0,[e.leaseHeartbeat]:!0,[e.leaseRelease]:!0};async function l(e){let{req:t,leaseRegistry:l}=e,s=a(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:l.allocateLease({tenantId:s.tenantId??"",runId:s.runId??"",backend:s.leaseBackend,ttlMs:s.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:l.heartbeatLease({leaseId:s.leaseId??"",tenantId:s.tenantId,runId:s.runId,ttlMs:s.leaseTtlMs})}};case"lease_release":return{ok:!0,data:l.releaseLease({leaseId:s.leaseId??"",tenantId:s.tenantId,runId:s.runId})};default:return null}}export{t as LEASE_COMMAND_HANDLERS,l as handleLeaseCommands};
1
+ import{resolveLeaseScope as e}from"./2415.js";async function a(a){let{req:t,leaseRegistry:n}=a,s=e(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:n.allocateLease({tenantId:s.tenantId??"",runId:s.runId??"",backend:s.leaseBackend,ttlMs:s.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:n.heartbeatLease({leaseId:s.leaseId??"",tenantId:s.tenantId,runId:s.runId,ttlMs:s.leaseTtlMs})}};case"lease_release":return{ok:!0,data:n.releaseLease({leaseId:s.leaseId??"",tenantId:s.tenantId,runId:s.runId})};default:return null}}export{a as handleLeaseCommands};
@@ -1 +1 @@
1
- import{dispatchCommand as e,errorResponse as t,isCommandSupportedOnDevice as i}from"./2415.js";import{PUBLIC_COMMANDS as a}from"./5792.js";import{analyzeReactNativeOverlay as r}from"./9533.js";import{normalizeError as n}from"./9152.js";import{stripUndefined as o}from"./7455.js";import{interaction_snapshot_captureSnapshotForSession as s,readSnapshotNodesReferenceFrame as d,finalizeTouchInteraction as c}from"./9471.js";import{successText as l}from"./1998.js";let v={[a.reactNative]:!0};async function f(e){var o;let{req:d,sessionName:c,sessionStore:v}=e;if(d.command!==a.reactNative)return null;let f=1===(o=d.positionals??[]).length&&"dismiss-overlay"===o[0]?{ok:!0}:{ok:!1,response:t("INVALID_ARGS","react-native supports only: dismiss-overlay")};if(!f.ok)return f.response;let _=v.get(c);if(!_)return t("SESSION_NOT_FOUND","No active session. Run open first.");if(!i(a.reactNative,_.device))return t("UNSUPPORTED_OPERATION","react-native dismiss-overlay is not supported on this device");try{let i=await s(_,d.flags,v,e.contextFromFlags,{interactiveOnly:!0}),a=r(i.nodes),n=a.primaryAction;if(!n)return a.detected?t("COMMAND_FAILED","React Native overlay detected, but no safe dismiss target was found",{hint:"Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body."}):{ok:!0,data:{action:"dismiss-overlay",detected:!1,dismissed:!1,...l("No React Native overlay detected")}};return await m(e,_,i,n)}catch(e){return{ok:!1,error:n(e)}}}async function m(t,i,a,r){let{req:n,sessionStore:s}=t,v=Date.now(),f=await e(i.device,"press",[String(r.point.x),String(r.point.y)],n.flags?.out,t.contextFromFlags(n.flags,i.appBundleId,i.trace?.outPath))??{},m=Date.now(),p=await _(t,i),y=o({...d(a.nodes),...f,action:"dismiss-overlay",overlayAction:r.action,x:r.point.x,y:r.point.y,ref:r.ref,label:r.label,warning:r.warning,dismissed:!0,verified:p.verified,verificationRequired:!p.verified,verificationWarning:p.verificationWarning,nextCommand:p.nextCommand,...l(p.verified?"React Native overlay dismiss action sent and verified gone":"React Native overlay dismiss action sent, but verification still detects an overlay")});return c({session:i,sessionStore:s,command:n.command,positionals:n.positionals??[],flags:n.flags,result:y,responseData:y,actionStartedAt:v,actionFinishedAt:m})}async function _(e,t){let{req:i,sessionStore:a}=e;return r((await s(t,i.flags,a,e.contextFromFlags,{interactiveOnly:!0})).nodes).detected?{verified:!1,verificationWarning:"React Native overlay is still detected after dismissal. Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body.",nextCommand:"agent-device screenshot --overlay-refs"}:{verified:!0}}export{v as REACT_NATIVE_COMMAND_HANDLERS,f as handleReactNativeCommands};
1
+ import{dispatchCommand as e,errorResponse as t,isCommandSupportedOnDevice as i}from"./2415.js";import{PUBLIC_COMMANDS as r}from"./5792.js";import{analyzeReactNativeOverlay as a}from"./9533.js";import{normalizeError as n}from"./9152.js";import{stripUndefined as o}from"./7455.js";import{interaction_snapshot_captureSnapshotForSession as s,readSnapshotNodesReferenceFrame as d,finalizeTouchInteraction as c}from"./9471.js";import{successText as l}from"./1998.js";async function v(e){var o;let{req:d,sessionName:c,sessionStore:v}=e;if(d.command!==r.reactNative)return null;let m=1===(o=d.positionals??[]).length&&"dismiss-overlay"===o[0]?{ok:!0}:{ok:!1,response:t("INVALID_ARGS","react-native supports only: dismiss-overlay")};if(!m.ok)return m.response;let _=v.get(c);if(!_)return t("SESSION_NOT_FOUND","No active session. Run open first.");if(!i(r.reactNative,_.device))return t("UNSUPPORTED_OPERATION","react-native dismiss-overlay is not supported on this device");try{let i=await s(_,d.flags,v,e.contextFromFlags,{interactiveOnly:!0}),r=a(i.nodes),n=r.primaryAction;if(!n)return r.detected?t("COMMAND_FAILED","React Native overlay detected, but no safe dismiss target was found",{hint:"Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body."}):{ok:!0,data:{action:"dismiss-overlay",detected:!1,dismissed:!1,...l("No React Native overlay detected")}};return await f(e,_,i,n)}catch(e){return{ok:!1,error:n(e)}}}async function f(t,i,r,a){let{req:n,sessionStore:s}=t,v=Date.now(),f=await e(i.device,"press",[String(a.point.x),String(a.point.y)],n.flags?.out,t.contextFromFlags(n.flags,i.appBundleId,i.trace?.outPath))??{},_=Date.now(),p=await m(t,i),y=o({...d(r.nodes),...f,action:"dismiss-overlay",overlayAction:a.action,x:a.point.x,y:a.point.y,ref:a.ref,label:a.label,warning:a.warning,dismissed:!0,verified:p.verified,verificationRequired:!p.verified,verificationWarning:p.verificationWarning,nextCommand:p.nextCommand,...l(p.verified?"React Native overlay dismiss action sent and verified gone":"React Native overlay dismiss action sent, but verification still detects an overlay")});return c({session:i,sessionStore:s,command:n.command,positionals:n.positionals??[],flags:n.flags,result:y,responseData:y,actionStartedAt:v,actionFinishedAt:_})}async function m(e,t){let{req:i,sessionStore:r}=e;return a((await s(t,i.flags,r,e.contextFromFlags,{interactiveOnly:!0})).nodes).detected?{verified:!1,verificationWarning:"React Native overlay is still detected after dismissal. Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body.",nextCommand:"agent-device screenshot --overlay-refs"}:{verified:!0}}export{v as handleReactNativeCommands};
@@ -1,4 +1,4 @@
1
- let e,t,r,a;import{__webpack_require__ as i}from"./rslib-runtime.js";import o from"node:fs";import n from"node:path";import{createHash as s}from"node:crypto";import c from"node:os";import{setTimeout as d}from"node:timers/promises";import{fileURLToPath as l}from"node:url";import{AppError as u}from"./9152.js";import{runCmd as m}from"./9818.js";import{sleep as f}from"./4829.js";import{withDiagnosticTimer as p,emitDiagnostic as h}from"./7599.js";import{androidDeviceForSerial as w,runAndroidAdb as g}from"./8806.js";import{pullAndroidAdbFile as y}from"./9639.js";import{runXcrun as _,SessionStore as v,runIosRunnerCommand as P,errorResponse as S,isCommandSupportedOnDevice as A,ensureDeviceReady as C,resolvePublicSessionName as b,resolveImplicitSessionScope as M,resolveTargetDevice as I,IOS_RUNNER_CONTAINER_BUNDLE_IDS as x}from"./2415.js";import{resolveRecordingProvider as D}from"./recording-provider.js";import{PUBLIC_COMMANDS as R}from"./5792.js";var N={};function $(e=process.env){let t=F(),r=n.join(t,"home"),a=n.join(t,"module-cache");return o.mkdirSync(r,{recursive:!0}),o.mkdirSync(a,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:a}}async function E(e){let t=o.statSync(e.sourcePath),r=o.readFileSync(e.sourcePath),a=U(e.cacheName??n.basename(e.sourcePath,n.extname(e.sourcePath))),i=z(["2",process.platform,process.arch,n.resolve(e.sourcePath),t.size,r]),s=n.join(F(),"bin",`${a}-${i}`);return await O({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function k(e){let t=U(e.cacheName),r=z(["2",process.platform,process.arch,e.source]),a=n.join(F(),"sources",`${t}-${r}.swift`),i=n.join(F(),"bin",`${t}-${r}`);return await O({sourcePath:a,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function F(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?n.resolve(e):n.join(c.tmpdir(),"agent-device-swift-cache")}async function O(e){if(T(e.executablePath))return;let t=n.dirname(e.executablePath);o.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`;if(!await L(r,e.executablePath,e.timeoutMs??12e4))return;let a=o.mkdtempSync(n.join(t,`.${n.basename(e.executablePath)}.${process.pid}.`)),i=n.join(a,n.basename(e.executablePath));try{if(T(e.executablePath))return;void 0===e.sourceText||o.existsSync(e.sourcePath)||(o.mkdirSync(n.dirname(e.sourcePath),{recursive:!0}),o.writeFileSync(e.sourcePath,e.sourceText)),await m("xcrun",["swiftc",e.sourcePath,"-o",i],{timeoutMs:e.timeoutMs??12e4,env:$()}),o.renameSync(i,e.executablePath)}finally{o.rmSync(a,{recursive:!0,force:!0}),o.rmSync(r,{recursive:!0,force:!0})}}async function L(e,t,r){let a=Date.now()+r;for(;;){if(T(t))return!1;try{return o.mkdirSync(e),!0}catch(t){if("EEXIST"!==t.code)throw t;if(function(e,t){try{return Date.now()-o.statSync(e).mtimeMs>=t}catch{return!1}}(e,r)){o.rmSync(e,{recursive:!0,force:!0});continue}if(Date.now()>=a)throw new u("COMMAND_FAILED",`Timed out waiting for Swift cache lock: ${e} (${r}ms)`,{lockDir:e,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${e}" and retry.`});await d(25)}}}function T(e){try{return o.accessSync(e,o.constants.X_OK),o.statSync(e).isFile()}catch{return!1}}function U(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function z(e){let t=s("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}i.r(N),i.d(N,{RECORD_TRACE_COMMAND_HANDLERS:()=>e2,handleRecordTraceCommands:()=>e4});let K=`
1
+ let e,t,r,a;import{__webpack_require__ as i}from"./rslib-runtime.js";import o from"node:fs";import n from"node:path";import{createHash as s}from"node:crypto";import c from"node:os";import{setTimeout as d}from"node:timers/promises";import{fileURLToPath as l}from"node:url";import{AppError as u}from"./9152.js";import{runCmd as m}from"./9818.js";import{sleep as f}from"./4829.js";import{withDiagnosticTimer as p,emitDiagnostic as h}from"./7599.js";import{androidDeviceForSerial as w,runAndroidAdb as g}from"./8806.js";import{pullAndroidAdbFile as y}from"./9639.js";import{runXcrun as _,SessionStore as v,runIosRunnerCommand as P,errorResponse as S,isCommandSupportedOnDevice as A,ensureDeviceReady as b,resolvePublicSessionName as C,resolveImplicitSessionScope as M,resolveTargetDevice as I,IOS_RUNNER_CONTAINER_BUNDLE_IDS as x}from"./2415.js";import{resolveRecordingProvider as D}from"./recording-provider.js";var R={};function $(e=process.env){let t=k(),r=n.join(t,"home"),a=n.join(t,"module-cache");return o.mkdirSync(r,{recursive:!0}),o.mkdirSync(a,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:a}}async function N(e){let t=o.statSync(e.sourcePath),r=o.readFileSync(e.sourcePath),a=T(e.cacheName??n.basename(e.sourcePath,n.extname(e.sourcePath))),i=U(["2",process.platform,process.arch,n.resolve(e.sourcePath),t.size,r]),s=n.join(k(),"bin",`${a}-${i}`);return await F({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function E(e){let t=T(e.cacheName),r=U(["2",process.platform,process.arch,e.source]),a=n.join(k(),"sources",`${t}-${r}.swift`),i=n.join(k(),"bin",`${t}-${r}`);return await F({sourcePath:a,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function k(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?n.resolve(e):n.join(c.tmpdir(),"agent-device-swift-cache")}async function F(e){if(L(e.executablePath))return;let t=n.dirname(e.executablePath);o.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`;if(!await O(r,e.executablePath,e.timeoutMs??12e4))return;let a=o.mkdtempSync(n.join(t,`.${n.basename(e.executablePath)}.${process.pid}.`)),i=n.join(a,n.basename(e.executablePath));try{if(L(e.executablePath))return;void 0===e.sourceText||o.existsSync(e.sourcePath)||(o.mkdirSync(n.dirname(e.sourcePath),{recursive:!0}),o.writeFileSync(e.sourcePath,e.sourceText)),await m("xcrun",["swiftc",e.sourcePath,"-o",i],{timeoutMs:e.timeoutMs??12e4,env:$()}),o.renameSync(i,e.executablePath)}finally{o.rmSync(a,{recursive:!0,force:!0}),o.rmSync(r,{recursive:!0,force:!0})}}async function O(e,t,r){let a=Date.now()+r;for(;;){if(L(t))return!1;try{return o.mkdirSync(e),!0}catch(t){if("EEXIST"!==t.code)throw t;if(function(e,t){try{return Date.now()-o.statSync(e).mtimeMs>=t}catch{return!1}}(e,r)){o.rmSync(e,{recursive:!0,force:!0});continue}if(Date.now()>=a)throw new u("COMMAND_FAILED",`Timed out waiting for Swift cache lock: ${e} (${r}ms)`,{lockDir:e,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${e}" and retry.`});await d(25)}}}function L(e){try{return o.accessSync(e,o.constants.X_OK),o.statSync(e).isFile()}catch{return!1}}function T(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function U(e){let t=s("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}i.r(R),i.d(R,{handleRecordTraceCommands:()=>e1});let z=`
2
2
  import Foundation
3
3
  import AVFoundation
4
4
 
@@ -22,5 +22,5 @@ Task {
22
22
 
23
23
  semaphore.wait()
24
24
  exit(exitCode)
25
- `.trim();async function q(e,t={}){let r,a=t.pollMs??150,i=t.attempts??12,n=0;for(let t=0;t<i;t+=1){let t=0;try{t=o.statSync(e).size}catch{t=0}if(t>0&&t===r){if((n+=1)>=2)return}else n=0;r=t,await f(a)}}async function V(e){try{let t=await G(),r=await m(t,[e],{allowFailure:!0,timeoutMs:1e4,env:$()});if(0===r.exitCode)return!0;if(j(r.stderr,r.stdout))return B(e);return!1}catch(r){var t;if((t=r)instanceof u&&("TOOL_MISSING"===t.code||j(String(t.details?.stderr??""),String(t.details?.stdout??""))))return B(e);throw r}}async function G(){e??=k({source:K,cacheName:"video-validator",timeoutMs:3e4});try{return await e}catch(t){throw e=void 0,t}}async function H(e,t={}){let r=t.pollMs??150,a=t.attempts??12;for(let t=0;t<a;t+=1){if(await V(e))return;await f(r)}}function j(e,t){let r=`${e}
26
- ${t}`;return/\b(no such module ['"]AVFoundation['"]|unable to find utility ["']swiftc?["']|xcrun: error: unable to find utility ["']swiftc?["'])\b/i.test(r)}function B(e){try{let t=o.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=function(e){try{let t=o.openSync(e,"r");try{let e=o.fstatSync(t).size,r=0,a=[];for(;r+8<=e&&a.length<16;){let e=Buffer.alloc(8);if(8>o.readSync(t,e,0,8,r))break;let i=e.readUInt32BE(0),n=e.toString("latin1",4,8);if(a.push(n),1===i){let e=Buffer.alloc(8);if(8>o.readSync(t,e,0,8,r+8))break;i=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(i)||i<=0)break;r+=i}return a}finally{o.closeSync(t)}}catch{return[]}}(e);return t.includes("ftyp")&&t.includes("moov")}function W(e){let t=n.parse(e);return n.join(t.dir,`${t.name}.gesture-telemetry.json`)}function X(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function J(e){var t,r,a;let i,n,{recording:s,trimStartMs:c}=e,d=(i=W((t={videoPath:s.outPath,events:s.gestureEvents,trimStartMs:c}).videoPath),n={version:1,generatedAt:new Date().toISOString(),events:(r=t.events,(a=t.trimStartMs??0)>0?X(r.flatMap(e=>{let t=e.tMs-a,r="durationMs"in e?e.durationMs:void 0;return("number"==typeof r?t+r:t)<=0?[]:[{...e,tMs:Math.max(0,t)}]})):X(r))},o.writeFileSync(i,JSON.stringify(n,null,2)),i);return s.telemetryPath=d,d}function Z(e){let t=n.dirname(l(import.meta.url)),r=[l(new URL(`./${e}`,import.meta.url)),n.resolve(t,`../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),n.resolve(t,`../../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),n.resolve(process.cwd(),`ios-runner/AgentDeviceRunner/RecordingScripts/${e}`)];for(let e of r)if(o.existsSync(e))return e;throw new u("COMMAND_FAILED",`Missing recording helper script: ${e}`,{hint:"Ensure ios-runner/AgentDeviceRunner/RecordingScripts is present in this checkout or bundled with the package.",scriptName:e,searchedPaths:r})}async function Q(e){var t;let r,a,{videoPath:i,scriptPath:s,scriptArgs:c,commandDescription:d}=e;await q(i),await H(i);let l=(t=i,r=n.parse(t),a=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,n.join(r.dir,`.${r.name}.agent-device-${a}${r.ext||".mp4"}`));try{let e=await E({sourcePath:s});await m(e,["--input",i,"--output",l,...c],{timeoutMs:12e4,env:$()}),await H(l),o.renameSync(l,i)}catch(t){let e=t instanceof u?t:new u("COMMAND_FAILED",String(t),void 0,t instanceof Error?t:void 0);throw new u("COMMAND_FAILED",d,{...e.details,videoPath:i,script:s},e)}finally{o.rmSync(l,{force:!0})}}async function Y(e){let{videoPath:t,trimStartMs:a}=e;a>0&&await Q({videoPath:t,scriptPath:r??=Z("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(a)],commandDescription:"Failed to trim the start of the iOS recording"})}async function ee(e){let{videoPath:r,telemetryPath:a,targetLabel:i="recording"}=e;await Q({videoPath:r,scriptPath:t??=Z("recording-overlay.swift"),scriptArgs:["--events",a],commandDescription:`Failed to add touch overlays to the ${i}`})}async function et(e){let{videoPath:t,quality:r,targetLabel:i="recording"}=e;await Q({videoPath:t,scriptPath:a??=Z("recording-resize.swift"),scriptArgs:["--quality",String(r)],commandDescription:`Failed to resize the ${i}`})}function er(e){return e instanceof Error?e.message:String(e)}function ea(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function ei(e,t,r=Date.now()){let a=Math.max(0,r-t.startedAt);return a>=1e3?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(a)}ms; wait at least 1000ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function eo(e){let{recording:t,deps:r,trimStartMs:a,targetLabel:i}=e,o=J({recording:t,trimStartMs:a});if(!t.showTouches)return void h({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void h({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"no_gesture_events"}});let n=function(e=process.platform){if("darwin"!==e)return"touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry"}();if(n){t.overlayWarning??=n;return}try{await p("record_stop_overlay_export",()=>r.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:o,targetLabel:i}),{targetLabel:i,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${er(e)}`}}function en(e,t){if(1===t)return e;let r=n.parse(e),a=r.ext||".mp4";return n.join(r.dir,`${r.name}.part-${String(t).padStart(3,"0")}${a}`)}function es(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function ec(e){let{recording:t,startNextChunk:r,finishCurrentChunk:a}=e;if(t.stopping)return;let i=await a();if(i)throw Error(i);if(t.stopping)return;let o=es(t),s=o.length+1,c=await r(n.posix.dirname(t.remotePath));t.remotePath=c.remotePath,t.remotePid=c.remotePid,o.push({index:s,path:en(t.outPath,s),remotePath:c.remotePath}),t.warning??="Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks."}async function ed(e){let{recording:t,deps:r}=e;es(t).length<=1?await eo({recording:t,deps:r,targetLabel:"Android recording"}):(J({recording:t}),t.showTouches&&t.gestureEvents.length>0&&(t.overlayWarning??="touch overlay burn-in is skipped for chunked Android recordings; returning raw chunks plus gesture telemetry"))}async function el(e){for(let t of e.chunks){let r=await eu({deps:e.deps,deviceId:e.deviceId,remotePath:t.remotePath,outPath:t.path});if(r)return`failed to copy recording chunk ${t.index}: ${r}`}}async function eu(e){let t,{deps:r,deviceId:a,remotePath:i,outPath:n}=e;for(let e=0;e<2;e+=1){em(n);let s=w(a),c=await y(i,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=ea(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(h({level:"debug",phase:"record_stop_android_pull_validation",data:{deviceId:a,remotePath:i,outPath:n,attempt:e+1,fileSize:function(e){try{return o.statSync(e).size}catch{return 0}}(n),playable:t}}),t)return;h({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:a,remotePath:i,outPath:n,attempt:e+1}})}e<1&&await f(750)}return t?`failed to copy recording from device: ${t}`:(em(n),"failed to copy recording from device: pulled file is not a playable MP4")}function em(e){try{o.rmSync(e,{force:!0})}catch{}}async function ef(e,t,r){return await g(w(e),t,r)}async function ep(e,t){let r=await ef(e,["shell","ps","-o","pid=","-p",t],{allowFailure:!0});return 0===r.exitCode&&r.stdout.split(/\s+/).map(e=>e.trim()).includes(t)}async function eh(e,t){for(let r=0;r<40;r+=1){if(!await ep(e,t))return!0;await f(250)}return!await ep(e,t)}async function ew(e,t){let r,a=0;for(let i=0;i<20;i+=1){let i=await ef(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?i.stdout.trim():"";if(o.length>0&&o===r){if((a+=1)>=4)return}else a=0;r=o,await f(250)}}async function eg(e,t,r){for(let a=0;a<8;a+=1){let i=await ef(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?Number(i.stdout.trim()):NaN;if(Number.isFinite(o)&&o>0)return!0;if(!await ep(e,r))break;if(a+1>=2)return!0;await f(250)}return!1}async function ey(e){let{deviceId:t,quality:r}=e;if(void 0===r||r>=10)return;let a=await ef(t,["shell","wm","size"],{allowFailure:!0}),i=a.stdout.match(/Override size:\s*(\d+)x(\d+)/)??a.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(0!==a.exitCode||!i)throw Error(`failed to resolve Android screen size for recording quality: ${ea(a,"adb shell wm size")}`);return{width:e_(Number(i[1]),r),height:e_(Number(i[2]),r)}}function e_(e,t){return Math.max(2,2*Math.round(e*t/10/2))}async function ev(e,t){await ef(e,["shell","rm","-f",t],{allowFailure:!0})}async function eP(e,t){let r=await ef(e,["shell","kill","-9",t],{allowFailure:!0});return h({level:"warn",phase:"record_stop_android_force_signal",data:{deviceId:e,remotePid:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),!(0!==r.exitCode&&await ep(e,t))&&await eh(e,t)}async function eS(e){var t;let r,a,{device:i,recordingSize:o,preferredRemoteDir:n}=e,s="failed to start recording: Android screenrecord did not begin producing frames";for(let e of(t=Date.now(),r=`agent-device-recording-${t}.mp4`,a=["/sdcard","/data/local/tmp"],(n&&a.includes(n)?[n,...a.filter(e=>e!==n)]:a).map(e=>`${e}/${r}`))){let t=await ef(i.id,["shell",function(e,t){let r=["screenrecord"];return t&&r.push("--size",`${t.width}x${t.height}`),r.push(e),`${r.join(" ")} >/dev/null 2>&1 & echo $!`}(e,o)],{allowFailure:!0});if(0!==t.exitCode){s=`failed to start recording: ${ea(t,"adb shell screenrecord")}`;continue}let r=t.stdout.split(/\r?\n/).map(e=>e.trim()).filter(e=>/^\d+$/.test(e)).at(-1);if(!r){s="failed to start recording: adb did not return a valid Android screenrecord pid",await ev(i.id,e);continue}if(h({level:"debug",phase:"record_start_android_started",data:{deviceId:i.id,remotePath:e,remotePid:r}}),await eg(i.id,e,r))return{remotePath:e,remotePid:r,startedAt:Date.now()};s="failed to start recording: Android screenrecord did not begin producing frames",await eP(i.id,r),await ev(i.id,e)}return{error:S("COMMAND_FAILED",s)}}async function eA(e){let t,{device:r,recordingBase:a}=e;try{t=await ey({deviceId:r.id,quality:a.quality})}catch(e){return S("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let i=await eS({device:r,recordingSize:t});if("error"in i)return i.error;let o={platform:"android",remotePath:i.remotePath,remotePid:i.remotePid,chunks:[{index:1,path:a.outPath,remotePath:i.remotePath}],...a,startedAt:i.startedAt};return!function e(t){let{recording:r,startNextChunk:a,finishCurrentChunk:i}=t,o=setTimeout(()=>{r.rotationPromise=ec({recording:r,startNextChunk:a,finishCurrentChunk:i}).catch(e=>{r.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{r.rotationPromise=void 0,r.stopping||r.rotationFailedReason||e({recording:r,startNextChunk:a,finishCurrentChunk:i})})},17e4);o.unref?.(),r.rotationTimer=o}({recording:o,finishCurrentChunk:async()=>await eC({device:r,recording:o,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let a=await eS({device:r,recordingSize:t,preferredRemoteDir:e});if("error"in a)throw Error(a.error.ok?"failed to start next Android recording chunk":a.error.error.message);return a}}),o}async function eC(e){let{device:t,recording:r,waitForRemoteFileStability:a=!0}=e;await ep(t.id,r.remotePid)||(r.warning??=function(e){if(!(Date.now()-e.startedAt<178e3))return"Android adb screenrecord stopped before record stop, likely after reaching the 180s platform limit. The MP4 may be truncated; final interactions after the limit are not in the video."}(r));let i=await ef(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(h({level:"debug",phase:"record_stop_android_signal",data:{deviceId:t.id,remotePath:r.remotePath,remotePid:r.remotePid,exitCode:i.exitCode,stdout:i.stdout.trim(),stderr:i.stderr.trim()}}),0!==i.exitCode)return await eb(t.id,r.remotePid,i);let o=await eM(t.id,r.remotePid);if(o)return o;a&&await ew(t.id,r.remotePath)}async function eb(e,t,r){if(await ep(e,t)&&!await eP(e,t))return`failed to stop recording: ${ea(r,"adb shell kill")}`}async function eM(e,t){if(!await eh(e,t)&&!await eP(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function eI(e){let t,{deps:r,device:a,recording:i,stopRequestedAt:o}=e;h({level:"debug",phase:"record_stop_android_enter",data:{deviceId:a.id,remotePath:i.remotePath,remotePid:i.remotePid}}),i.stopping=!0,i.rotationTimer&&(clearTimeout(i.rotationTimer),i.rotationTimer=void 0),await i.rotationPromise;let n=await eC({device:a,recording:i});if(i.rotationFailedReason&&!n&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`),!n){let e=await el({deps:r,deviceId:a.id,chunks:es(i)});if(e)return await s(),S("COMMAND_FAILED",ex(e,i,o));await ed({recording:i,deps:r})}if(await s(),n)return S("COMMAND_FAILED",ex(n,i,o));if(t)return S("COMMAND_FAILED",t);return null;async function s(){for(let e of es(i)){let r=await ef(a.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});h({level:"debug",phase:"record_stop_android_cleanup",data:{deviceId:a.id,remotePath:e.remotePath,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),0===r.exitCode||n||(t=`failed to clean up remote recording: ${ea(r,"adb shell rm")}`)}}}function ex(e,t,r){return ei(e,t,r).message}function eD(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function eR(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath,requestId:e.meta?.requestId}}async function eN(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=eD(r);try{await o.runIosRunnerCommand(a,{command:"recordStop",appBundleId:n},eR(t,i,r))}catch(e){h({level:"warn",phase:"record_stop_runner_failed",data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:r.name,error:er(e)}})}}async function e$(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=eD(r);if(n)try{await o.runIosRunnerCommand(a,{command:"snapshot",appBundleId:n,interactiveOnly:!0,compact:!0,depth:1},eR(t,i,r))}catch(e){h({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:a.id,session:r.name,appBundleId:n,error:er(e)}})}}async function eE(e){let t,r,{req:a,activeSession:i,sessionStore:o,device:n,logPath:s,deps:c,fpsFlag:d,recordingBase:l,appBundleId:u}=e,m=`agent-device-recording-${Date.now()}.mp4`,f=`tmp/${m}`,p=eR(a,s,i),w=async()=>c.runIosRunnerCommand(n,{command:"recordStart",outPath:m,fps:d,quality:l.quality,appBundleId:u},p);try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(a){var g,y;if(!er(a).toLowerCase().includes("recording already in progress"))return S("COMMAND_FAILED",`failed to start recording: ${er(a)}`);h({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:i.name,error:er(a)}});let e=(g=n.id,y=i.name,o.toArray().find(e=>e.name!==y&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===g&&e.recording?.platform==="ios-device-runner"));if(e)return S("COMMAND_FAILED",`failed to start recording: recording already in progress in session '${e.name}'`);try{await c.runIosRunnerCommand(n,{command:"recordStop",appBundleId:u},p)}catch{}try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(e){return S("COMMAND_FAILED",`failed to start recording: ${er(e)}`)}}return{platform:"ios-device-runner",remotePath:f,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...l}}async function ek(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}=e;try{await o.runIosRunnerCommand(a,{command:"recordStart",outPath:s.outPath,fps:n,quality:s.quality,appBundleId:c},eR(t,i,r))}catch(e){return S("COMMAND_FAILED",`failed to start recording: ${er(e)}`)}return{platform:"macos-runner",...s}}async function eF(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;await eN({req:t,activeSession:r,device:a,logPath:i,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of x)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",a.id,"--source",n.remotePath,"--destination",n.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(0!==s.exitCode){let e=s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`;return S("COMMAND_FAILED",`failed to copy recording from device: ${e}`)}let c="number"!=typeof n.runnerStartedAtUptimeMs||"number"!=typeof n.targetAppReadyUptimeMs?0:Math.max(0,n.targetAppReadyUptimeMs-n.runnerStartedAtUptimeMs);return c>0&&await o.trimRecordingStart({videoPath:n.outPath,trimStartMs:c}),await eo({recording:n,deps:o,trimStartMs:c,targetLabel:"iOS recording"}),null}async function eO(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;return await eN({req:t,activeSession:r,device:a,logPath:i,deps:o}),await eo({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eL(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let a=await eT(r.wait,5e3);return a||(await eU(t,r,"SIGINT"),(a=await eT(r.wait,2e3))||(r.child.kill("SIGTERM"),await eU(t,r,"SIGTERM"),a=await eT(r.wait,2e3)))?a:(r.child.kill("SIGKILL"),await eU(t,r,"SIGKILL"),await eT(r.wait,2e3))}async function eT(e,t){return await Promise.race([e,f(t).then(()=>null)])}async function eU(e,t,r){await eK(e,t,r)||await ez(e,t.outPath,r)}async function ez(e,t,r){let a,i=`simctl.*recordVideo.*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`;try{a=await e.runCmd("pgrep",["-f",i],{allowFailure:!0})}catch(e){h({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:er(e)}});return}let o=eV(eH(a.stdout)),n=eG(o,r);h({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_recorders",data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:n,pgrepExitCode:a.exitCode}})}async function eK(e,t,r){let a=t.recorderPid??t.child.pid;if("number"!=typeof a||!Number.isInteger(a)||a<=0)return h({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let i=await eq(e,a,t.outPath,r),o=eV([a,...i.pids]),n=eG(o,r);return h({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_owned_recorder",data:{outPath:t.outPath,signal:r,recorderPid:a,childPidCount:i.pids.length,matchedPidCount:o.length,signaled:n,pgrepExitCode:i.exitCode}}),n>0}async function eq(e,t,r,a){let i;try{i=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return h({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:a,parentPid:t,error:er(e)}}),{pids:[]}}return{pids:eH(i.stdout),exitCode:i.exitCode}}function eV(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eG(e,t){let r=0;for(let a of e)try{process.kill(a,t),r+=1}catch{}return r}function eH(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}async function ej(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await f(350)}async function eB(e){for(let t=0;t<2;t+=1){try{if(o.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)break;await f(250)}return Date.now()}async function eW(e){let t,r,{req:a,activeSession:i,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e;c.showTouches&&await e$({req:a,activeSession:i,device:o,logPath:n,deps:s});let{child:l,wait:u}=s.startIosSimulatorRecording({device:o,outPath:d}),m=await eB(d);if(c.showTouches)try{let e=Date.now(),c=await s.runIosRunnerCommand(o,{command:"uptime",appBundleId:eD(i)},eR(a,n,i)),d=Date.now();t=Math.round((e+d)/2),r="number"==typeof c.currentUptimeMs?c.currentUptimeMs:void 0}catch{}return{platform:"ios",child:l,wait:u,...c,recorderPid:l.pid,startedAt:m,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function eX(e){let t,{req:r,sessionName:a,sessionStore:i,activeSession:s,device:c,logPath:d,deps:l}=e;if(s.recording)return S("INVALID_ARGS","recording already in progress");let u=r.flags?.fps,m=r.flags?.quality;if(void 0!==u&&(!Number.isInteger(u)||u<1||u>120))return S("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==m&&(!Number.isInteger(m)||m<5||m>10))return S("INVALID_ARGS","quality must be an integer between 5 and 10");if(!A("record",c))return S("UNSUPPORTED_OPERATION","record is not supported on this device");let f=r.positionals?.[1]??`./recording-${Date.now()}.mp4`,p=v.expandHome(f,r.meta?.cwd),h={outPath:p,clientOutPath:r.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),quality:r.flags?.quality,showTouches:r.flags?.hideTouches!==!0,gestureEvents:[]};if(o.mkdirSync(n.dirname(p),{recursive:!0}),o.rmSync(p,{force:!0}),"ios"===c.platform&&"device"===c.kind){let e=eD(s);if(!e)return S("INVALID_ARGS","record on physical iOS devices requires an active app session; run open <app> first");t=await eE({req:r,activeSession:s,sessionStore:i,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:h,appBundleId:e})}else if("macos"===c.platform){let e=eD(s);if(!e)return S("INVALID_ARGS","record on macOS requires an active app session; run open <app> first");t=await ek({req:r,activeSession:s,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:h,appBundleId:e})}else t="ios"===c.platform?await eW({req:r,activeSession:s,device:c,logPath:d,deps:l,recordingBase:h,resolvedOut:p}):await eA({device:c,recordingBase:h});if("ok"in t)return t;s.recording=t,i.set(a,s);let w=i.ensureSessionDir(a);return i.recordAction(s,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:{action:"start",showTouches:t.showTouches}}),{ok:!0,data:{recording:"started",outPath:t.clientOutPath??f,sessionStateDir:w,showTouches:t.showTouches}}}async function eJ(e){let{deps:t,device:r,recording:a,stopRequestedAt:i}=e;if("android"===a.platform)return await eI({deps:t,device:r,recording:a,stopRequestedAt:i});await p("record_stop_tail_settle",()=>t.waitForRecordingTail(a),{platform:a.platform,gestureEventCount:a.gestureEvents.length});let o=await p("record_stop_ios_simulator_process",()=>eL({deps:t,recording:a}),{outPath:a.outPath});if(!o)return eZ("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",a,i);if(0!==o.exitCode)return eZ(`failed to stop recording: ${ea(o,"simctl recordVideo")}`,a,i);if(await p("record_stop_video_stable",()=>t.waitForStableFile(a.outPath,{pollMs:150,attempts:12}),{outPath:a.outPath}),!await p("record_stop_video_playable_check",()=>t.isPlayableVideo(a.outPath),{outPath:a.outPath}))return eZ(`failed to stop recording: ${a.outPath} was not finalized into a playable video`,a,i);if(void 0!==a.quality&&a.quality<10){let e=a.quality;try{await p("record_stop_resize",()=>t.resizeRecording({videoPath:a.outPath,quality:e,targetLabel:"iOS recording"}),{outPath:a.outPath,quality:e})}catch(e){a.overlayWarning=`failed to resize recording: ${er(e)}`}}return await p("record_stop_finalize_overlay",()=>eo({recording:a,deps:t,targetLabel:"iOS recording"}),{outPath:a.outPath,showTouches:a.showTouches,gestureEventCount:a.gestureEvents.length}),null}function eZ(e,t,r){let a=ei(e,t,r);return function(e){try{o.rmSync(e,{force:!0})}catch{}}(t.outPath),S("COMMAND_FAILED",a.message)}async function eQ(e){var t;let r,a,{req:i,activeSession:o,device:s,logPath:c,deps:d}=e;if(!o.recording)return S("INVALID_ARGS","no active recording");let l=o.recording,u=Date.now(),m=l.invalidatedReason;o.recording=void 0;let f="ios-device-runner"===l.platform?await eF({req:i,activeSession:o,device:s,logPath:c,deps:d,recording:l}):"macos-runner"===l.platform?await eO({req:i,activeSession:o,device:s,logPath:c,deps:d,recording:l}):await eJ({deps:d,device:s,recording:l,stopRequestedAt:u});if(f)return f;if(m&&"ios"===l.platform&&l.showTouches)l.overlayWarning??=`overlay unavailable: ${m}`;else if(m)return S("COMMAND_FAILED",m);return r="android"===(t=l).platform?t.chunks:void 0,a=[{field:"outPath",path:t.outPath,localPath:t.clientOutPath,fileName:n.basename(t.clientOutPath??t.outPath)}],r&&r.length>1&&a.push(...r.slice(1).map(e=>({field:"chunkPath",path:e.path,localPath:eY(t,e.index),fileName:n.basename(eY(t,e.index)??e.path)}))),t.telemetryPath&&a.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return W(e.clientOutPath)}(t),fileName:n.basename(t.telemetryPath)}),{ok:!0,data:{recording:"stopped",outPath:t.outPath,telemetryPath:t.telemetryPath,artifacts:a,showTouches:t.showTouches,warning:t.warning,overlayWarning:t.overlayWarning,chunks:r?.map(e=>({index:e.index,path:eY(t,e.index)??e.path}))}}}function eY(e,t){if("android"===e.platform&&e.clientOutPath)return en(e.clientOutPath,t)}function e0(e,t,r,a={}){r.recordOnlySession&&(a.writeLog&&e.writeSessionLog(r),e.delete(t))}async function e1(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await _(t,r):await m(e,t,r),startIosSimulatorRecording:e=>D().startIosSimulatorRecording(e),runIosRunnerCommand:P,waitForRecordingTail:ej,waitForStableFile:q,isPlayableVideo:V,trimRecordingStart:Y,resizeRecording:et,overlayRecordingTouches:ee},n=a.get(r),s=n?.device??await I(t.flags??{});n||await C(s);let c=n??{name:b(t),sessionScope:M(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return S("INVALID_ARGS","record requires start|stop");if("start"===d)return eX({req:t,sessionName:r,sessionStore:a,activeSession:c,device:s,logPath:i,deps:o});let l=await eQ({req:t,activeSession:c,device:s,logPath:i,deps:o});return l.ok?(a.recordAction(c,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:l.data?.outPath,showTouches:l.data?.showTouches}}),e0(a,r,c,{writeLog:!0})):e0(a,r,c),l}let e2={[R.record]:!0,[R.trace]:!0};async function e4(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,s=t.command;if("record"===s)return e1({req:t,sessionName:r,sessionStore:a,logPath:i});if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return S("INVALID_ARGS","trace requires start|stop");let i=a.get(r);if(!i)return S("SESSION_NOT_FOUND","No active session");if("start"===e){if(i.trace)return S("INVALID_ARGS","trace already in progress");let e=t.positionals?.[1]??a.defaultTracePath(i),r=v.expandHome(e);return o.mkdirSync(n.dirname(r),{recursive:!0}),o.appendFileSync(r,""),i.trace={outPath:r,startedAt:Date.now()},a.recordAction(i,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!i.trace)return S("INVALID_ARGS","no active trace");let c=i.trace.outPath;if(t.positionals?.[1]){let e=v.expandHome(t.positionals[1]);o.mkdirSync(n.dirname(e),{recursive:!0}),o.existsSync(c)?o.renameSync(c,e):o.appendFileSync(e,""),c=e}return i.trace=void 0,a.recordAction(i,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:c}}),{ok:!0,data:{trace:"stopped",outPath:c}}}return null}export{N as record_trace_namespaceObject};
25
+ `.trim();async function q(e,t={}){let r,a=t.pollMs??150,i=t.attempts??12,n=0;for(let t=0;t<i;t+=1){let t=0;try{t=o.statSync(e).size}catch{t=0}if(t>0&&t===r){if((n+=1)>=2)return}else n=0;r=t,await f(a)}}async function K(e){try{let t=await V(),r=await m(t,[e],{allowFailure:!0,timeoutMs:1e4,env:$()});if(0===r.exitCode)return!0;if(H(r.stderr,r.stdout))return j(e);return!1}catch(r){var t;if((t=r)instanceof u&&("TOOL_MISSING"===t.code||H(String(t.details?.stderr??""),String(t.details?.stdout??""))))return j(e);throw r}}async function V(){e??=E({source:z,cacheName:"video-validator",timeoutMs:3e4});try{return await e}catch(t){throw e=void 0,t}}async function G(e,t={}){let r=t.pollMs??150,a=t.attempts??12;for(let t=0;t<a;t+=1){if(await K(e))return;await f(r)}}function H(e,t){let r=`${e}
26
+ ${t}`;return/\b(no such module ['"]AVFoundation['"]|unable to find utility ["']swiftc?["']|xcrun: error: unable to find utility ["']swiftc?["'])\b/i.test(r)}function j(e){try{let t=o.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=function(e){try{let t=o.openSync(e,"r");try{let e=o.fstatSync(t).size,r=0,a=[];for(;r+8<=e&&a.length<16;){let e=Buffer.alloc(8);if(8>o.readSync(t,e,0,8,r))break;let i=e.readUInt32BE(0),n=e.toString("latin1",4,8);if(a.push(n),1===i){let e=Buffer.alloc(8);if(8>o.readSync(t,e,0,8,r+8))break;i=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(i)||i<=0)break;r+=i}return a}finally{o.closeSync(t)}}catch{return[]}}(e);return t.includes("ftyp")&&t.includes("moov")}function B(e){let t=n.parse(e);return n.join(t.dir,`${t.name}.gesture-telemetry.json`)}function W(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function X(e){var t,r,a;let i,n,{recording:s,trimStartMs:c}=e,d=(i=B((t={videoPath:s.outPath,events:s.gestureEvents,trimStartMs:c}).videoPath),n={version:1,generatedAt:new Date().toISOString(),events:(r=t.events,(a=t.trimStartMs??0)>0?W(r.flatMap(e=>{let t=e.tMs-a,r="durationMs"in e?e.durationMs:void 0;return("number"==typeof r?t+r:t)<=0?[]:[{...e,tMs:Math.max(0,t)}]})):W(r))},o.writeFileSync(i,JSON.stringify(n,null,2)),i);return s.telemetryPath=d,d}function J(e){let t=n.dirname(l(import.meta.url)),r=[l(new URL(`./${e}`,import.meta.url)),n.resolve(t,`../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),n.resolve(t,`../../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),n.resolve(process.cwd(),`ios-runner/AgentDeviceRunner/RecordingScripts/${e}`)];for(let e of r)if(o.existsSync(e))return e;throw new u("COMMAND_FAILED",`Missing recording helper script: ${e}`,{hint:"Ensure ios-runner/AgentDeviceRunner/RecordingScripts is present in this checkout or bundled with the package.",scriptName:e,searchedPaths:r})}async function Z(e){var t;let r,a,{videoPath:i,scriptPath:s,scriptArgs:c,commandDescription:d}=e;await q(i),await G(i);let l=(t=i,r=n.parse(t),a=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,n.join(r.dir,`.${r.name}.agent-device-${a}${r.ext||".mp4"}`));try{let e=await N({sourcePath:s});await m(e,["--input",i,"--output",l,...c],{timeoutMs:12e4,env:$()}),await G(l),o.renameSync(l,i)}catch(t){let e=t instanceof u?t:new u("COMMAND_FAILED",String(t),void 0,t instanceof Error?t:void 0);throw new u("COMMAND_FAILED",d,{...e.details,videoPath:i,script:s},e)}finally{o.rmSync(l,{force:!0})}}async function Q(e){let{videoPath:t,trimStartMs:a}=e;a>0&&await Z({videoPath:t,scriptPath:r??=J("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(a)],commandDescription:"Failed to trim the start of the iOS recording"})}async function Y(e){let{videoPath:r,telemetryPath:a,targetLabel:i="recording"}=e;await Z({videoPath:r,scriptPath:t??=J("recording-overlay.swift"),scriptArgs:["--events",a],commandDescription:`Failed to add touch overlays to the ${i}`})}async function ee(e){let{videoPath:t,quality:r,targetLabel:i="recording"}=e;await Z({videoPath:t,scriptPath:a??=J("recording-resize.swift"),scriptArgs:["--quality",String(r)],commandDescription:`Failed to resize the ${i}`})}function et(e){return e instanceof Error?e.message:String(e)}function er(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function ea(e,t,r=Date.now()){let a=Math.max(0,r-t.startedAt);return a>=1e3?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(a)}ms; wait at least 1000ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function ei(e){let{recording:t,deps:r,trimStartMs:a,targetLabel:i}=e,o=X({recording:t,trimStartMs:a});if(!t.showTouches)return void h({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void h({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"no_gesture_events"}});let n=function(e=process.platform){if("darwin"!==e)return"touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry"}();if(n){t.overlayWarning??=n;return}try{await p("record_stop_overlay_export",()=>r.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:o,targetLabel:i}),{targetLabel:i,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${et(e)}`}}function eo(e,t){if(1===t)return e;let r=n.parse(e),a=r.ext||".mp4";return n.join(r.dir,`${r.name}.part-${String(t).padStart(3,"0")}${a}`)}function en(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function es(e){let{recording:t,startNextChunk:r,finishCurrentChunk:a}=e;if(t.stopping)return;let i=await a();if(i)throw Error(i);if(t.stopping)return;let o=en(t),s=o.length+1,c=await r(n.posix.dirname(t.remotePath));t.remotePath=c.remotePath,t.remotePid=c.remotePid,o.push({index:s,path:eo(t.outPath,s),remotePath:c.remotePath}),t.warning??="Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks."}async function ec(e){let{recording:t,deps:r}=e;en(t).length<=1?await ei({recording:t,deps:r,targetLabel:"Android recording"}):(X({recording:t}),t.showTouches&&t.gestureEvents.length>0&&(t.overlayWarning??="touch overlay burn-in is skipped for chunked Android recordings; returning raw chunks plus gesture telemetry"))}async function ed(e){for(let t of e.chunks){let r=await el({deps:e.deps,deviceId:e.deviceId,remotePath:t.remotePath,outPath:t.path});if(r)return`failed to copy recording chunk ${t.index}: ${r}`}}async function el(e){let t,{deps:r,deviceId:a,remotePath:i,outPath:n}=e;for(let e=0;e<2;e+=1){eu(n);let s=w(a),c=await y(i,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=er(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(h({level:"debug",phase:"record_stop_android_pull_validation",data:{deviceId:a,remotePath:i,outPath:n,attempt:e+1,fileSize:function(e){try{return o.statSync(e).size}catch{return 0}}(n),playable:t}}),t)return;h({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:a,remotePath:i,outPath:n,attempt:e+1}})}e<1&&await f(750)}return t?`failed to copy recording from device: ${t}`:(eu(n),"failed to copy recording from device: pulled file is not a playable MP4")}function eu(e){try{o.rmSync(e,{force:!0})}catch{}}async function em(e,t,r){return await g(w(e),t,r)}async function ef(e,t){let r=await em(e,["shell","ps","-o","pid=","-p",t],{allowFailure:!0});return 0===r.exitCode&&r.stdout.split(/\s+/).map(e=>e.trim()).includes(t)}async function ep(e,t){for(let r=0;r<40;r+=1){if(!await ef(e,t))return!0;await f(250)}return!await ef(e,t)}async function eh(e,t){let r,a=0;for(let i=0;i<20;i+=1){let i=await em(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?i.stdout.trim():"";if(o.length>0&&o===r){if((a+=1)>=4)return}else a=0;r=o,await f(250)}}async function ew(e,t,r){for(let a=0;a<8;a+=1){let i=await em(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?Number(i.stdout.trim()):NaN;if(Number.isFinite(o)&&o>0)return!0;if(!await ef(e,r))break;if(a+1>=2)return!0;await f(250)}return!1}async function eg(e){let{deviceId:t,quality:r}=e;if(void 0===r||r>=10)return;let a=await em(t,["shell","wm","size"],{allowFailure:!0}),i=a.stdout.match(/Override size:\s*(\d+)x(\d+)/)??a.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(0!==a.exitCode||!i)throw Error(`failed to resolve Android screen size for recording quality: ${er(a,"adb shell wm size")}`);return{width:ey(Number(i[1]),r),height:ey(Number(i[2]),r)}}function ey(e,t){return Math.max(2,2*Math.round(e*t/10/2))}async function e_(e,t){await em(e,["shell","rm","-f",t],{allowFailure:!0})}async function ev(e,t){let r=await em(e,["shell","kill","-9",t],{allowFailure:!0});return h({level:"warn",phase:"record_stop_android_force_signal",data:{deviceId:e,remotePid:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),!(0!==r.exitCode&&await ef(e,t))&&await ep(e,t)}async function eP(e){var t;let r,a,{device:i,recordingSize:o,preferredRemoteDir:n}=e,s="failed to start recording: Android screenrecord did not begin producing frames";for(let e of(t=Date.now(),r=`agent-device-recording-${t}.mp4`,a=["/sdcard","/data/local/tmp"],(n&&a.includes(n)?[n,...a.filter(e=>e!==n)]:a).map(e=>`${e}/${r}`))){let t=await em(i.id,["shell",function(e,t){let r=["screenrecord"];return t&&r.push("--size",`${t.width}x${t.height}`),r.push(e),`${r.join(" ")} >/dev/null 2>&1 & echo $!`}(e,o)],{allowFailure:!0});if(0!==t.exitCode){s=`failed to start recording: ${er(t,"adb shell screenrecord")}`;continue}let r=t.stdout.split(/\r?\n/).map(e=>e.trim()).filter(e=>/^\d+$/.test(e)).at(-1);if(!r){s="failed to start recording: adb did not return a valid Android screenrecord pid",await e_(i.id,e);continue}if(h({level:"debug",phase:"record_start_android_started",data:{deviceId:i.id,remotePath:e,remotePid:r}}),await ew(i.id,e,r))return{remotePath:e,remotePid:r,startedAt:Date.now()};s="failed to start recording: Android screenrecord did not begin producing frames",await ev(i.id,r),await e_(i.id,e)}return{error:S("COMMAND_FAILED",s)}}async function eS(e){let t,{device:r,recordingBase:a}=e;try{t=await eg({deviceId:r.id,quality:a.quality})}catch(e){return S("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let i=await eP({device:r,recordingSize:t});if("error"in i)return i.error;let o={platform:"android",remotePath:i.remotePath,remotePid:i.remotePid,chunks:[{index:1,path:a.outPath,remotePath:i.remotePath}],...a,startedAt:i.startedAt};return!function e(t){let{recording:r,startNextChunk:a,finishCurrentChunk:i}=t,o=setTimeout(()=>{r.rotationPromise=es({recording:r,startNextChunk:a,finishCurrentChunk:i}).catch(e=>{r.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{r.rotationPromise=void 0,r.stopping||r.rotationFailedReason||e({recording:r,startNextChunk:a,finishCurrentChunk:i})})},17e4);o.unref?.(),r.rotationTimer=o}({recording:o,finishCurrentChunk:async()=>await eA({device:r,recording:o,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let a=await eP({device:r,recordingSize:t,preferredRemoteDir:e});if("error"in a)throw Error(a.error.ok?"failed to start next Android recording chunk":a.error.error.message);return a}}),o}async function eA(e){let{device:t,recording:r,waitForRemoteFileStability:a=!0}=e;await ef(t.id,r.remotePid)||(r.warning??=function(e){if(!(Date.now()-e.startedAt<178e3))return"Android adb screenrecord stopped before record stop, likely after reaching the 180s platform limit. The MP4 may be truncated; final interactions after the limit are not in the video."}(r));let i=await em(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(h({level:"debug",phase:"record_stop_android_signal",data:{deviceId:t.id,remotePath:r.remotePath,remotePid:r.remotePid,exitCode:i.exitCode,stdout:i.stdout.trim(),stderr:i.stderr.trim()}}),0!==i.exitCode)return await eb(t.id,r.remotePid,i);let o=await eC(t.id,r.remotePid);if(o)return o;a&&await eh(t.id,r.remotePath)}async function eb(e,t,r){if(await ef(e,t)&&!await ev(e,t))return`failed to stop recording: ${er(r,"adb shell kill")}`}async function eC(e,t){if(!await ep(e,t)&&!await ev(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function eM(e){let t,{deps:r,device:a,recording:i,stopRequestedAt:o}=e;h({level:"debug",phase:"record_stop_android_enter",data:{deviceId:a.id,remotePath:i.remotePath,remotePid:i.remotePid}}),i.stopping=!0,i.rotationTimer&&(clearTimeout(i.rotationTimer),i.rotationTimer=void 0),await i.rotationPromise;let n=await eA({device:a,recording:i});if(i.rotationFailedReason&&!n&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`),!n){let e=await ed({deps:r,deviceId:a.id,chunks:en(i)});if(e)return await s(),S("COMMAND_FAILED",eI(e,i,o));await ec({recording:i,deps:r})}if(await s(),n)return S("COMMAND_FAILED",eI(n,i,o));if(t)return S("COMMAND_FAILED",t);return null;async function s(){for(let e of en(i)){let r=await em(a.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});h({level:"debug",phase:"record_stop_android_cleanup",data:{deviceId:a.id,remotePath:e.remotePath,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),0===r.exitCode||n||(t=`failed to clean up remote recording: ${er(r,"adb shell rm")}`)}}}function eI(e,t,r){return ea(e,t,r).message}function ex(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function eD(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath,requestId:e.meta?.requestId}}async function eR(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=ex(r);try{await o.runIosRunnerCommand(a,{command:"recordStop",appBundleId:n},eD(t,i,r))}catch(e){h({level:"warn",phase:"record_stop_runner_failed",data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:r.name,error:et(e)}})}}async function e$(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=ex(r);if(n)try{await o.runIosRunnerCommand(a,{command:"snapshot",appBundleId:n,interactiveOnly:!0,compact:!0,depth:1},eD(t,i,r))}catch(e){h({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:a.id,session:r.name,appBundleId:n,error:et(e)}})}}async function eN(e){let t,r,{req:a,activeSession:i,sessionStore:o,device:n,logPath:s,deps:c,fpsFlag:d,recordingBase:l,appBundleId:u}=e,m=`agent-device-recording-${Date.now()}.mp4`,f=`tmp/${m}`,p=eD(a,s,i),w=async()=>c.runIosRunnerCommand(n,{command:"recordStart",outPath:m,fps:d,quality:l.quality,appBundleId:u},p);try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(a){var g,y;if(!et(a).toLowerCase().includes("recording already in progress"))return S("COMMAND_FAILED",`failed to start recording: ${et(a)}`);h({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:i.name,error:et(a)}});let e=(g=n.id,y=i.name,o.toArray().find(e=>e.name!==y&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===g&&e.recording?.platform==="ios-device-runner"));if(e)return S("COMMAND_FAILED",`failed to start recording: recording already in progress in session '${e.name}'`);try{await c.runIosRunnerCommand(n,{command:"recordStop",appBundleId:u},p)}catch{}try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(e){return S("COMMAND_FAILED",`failed to start recording: ${et(e)}`)}}return{platform:"ios-device-runner",remotePath:f,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...l}}async function eE(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}=e;try{await o.runIosRunnerCommand(a,{command:"recordStart",outPath:s.outPath,fps:n,quality:s.quality,appBundleId:c},eD(t,i,r))}catch(e){return S("COMMAND_FAILED",`failed to start recording: ${et(e)}`)}return{platform:"macos-runner",...s}}async function ek(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;await eR({req:t,activeSession:r,device:a,logPath:i,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of x)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",a.id,"--source",n.remotePath,"--destination",n.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(0!==s.exitCode){let e=s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`;return S("COMMAND_FAILED",`failed to copy recording from device: ${e}`)}let c="number"!=typeof n.runnerStartedAtUptimeMs||"number"!=typeof n.targetAppReadyUptimeMs?0:Math.max(0,n.targetAppReadyUptimeMs-n.runnerStartedAtUptimeMs);return c>0&&await o.trimRecordingStart({videoPath:n.outPath,trimStartMs:c}),await ei({recording:n,deps:o,trimStartMs:c,targetLabel:"iOS recording"}),null}async function eF(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;return await eR({req:t,activeSession:r,device:a,logPath:i,deps:o}),await ei({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eO(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let a=await eL(r.wait,5e3);return a||(await eT(t,r,"SIGINT"),(a=await eL(r.wait,2e3))||(r.child.kill("SIGTERM"),await eT(t,r,"SIGTERM"),a=await eL(r.wait,2e3)))?a:(r.child.kill("SIGKILL"),await eT(t,r,"SIGKILL"),await eL(r.wait,2e3))}async function eL(e,t){return await Promise.race([e,f(t).then(()=>null)])}async function eT(e,t,r){await ez(e,t,r)||await eU(e,t.outPath,r)}async function eU(e,t,r){let a,i=`simctl.*recordVideo.*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`;try{a=await e.runCmd("pgrep",["-f",i],{allowFailure:!0})}catch(e){h({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:et(e)}});return}let o=eK(eG(a.stdout)),n=eV(o,r);h({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_recorders",data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:n,pgrepExitCode:a.exitCode}})}async function ez(e,t,r){let a=t.recorderPid??t.child.pid;if("number"!=typeof a||!Number.isInteger(a)||a<=0)return h({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let i=await eq(e,a,t.outPath,r),o=eK([a,...i.pids]),n=eV(o,r);return h({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_owned_recorder",data:{outPath:t.outPath,signal:r,recorderPid:a,childPidCount:i.pids.length,matchedPidCount:o.length,signaled:n,pgrepExitCode:i.exitCode}}),n>0}async function eq(e,t,r,a){let i;try{i=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return h({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:a,parentPid:t,error:et(e)}}),{pids:[]}}return{pids:eG(i.stdout),exitCode:i.exitCode}}function eK(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eV(e,t){let r=0;for(let a of e)try{process.kill(a,t),r+=1}catch{}return r}function eG(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}async function eH(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await f(350)}async function ej(e){for(let t=0;t<2;t+=1){try{if(o.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)break;await f(250)}return Date.now()}async function eB(e){let t,r,{req:a,activeSession:i,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e;c.showTouches&&await e$({req:a,activeSession:i,device:o,logPath:n,deps:s});let{child:l,wait:u}=s.startIosSimulatorRecording({device:o,outPath:d}),m=await ej(d);if(c.showTouches)try{let e=Date.now(),c=await s.runIosRunnerCommand(o,{command:"uptime",appBundleId:ex(i)},eD(a,n,i)),d=Date.now();t=Math.round((e+d)/2),r="number"==typeof c.currentUptimeMs?c.currentUptimeMs:void 0}catch{}return{platform:"ios",child:l,wait:u,...c,recorderPid:l.pid,startedAt:m,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function eW(e){let t,{req:r,sessionName:a,sessionStore:i,activeSession:s,device:c,logPath:d,deps:l}=e;if(s.recording)return S("INVALID_ARGS","recording already in progress");let u=r.flags?.fps,m=r.flags?.quality;if(void 0!==u&&(!Number.isInteger(u)||u<1||u>120))return S("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==m&&(!Number.isInteger(m)||m<5||m>10))return S("INVALID_ARGS","quality must be an integer between 5 and 10");if(!A("record",c))return S("UNSUPPORTED_OPERATION","record is not supported on this device");let f=r.positionals?.[1]??`./recording-${Date.now()}.mp4`,p=v.expandHome(f,r.meta?.cwd),h={outPath:p,clientOutPath:r.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),quality:r.flags?.quality,showTouches:r.flags?.hideTouches!==!0,gestureEvents:[]};if(o.mkdirSync(n.dirname(p),{recursive:!0}),o.rmSync(p,{force:!0}),"ios"===c.platform&&"device"===c.kind){let e=ex(s);if(!e)return S("INVALID_ARGS","record on physical iOS devices requires an active app session; run open <app> first");t=await eN({req:r,activeSession:s,sessionStore:i,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:h,appBundleId:e})}else if("macos"===c.platform){let e=ex(s);if(!e)return S("INVALID_ARGS","record on macOS requires an active app session; run open <app> first");t=await eE({req:r,activeSession:s,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:h,appBundleId:e})}else t="ios"===c.platform?await eB({req:r,activeSession:s,device:c,logPath:d,deps:l,recordingBase:h,resolvedOut:p}):await eS({device:c,recordingBase:h});if("ok"in t)return t;s.recording=t,i.set(a,s);let w=i.ensureSessionDir(a);return i.recordAction(s,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:{action:"start",showTouches:t.showTouches}}),{ok:!0,data:{recording:"started",outPath:t.clientOutPath??f,sessionStateDir:w,showTouches:t.showTouches}}}async function eX(e){let{deps:t,device:r,recording:a,stopRequestedAt:i}=e;if("android"===a.platform)return await eM({deps:t,device:r,recording:a,stopRequestedAt:i});await p("record_stop_tail_settle",()=>t.waitForRecordingTail(a),{platform:a.platform,gestureEventCount:a.gestureEvents.length});let o=await p("record_stop_ios_simulator_process",()=>eO({deps:t,recording:a}),{outPath:a.outPath});if(!o)return eJ("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",a,i);if(0!==o.exitCode)return eJ(`failed to stop recording: ${er(o,"simctl recordVideo")}`,a,i);if(await p("record_stop_video_stable",()=>t.waitForStableFile(a.outPath,{pollMs:150,attempts:12}),{outPath:a.outPath}),!await p("record_stop_video_playable_check",()=>t.isPlayableVideo(a.outPath),{outPath:a.outPath}))return eJ(`failed to stop recording: ${a.outPath} was not finalized into a playable video`,a,i);if(void 0!==a.quality&&a.quality<10){let e=a.quality;try{await p("record_stop_resize",()=>t.resizeRecording({videoPath:a.outPath,quality:e,targetLabel:"iOS recording"}),{outPath:a.outPath,quality:e})}catch(e){a.overlayWarning=`failed to resize recording: ${et(e)}`}}return await p("record_stop_finalize_overlay",()=>ei({recording:a,deps:t,targetLabel:"iOS recording"}),{outPath:a.outPath,showTouches:a.showTouches,gestureEventCount:a.gestureEvents.length}),null}function eJ(e,t,r){let a=ea(e,t,r);return function(e){try{o.rmSync(e,{force:!0})}catch{}}(t.outPath),S("COMMAND_FAILED",a.message)}async function eZ(e){var t;let r,a,{req:i,activeSession:o,device:s,logPath:c,deps:d}=e;if(!o.recording)return S("INVALID_ARGS","no active recording");let l=o.recording,u=Date.now(),m=l.invalidatedReason;o.recording=void 0;let f="ios-device-runner"===l.platform?await ek({req:i,activeSession:o,device:s,logPath:c,deps:d,recording:l}):"macos-runner"===l.platform?await eF({req:i,activeSession:o,device:s,logPath:c,deps:d,recording:l}):await eX({deps:d,device:s,recording:l,stopRequestedAt:u});if(f)return f;if(m&&"ios"===l.platform&&l.showTouches)l.overlayWarning??=`overlay unavailable: ${m}`;else if(m)return S("COMMAND_FAILED",m);return r="android"===(t=l).platform?t.chunks:void 0,a=[{field:"outPath",path:t.outPath,localPath:t.clientOutPath,fileName:n.basename(t.clientOutPath??t.outPath)}],r&&r.length>1&&a.push(...r.slice(1).map(e=>({field:"chunkPath",path:e.path,localPath:eQ(t,e.index),fileName:n.basename(eQ(t,e.index)??e.path)}))),t.telemetryPath&&a.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return B(e.clientOutPath)}(t),fileName:n.basename(t.telemetryPath)}),{ok:!0,data:{recording:"stopped",outPath:t.outPath,telemetryPath:t.telemetryPath,artifacts:a,showTouches:t.showTouches,warning:t.warning,overlayWarning:t.overlayWarning,chunks:r?.map(e=>({index:e.index,path:eQ(t,e.index)??e.path}))}}}function eQ(e,t){if("android"===e.platform&&e.clientOutPath)return eo(e.clientOutPath,t)}function eY(e,t,r,a={}){r.recordOnlySession&&(a.writeLog&&e.writeSessionLog(r),e.delete(t))}async function e0(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await _(t,r):await m(e,t,r),startIosSimulatorRecording:e=>D().startIosSimulatorRecording(e),runIosRunnerCommand:P,waitForRecordingTail:eH,waitForStableFile:q,isPlayableVideo:K,trimRecordingStart:Q,resizeRecording:ee,overlayRecordingTouches:Y},n=a.get(r),s=n?.device??await I(t.flags??{});n||await b(s);let c=n??{name:C(t),sessionScope:M(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return S("INVALID_ARGS","record requires start|stop");if("start"===d)return eW({req:t,sessionName:r,sessionStore:a,activeSession:c,device:s,logPath:i,deps:o});let l=await eZ({req:t,activeSession:c,device:s,logPath:i,deps:o});return l.ok?(a.recordAction(c,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:l.data?.outPath,showTouches:l.data?.showTouches}}),eY(a,r,c,{writeLog:!0})):eY(a,r,c),l}async function e1(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,s=t.command;if("record"===s)return e0({req:t,sessionName:r,sessionStore:a,logPath:i});if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return S("INVALID_ARGS","trace requires start|stop");let i=a.get(r);if(!i)return S("SESSION_NOT_FOUND","No active session");if("start"===e){if(i.trace)return S("INVALID_ARGS","trace already in progress");let e=t.positionals?.[1]??a.defaultTracePath(i),r=v.expandHome(e);return o.mkdirSync(n.dirname(r),{recursive:!0}),o.appendFileSync(r,""),i.trace={outPath:r,startedAt:Date.now()},a.recordAction(i,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!i.trace)return S("INVALID_ARGS","no active trace");let c=i.trace.outPath;if(t.positionals?.[1]){let e=v.expandHome(t.positionals[1]);o.mkdirSync(n.dirname(e),{recursive:!0}),o.existsSync(c)?o.renameSync(c,e):o.appendFileSync(e,""),c=e}return i.trace=void 0,a.recordAction(i,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:c}}),{ok:!0,data:{trace:"stopped",outPath:c}}}return null}export{R as record_trace_namespaceObject};