agent-device 0.17.5 → 0.17.6

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 (123) hide show
  1. package/README.md +2 -2
  2. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.5.apk → agent-device-android-multitouch-helper-0.17.6.apk} +0 -0
  3. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.6.apk.sha256 +1 -0
  4. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.5.manifest.json → agent-device-android-multitouch-helper-0.17.6.manifest.json} +4 -4
  5. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.5.apk → agent-device-android-snapshot-helper-0.17.6.apk} +0 -0
  6. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.6.apk.sha256 +1 -0
  7. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.5.manifest.json → agent-device-android-snapshot-helper-0.17.6.manifest.json} +6 -6
  8. package/dist/src/2133.js +1 -0
  9. package/dist/src/2748.js +1 -0
  10. package/dist/src/{4012.js → 2892.js} +1 -1
  11. package/dist/src/2948.js +1 -0
  12. package/dist/src/2954.js +2 -0
  13. package/dist/src/{7651.js → 3006.js} +1 -1
  14. package/dist/src/314.js +1 -0
  15. package/dist/src/{8806.js → 3340.js} +5 -5
  16. package/dist/src/4291.js +2 -0
  17. package/dist/src/{7599.js → 432.js} +1 -1
  18. package/dist/src/4418.js +1 -0
  19. package/dist/src/{2403.js → 4428.js} +1 -1
  20. package/dist/src/4723.js +1 -0
  21. package/dist/src/5299.js +1 -0
  22. package/dist/src/{113.js → 5448.js} +1 -1
  23. package/dist/src/5484.js +1 -0
  24. package/dist/src/5628.js +1 -0
  25. package/dist/src/587.js +1 -0
  26. package/dist/src/6311.js +27 -0
  27. package/dist/src/6918.js +1 -0
  28. package/dist/src/7244.js +1 -0
  29. package/dist/src/7394.js +6 -0
  30. package/dist/src/8184.js +1 -0
  31. package/dist/src/8225.js +1 -0
  32. package/dist/src/{1974.js → 8275.js} +1 -1
  33. package/dist/src/8875.js +1 -0
  34. package/dist/src/{1352.js → 9581.js} +1 -1
  35. package/dist/src/9624.js +1 -0
  36. package/dist/src/9722.js +38 -0
  37. package/dist/src/9836.js +1 -0
  38. package/dist/src/9873.js +1 -0
  39. package/dist/src/9919.js +6 -0
  40. package/dist/src/android-adb.d.ts +3 -3
  41. package/dist/src/android-adb.js +1 -1
  42. package/dist/src/android-snapshot-helper.js +1 -1
  43. package/dist/src/android.js +1 -1
  44. package/dist/src/apple.js +1 -1
  45. package/dist/src/apps.js +6 -6
  46. package/dist/src/artifacts.js +1 -1
  47. package/dist/src/batch.d.ts +4 -4
  48. package/dist/src/batch.js +1 -1
  49. package/dist/src/{args.js → cli-help.js} +18 -18
  50. package/dist/src/cli-output.js +4 -30
  51. package/dist/src/cli.js +17 -17
  52. package/dist/src/command-surface.js +1 -1
  53. package/dist/src/contracts.d.ts +6 -6
  54. package/dist/src/contracts.js +1 -1
  55. package/dist/src/devices.js +1 -1
  56. package/dist/src/find.js +1 -1
  57. package/dist/src/finders.d.ts +1 -1
  58. package/dist/src/finders.js +1 -1
  59. package/dist/src/generic.js +8 -14
  60. package/dist/src/index.d.ts +28 -25
  61. package/dist/src/index.js +1 -1
  62. package/dist/src/input-actions.js +1 -1
  63. package/dist/src/input-actions~1.js +1 -1
  64. package/dist/src/install-source.js +1 -1
  65. package/dist/src/interaction.js +1 -1
  66. package/dist/src/internal/bin.js +5 -5
  67. package/dist/src/internal/companion-tunnel.js +1 -1
  68. package/dist/src/internal/daemon.js +1 -1
  69. package/dist/src/internal/png-worker.js +1 -1
  70. package/dist/src/internal/update-check-entry.js +1 -1
  71. package/dist/src/io.js +1 -1
  72. package/dist/src/lease.js +1 -1
  73. package/dist/src/linux.js +1 -1
  74. package/dist/src/metro.js +1 -1
  75. package/dist/src/notifications.js +1 -1
  76. package/dist/src/react-native.js +1 -1
  77. package/dist/src/record-trace-recording.js +2 -2
  78. package/dist/src/record-trace.js +1 -1
  79. package/dist/src/recording-provider.js +1 -1
  80. package/dist/src/remote-config.d.ts +5 -5
  81. package/dist/src/remote-config.js +1 -1
  82. package/dist/src/rslib-runtime.js +1 -1
  83. package/dist/src/selector-runtime.js +1 -1
  84. package/dist/src/selectors.d.ts +1 -1
  85. package/dist/src/selectors.js +1 -1
  86. package/dist/src/server.js +1 -1
  87. package/dist/src/session.js +7 -7
  88. package/dist/src/snapshot.js +2 -2
  89. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +5 -0
  90. package/package.json +14 -13
  91. package/server.json +3 -3
  92. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.5.apk.sha256 +0 -1
  93. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.5.apk.sha256 +0 -1
  94. package/dist/src/1010.js +0 -1
  95. package/dist/src/123.js +0 -1
  96. package/dist/src/1231.js +0 -1
  97. package/dist/src/208.js +0 -1
  98. package/dist/src/221.js +0 -6
  99. package/dist/src/2415.js +0 -38
  100. package/dist/src/3675.js +0 -1
  101. package/dist/src/5611.js +0 -1
  102. package/dist/src/5827.js +0 -1
  103. package/dist/src/6088.js +0 -1
  104. package/dist/src/6133.js +0 -1
  105. package/dist/src/6629.js +0 -1
  106. package/dist/src/7556.js +0 -1
  107. package/dist/src/7719.js +0 -1
  108. package/dist/src/7847.js +0 -1
  109. package/dist/src/8133.js +0 -1
  110. package/dist/src/8656.js +0 -1
  111. package/dist/src/9010.js +0 -1
  112. package/dist/src/9471.js +0 -1
  113. package/dist/src/9542.js +0 -6
  114. package/dist/src/9616.js +0 -2
  115. package/dist/src/9639.js +0 -2
  116. package/dist/src/9671.js +0 -1
  117. package/dist/src/9818.js +0 -1
  118. package/dist/src/989.js +0 -1
  119. /package/dist/src/{2301.js → 4069.js} +0 -0
  120. /package/dist/src/{4829.js → 5560.js} +0 -0
  121. /package/dist/src/{4778.js → 6024.js} +0 -0
  122. /package/dist/src/{9152.js → 733.js} +0 -0
  123. /package/dist/src/{3267.js → 9612.js} +0 -0
package/dist/src/linux.js CHANGED
@@ -1 +1 @@
1
- import{longPressLinux as t,pressLinux as e,typeLinux as n,scrollLinux as o,sendKey as r,fillLinux as a,focusLinux as i,swipeLinux as s,doubleClickLinux as p}from"./input-actions~1.js";import{snapshotLinux as u,resolveLinuxToolProvider as c}from"./2415.js";import{AppError as w}from"./9152.js";import{withDiagnosticTimer as _}from"./7599.js";async function P(t){await c().desktop.openTarget(t)}async function d(t){await c().desktop.closeApp(t)}async function O(){await r("alt+Left",["56:1","105:1","105:0","56:0"])}async function f(){await r("super+d",["125:1","32:1","32:0","125:0"])}async function l(){return await c().clipboard.readText()}async function S(t){await c().clipboard.writeText(t)}async function E(t,e){await c().screenshot.capture(t,e)}function N(){return{open:t=>P(t),openDevice:()=>Promise.resolve(),close:t=>d(t),tap:(t,n)=>e(t,n),doubleTap:(t,e)=>p(t,e),swipe:(t,e,n,o,r)=>s(t,e,n,o,r),pan:(t,e,n,o,r)=>s(t,e,n,o,r),fling:()=>{throw new w("UNSUPPORTED_OPERATION","gesture fling not supported on Linux")},longPress:(e,n,o)=>t(e,n,o),focus:(t,e)=>i(t,e),type:(t,e)=>n(t,e),fill:(t,e,n,o)=>a(t,e,n,o),scroll:(t,e)=>o(t,e),pinch:()=>{throw new w("UNSUPPORTED_OPERATION","gesture pinch not supported on Linux")},screenshot:(t,e)=>E(t,e),snapshot:async t=>{let e=await _("snapshot_capture",async()=>await u(t?.surface),{backend:"linux-atspi"});return{nodes:e.nodes??[],truncated:e.truncated??!1,backend:"linux-atspi"}},back:()=>O(),home:()=>f(),rotate:()=>{throw new w("UNSUPPORTED_OPERATION","rotate not supported on Linux")},rotateGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture rotate not supported on Linux")},transformGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture transform not supported on Linux")},appSwitcher:()=>{throw new w("UNSUPPORTED_OPERATION","appSwitcher not yet supported on Linux")},readClipboard:()=>l(),writeClipboard:t=>S(t),setSetting:()=>{throw new w("UNSUPPORTED_OPERATION","setSetting not supported on Linux")}}}export{N as createLinuxInteractor};
1
+ import{longPressLinux as t,pressLinux as e,typeLinux as n,scrollLinux as o,sendKey as r,fillLinux as a,focusLinux as i,swipeLinux as s,doubleClickLinux as p}from"./input-actions~1.js";import{snapshotLinux as u,resolveLinuxToolProvider as c}from"./9722.js";import{AppError as w}from"./733.js";import{withDiagnosticTimer as _}from"./432.js";async function P(t){await c().desktop.openTarget(t)}async function d(t){await c().desktop.closeApp(t)}async function O(){await r("alt+Left",["56:1","105:1","105:0","56:0"])}async function f(){await r("super+d",["125:1","32:1","32:0","125:0"])}async function l(){return await c().clipboard.readText()}async function S(t){await c().clipboard.writeText(t)}async function E(t,e){await c().screenshot.capture(t,e)}function N(){return{open:t=>P(t),openDevice:()=>Promise.resolve(),close:t=>d(t),tap:(t,n)=>e(t,n),doubleTap:(t,e)=>p(t,e),swipe:(t,e,n,o,r)=>s(t,e,n,o,r),pan:(t,e,n,o,r)=>s(t,e,n,o,r),fling:()=>{throw new w("UNSUPPORTED_OPERATION","gesture fling not supported on Linux")},longPress:(e,n,o)=>t(e,n,o),focus:(t,e)=>i(t,e),type:(t,e)=>n(t,e),fill:(t,e,n,o)=>a(t,e,n,o),scroll:(t,e)=>o(t,e),pinch:()=>{throw new w("UNSUPPORTED_OPERATION","gesture pinch not supported on Linux")},screenshot:(t,e)=>E(t,e),snapshot:async t=>{let e=await _("snapshot_capture",async()=>await u(t?.surface),{backend:"linux-atspi"});return{nodes:e.nodes??[],truncated:e.truncated??!1,backend:"linux-atspi"}},back:()=>O(),home:()=>f(),rotate:()=>{throw new w("UNSUPPORTED_OPERATION","rotate not supported on Linux")},rotateGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture rotate not supported on Linux")},transformGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture transform not supported on Linux")},appSwitcher:()=>{throw new w("UNSUPPORTED_OPERATION","appSwitcher not yet supported on Linux")},readClipboard:()=>l(),writeClipboard:t=>S(t),setSetting:()=>{throw new w("UNSUPPORTED_OPERATION","setSetting not supported on Linux")}}}export{N as createLinuxInteractor};
package/dist/src/metro.js CHANGED
@@ -1 +1 @@
1
- import{buildMetroRuntimeHints as e,ensureMetroCompanion as t,reloadMetro as r,stopMetroCompanion as o,prepareMetroRuntime as n}from"./1974.js";import{resolveRuntimeTransportHints as i}from"./8656.js";function s(e){return i(e)}async function a(e){let t=await n({projectRoot:e.projectRoot,kind:e.kind,publicBaseUrl:e.publicBaseUrl,proxyBaseUrl:e.proxyBaseUrl,proxyBearerToken:e.proxyBearerToken,bridgeScope:e.bridgeScope,launchUrl:e.launchUrl,companionProfileKey:e.profileKey,companionConsumerKey:e.consumerKey,metroPort:e.port,listenHost:e.listenHost,statusHost:e.statusHost,startupTimeoutMs:e.startupTimeoutMs,probeTimeoutMs:e.probeTimeoutMs,reuseExisting:e.reuseExisting,installDependenciesIfNeeded:e.installDependenciesIfNeeded,runtimeFilePath:e.runtimeFilePath,logPath:e.logPath,env:e.env});return{iosRuntime:t.iosRuntime,androidRuntime:t.androidRuntime,bridge:t.bridge,started:t.started,reused:t.reused,logPath:t.logPath}}async function u(e){let r=await t(e);return{pid:r.pid,started:r.spawned,logPath:r.logPath}}async function l(e){await o(e)}async function d(e={}){return await r(e)}function p(t){return e(t,"ios")}function m(t){return e(t,"android")}export{buildBundleUrl,normalizeBaseUrl}from"./2301.js";export{m as buildAndroidRuntimeHints,p as buildIosRuntimeHints,u as ensureMetroTunnel,a as prepareRemoteMetro,d as reloadRemoteMetro,s as resolveRuntimeTransport,l as stopMetroTunnel};
1
+ import{buildMetroRuntimeHints as e,ensureMetroCompanion as t,reloadMetro as r,stopMetroCompanion as o,prepareMetroRuntime as n}from"./8275.js";import{resolveRuntimeTransportHints as i}from"./5628.js";function s(e){return i(e)}async function a(e){let t=await n({projectRoot:e.projectRoot,kind:e.kind,publicBaseUrl:e.publicBaseUrl,proxyBaseUrl:e.proxyBaseUrl,proxyBearerToken:e.proxyBearerToken,bridgeScope:e.bridgeScope,launchUrl:e.launchUrl,companionProfileKey:e.profileKey,companionConsumerKey:e.consumerKey,metroPort:e.port,listenHost:e.listenHost,statusHost:e.statusHost,startupTimeoutMs:e.startupTimeoutMs,probeTimeoutMs:e.probeTimeoutMs,reuseExisting:e.reuseExisting,installDependenciesIfNeeded:e.installDependenciesIfNeeded,runtimeFilePath:e.runtimeFilePath,logPath:e.logPath,env:e.env});return{iosRuntime:t.iosRuntime,androidRuntime:t.androidRuntime,bridge:t.bridge,started:t.started,reused:t.reused,logPath:t.logPath}}async function u(e){let r=await t(e);return{pid:r.pid,started:r.spawned,logPath:r.logPath}}async function l(e){await o(e)}async function d(e={}){return await r(e)}function p(t){return e(t,"ios")}function m(t){return e(t,"android")}export{buildBundleUrl,normalizeBaseUrl}from"./4069.js";export{m as buildAndroidRuntimeHints,p as buildIosRuntimeHints,u as ensureMetroTunnel,a as prepareRemoteMetro,d as reloadRemoteMetro,s as resolveRuntimeTransport,l as stopMetroTunnel};
@@ -1 +1 @@
1
- import{AppError as e}from"./9152.js";import{runAndroidAdb as r}from"./8806.js";async function t(t,o,i){let n="string"==typeof i.action&&i.action.trim()?i.action.trim():`${o}.TEST_PUSH`,s=["shell","am","broadcast","-a",n,"-p",o],a="string"==typeof i.receiver?i.receiver.trim():"";a&&s.push("-n",a);let p=i.extras;if(void 0!==p&&("object"!=typeof p||null===p||Array.isArray(p)))throw new e("INVALID_ARGS","Android push payload extras must be an object");let u=0;for(let[r,t]of Object.entries(p??{}))r&&(function(r,t,o){if("string"==typeof o)return r.push("--es",t,o);if("boolean"==typeof o)return r.push("--ez",t,o?"true":"false");if("number"==typeof o&&Number.isFinite(o))return Number.isInteger(o)?r.push("--ei",t,String(o)):r.push("--ef",t,String(o));throw new e("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(s,r,t),u+=1);return await r(t,s),{action:n,extrasCount:u}}export{t as pushAndroidNotification};
1
+ import{AppError as e}from"./733.js";import{runAndroidAdb as r}from"./3340.js";async function t(t,o,i){let n="string"==typeof i.action&&i.action.trim()?i.action.trim():`${o}.TEST_PUSH`,s=["shell","am","broadcast","-a",n,"-p",o],a="string"==typeof i.receiver?i.receiver.trim():"";a&&s.push("-n",a);let p=i.extras;if(void 0!==p&&("object"!=typeof p||null===p||Array.isArray(p)))throw new e("INVALID_ARGS","Android push payload extras must be an object");let u=0;for(let[r,t]of Object.entries(p??{}))r&&(function(r,t,o){if("string"==typeof o)return r.push("--es",t,o);if("boolean"==typeof o)return r.push("--ez",t,o?"true":"false");if("number"==typeof o&&Number.isFinite(o))return Number.isInteger(o)?r.push("--ei",t,String(o)):r.push("--ef",t,String(o));throw new e("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(s,r,t),u+=1);return await r(t,s),{action:n,extrasCount:u}}export{t as pushAndroidNotification};
@@ -1 +1 @@
1
- import{dispatchCommand as e,errorResponse as t,isCommandSupportedOnDevice as i}from"./2415.js";import{PUBLIC_COMMANDS as a}from"./6088.js";import{isSparseSnapshotQualityVerdict as s,analyzeReactNativeOverlay as r,successText as n,parsing_stripUndefined as o}from"./6133.js";import{normalizeError as d}from"./9152.js";import{interaction_snapshot_captureSnapshotForSession as l,readSnapshotNodesReferenceFrame as c,finalizeTouchInteraction as v}from"./9471.js";async function f(e){var o,c;let{req:v,sessionName:f,sessionStore:u}=e;if(v.command!==a.reactNative)return null;let y=1===(o=v.positionals??[]).length&&"dismiss-overlay"===o[0]?{ok:!0}:{ok:!1,response:t("INVALID_ARGS","react-native supports only: dismiss-overlay")};if(!y.ok)return y.response;let p=u.get(f);if(!p)return t("SESSION_NOT_FOUND","No active session. Run open first.");if(!i(a.reactNative,p.device))return t("UNSUPPORTED_OPERATION","react-native dismiss-overlay is not supported on this device");try{let i=await l(p,v.flags,u,e.contextFromFlags,{interactiveOnly:!0});if(s(i.snapshotQuality)){return c=i.snapshotQuality,t("COMMAND_FAILED","React Native overlay state could not be determined because the accessibility tree is unreadable",{reason:c.reason,hint:"The snapshot quality verdict is sparse. Use screenshot as visual truth; if an overlay is visible, report it or navigate with coordinates, then retry snapshot or dismiss-overlay on a readable screen."})}let a=r(i.nodes),o=a.primaryAction;if(!o)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,...n("No React Native overlay detected")}};return await m(e,p,i,o)}catch(e){return{ok:!1,error:d(e)}}}async function m(t,i,a,s){let{req:r,sessionStore:d}=t,l=Date.now(),f=await e(i.device,"press",[String(s.point.x),String(s.point.y)],r.flags?.out,t.contextFromFlags(r.flags,i.appBundleId,i.trace?.outPath))??{},m=Date.now(),y=await u(t,i),p=o({...c(a.nodes),...f,action:"dismiss-overlay",overlayAction:s.action,x:s.point.x,y:s.point.y,ref:s.ref,label:s.label,warning:s.warning,dismissed:!0,verified:y.verified,verificationRequired:!y.verified,verificationWarning:y.verificationWarning,nextCommand:y.nextCommand,...n(y.verified?"React Native overlay dismiss action sent and verified gone":"React Native overlay dismiss action sent, but verification still detects an overlay")});return v({session:i,sessionStore:d,command:r.command,positionals:r.positionals??[],flags:r.flags,result:p,responseData:p,actionStartedAt:l,actionFinishedAt:m})}async function u(e,t){let{req:i,sessionStore:a}=e,n=await l(t,i.flags,a,e.contextFromFlags,{interactiveOnly:!0});return s(n.snapshotQuality)?{verified:!1,verificationWarning:"React Native overlay dismissal could not be verified because the post-dismiss accessibility tree is unreadable. Use screenshot as visual truth.",nextCommand:"agent-device screenshot"}:r(n.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{f as handleReactNativeCommands};
1
+ import{dispatchCommand as e,errorResponse as t,isCommandSupportedOnDevice as i}from"./9722.js";import{PUBLIC_COMMANDS as a}from"./2133.js";import{isSparseSnapshotQualityVerdict as s,analyzeReactNativeOverlay as r,successText as n,parsing_stripUndefined as o}from"./9873.js";import{normalizeError as d}from"./733.js";import{interaction_snapshot_captureSnapshotForSession as l,readSnapshotNodesReferenceFrame as c,finalizeTouchInteraction as v}from"./8184.js";async function f(e){var o,c;let{req:v,sessionName:f,sessionStore:u}=e;if(v.command!==a.reactNative)return null;let y=1===(o=v.positionals??[]).length&&"dismiss-overlay"===o[0]?{ok:!0}:{ok:!1,response:t("INVALID_ARGS","react-native supports only: dismiss-overlay")};if(!y.ok)return y.response;let p=u.get(f);if(!p)return t("SESSION_NOT_FOUND","No active session. Run open first.");if(!i(a.reactNative,p.device))return t("UNSUPPORTED_OPERATION","react-native dismiss-overlay is not supported on this device");try{let i=await l(p,v.flags,u,e.contextFromFlags,{interactiveOnly:!0});if(s(i.snapshotQuality)){return c=i.snapshotQuality,t("COMMAND_FAILED","React Native overlay state could not be determined because the accessibility tree is unreadable",{reason:c.reason,hint:"The snapshot quality verdict is sparse. Use screenshot as visual truth; if an overlay is visible, report it or navigate with coordinates, then retry snapshot or dismiss-overlay on a readable screen."})}let a=r(i.nodes),o=a.primaryAction;if(!o)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,...n("No React Native overlay detected")}};return await m(e,p,i,o)}catch(e){return{ok:!1,error:d(e)}}}async function m(t,i,a,s){let{req:r,sessionStore:d}=t,l=Date.now(),f=await e(i.device,"press",[String(s.point.x),String(s.point.y)],r.flags?.out,t.contextFromFlags(r.flags,i.appBundleId,i.trace?.outPath))??{},m=Date.now(),y=await u(t,i),p=o({...c(a.nodes),...f,action:"dismiss-overlay",overlayAction:s.action,x:s.point.x,y:s.point.y,ref:s.ref,label:s.label,warning:s.warning,dismissed:!0,verified:y.verified,verificationRequired:!y.verified,verificationWarning:y.verificationWarning,nextCommand:y.nextCommand,...n(y.verified?"React Native overlay dismiss action sent and verified gone":"React Native overlay dismiss action sent, but verification still detects an overlay")});return v({session:i,sessionStore:d,command:r.command,positionals:r.positionals??[],flags:r.flags,result:p,responseData:p,actionStartedAt:l,actionFinishedAt:m})}async function u(e,t){let{req:i,sessionStore:a}=e,n=await l(t,i.flags,a,e.contextFromFlags,{interactiveOnly:!0});return s(n.snapshotQuality)?{verified:!1,verificationWarning:"React Native overlay dismissal could not be verified because the post-dismiss accessibility tree is unreadable. Use screenshot as visual truth.",nextCommand:"agent-device screenshot"}:r(n.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{f as handleReactNativeCommands};
@@ -1,4 +1,4 @@
1
- let e,t,r,i;import a from"node:fs";import o from"node:path";import{createHash as n}from"node:crypto";import s from"node:os";import{fileURLToPath as c}from"node:url";import{AppError as d}from"./9152.js";import{runCmd as l}from"./9818.js";import{runXcrun as u,SessionStore as m,runIosRunnerCommand as f,isCommandSupportedOnDevice as p,errorResponse as h,acquireProcessLock as w,ensureDeviceReady as g,resolvePublicSessionName as y,resolveImplicitSessionScope as _,resolveTargetDevice as v,IOS_RUNNER_CONTAINER_BUNDLE_IDS as P}from"./2415.js";import{readProcessStartTime as S}from"./8656.js";import{sleep as A}from"./4829.js";import{withDiagnosticTimer as M,emitDiagnostic as b}from"./7599.js";import{androidDeviceForSerial as C,runAndroidAdb as I}from"./8806.js";import{pullAndroidAdbFile as x}from"./9639.js";import{resolveRecordingProvider as D}from"./recording-provider.js";function $(e=process.env){let t=N(),r=o.join(t,"home"),i=o.join(t,"module-cache");return a.mkdirSync(r,{recursive:!0}),a.mkdirSync(i,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:i}}async function R(e){let t=a.statSync(e.sourcePath),r=a.readFileSync(e.sourcePath),i=L(e.cacheName??o.basename(e.sourcePath,o.extname(e.sourcePath))),n=T(["2",process.platform,process.arch,o.resolve(e.sourcePath),t.size,r]),s=o.join(N(),"bin",`${i}-${n}`);return await E({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function k(e){let t=L(e.cacheName),r=T(["2",process.platform,process.arch,e.source]),i=o.join(N(),"sources",`${t}-${r}.swift`),a=o.join(N(),"bin",`${t}-${r}`);return await E({sourcePath:i,executablePath:a,sourceText:e.source,timeoutMs:e.timeoutMs}),a}function N(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?o.resolve(e):o.join(s.tmpdir(),"agent-device-swift-cache")}async function E(e){if(O(e.executablePath))return;let t=o.dirname(e.executablePath);a.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`,i=await F(r,e.executablePath,e.timeoutMs??12e4);if(!i)return;let n=a.mkdtempSync(o.join(t,`.${o.basename(e.executablePath)}.${process.pid}.`)),s=o.join(n,o.basename(e.executablePath));try{if(O(e.executablePath))return;void 0===e.sourceText||a.existsSync(e.sourcePath)||(a.mkdirSync(o.dirname(e.sourcePath),{recursive:!0}),a.writeFileSync(e.sourcePath,e.sourceText)),await l("xcrun",["swiftc",e.sourcePath,"-o",s],{timeoutMs:e.timeoutMs??12e4,env:$()}),a.renameSync(s,e.executablePath)}finally{a.rmSync(n,{recursive:!0,force:!0}),await i()}}async function F(e,t,r){if(O(t))return null;try{return await w({lockDirPath:e,owner:{pid:process.pid,startTime:S(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${e} (${r}ms)`})}catch(t){if(t instanceof d&&t.message.startsWith("Timed out waiting for Swift cache lock:"))throw new d("COMMAND_FAILED",t.message,{...t.details,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.`});throw t}}function O(e){try{return a.accessSync(e,a.constants.X_OK),a.statSync(e).isFile()}catch{return!1}}function L(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function T(e){let t=n("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}let U=`
1
+ let e,t,r,i;import a from"node:fs";import o from"node:path";import{createHash as n}from"node:crypto";import s from"node:os";import{fileURLToPath as c}from"node:url";import{AppError as d}from"./733.js";import{runCmd as l}from"./8875.js";import{runXcrun as u,SessionStore as m,runIosRunnerCommand as f,isCommandSupportedOnDevice as p,errorResponse as h,acquireProcessLock as w,ensureDeviceReady as g,resolvePublicSessionName as y,resolveImplicitSessionScope as _,resolveTargetDevice as v,IOS_RUNNER_CONTAINER_BUNDLE_IDS as P}from"./9722.js";import{readProcessStartTime as S}from"./5628.js";import{sleep as A}from"./5560.js";import{withDiagnosticTimer as M,emitDiagnostic as b}from"./432.js";import{androidDeviceForSerial as C,runAndroidAdb as I}from"./3340.js";import{pullAndroidAdbFile as x}from"./2954.js";import{resolveRecordingProvider as D}from"./recording-provider.js";function $(e=process.env){let t=E(),r=o.join(t,"home"),i=o.join(t,"module-cache");return a.mkdirSync(r,{recursive:!0}),a.mkdirSync(i,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:i}}async function R(e){let t=a.statSync(e.sourcePath),r=a.readFileSync(e.sourcePath),i=L(e.cacheName??o.basename(e.sourcePath,o.extname(e.sourcePath))),n=T(["2",process.platform,process.arch,o.resolve(e.sourcePath),t.size,r]),s=o.join(E(),"bin",`${i}-${n}`);return await N({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function k(e){let t=L(e.cacheName),r=T(["2",process.platform,process.arch,e.source]),i=o.join(E(),"sources",`${t}-${r}.swift`),a=o.join(E(),"bin",`${t}-${r}`);return await N({sourcePath:i,executablePath:a,sourceText:e.source,timeoutMs:e.timeoutMs}),a}function E(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?o.resolve(e):o.join(s.tmpdir(),"agent-device-swift-cache")}async function N(e){if(O(e.executablePath))return;let t=o.dirname(e.executablePath);a.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`,i=await F(r,e.executablePath,e.timeoutMs??12e4);if(!i)return;let n=a.mkdtempSync(o.join(t,`.${o.basename(e.executablePath)}.${process.pid}.`)),s=o.join(n,o.basename(e.executablePath));try{if(O(e.executablePath))return;void 0===e.sourceText||a.existsSync(e.sourcePath)||(a.mkdirSync(o.dirname(e.sourcePath),{recursive:!0}),a.writeFileSync(e.sourcePath,e.sourceText)),await l("xcrun",["swiftc",e.sourcePath,"-o",s],{timeoutMs:e.timeoutMs??12e4,env:$()}),a.renameSync(s,e.executablePath)}finally{a.rmSync(n,{recursive:!0,force:!0}),await i()}}async function F(e,t,r){if(O(t))return null;try{return await w({lockDirPath:e,owner:{pid:process.pid,startTime:S(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${e} (${r}ms)`})}catch(t){if(t instanceof d&&t.message.startsWith("Timed out waiting for Swift cache lock:"))throw new d("COMMAND_FAILED",t.message,{...t.details,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.`});throw t}}function O(e){try{return a.accessSync(e,a.constants.X_OK),a.statSync(e).isFile()}catch{return!1}}function L(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function T(e){let t=n("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}let U=`
2
2
  import Foundation
3
3
  import AVFoundation
4
4
 
@@ -23,4 +23,4 @@ Task {
23
23
  semaphore.wait()
24
24
  exit(exitCode)
25
25
  `.trim();async function z(e,t={}){let r,i=t.pollMs??150,o=t.attempts??12,n=0;for(let t=0;t<o;t+=1){let t=0;try{t=a.statSync(e).size}catch{t=0}if(t>0&&t===r){if((n+=1)>=2)return}else n=0;r=t,await A(i)}}async function q(e){try{let t=await K(),r=await l(t,[e],{allowFailure:!0,timeoutMs:1e4,env:$()});if(0===r.exitCode)return!0;if(V(r.stderr,r.stdout))return H(e);return!1}catch(r){var t;if((t=r)instanceof d&&("TOOL_MISSING"===t.code||V(String(t.details?.stderr??""),String(t.details?.stdout??""))))return H(e);throw r}}async function K(){e??=k({source:U,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,i=t.attempts??12;for(let t=0;t<i;t+=1){if(await q(e))return;await A(r)}}function V(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 H(e){try{let t=a.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=function(e){try{let t=a.openSync(e,"r");try{let e=a.fstatSync(t).size,r=0,i=[];for(;r+8<=e&&i.length<16;){let e=Buffer.alloc(8);if(8>a.readSync(t,e,0,8,r))break;let o=e.readUInt32BE(0),n=e.toString("latin1",4,8);if(i.push(n),1===o){let e=Buffer.alloc(8);if(8>a.readSync(t,e,0,8,r+8))break;o=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(o)||o<=0)break;r+=o}return i}finally{a.closeSync(t)}}catch{return[]}}(e);return t.includes("ftyp")&&t.includes("moov")}function j(e){let t=o.parse(e);return o.join(t.dir,`${t.name}.gesture-telemetry.json`)}function W(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function B(e){var t,r,i;let o,n,{recording:s,trimStartMs:c}=e,d=(o=j((t={videoPath:s.outPath,events:s.gestureEvents,trimStartMs:c}).videoPath),n={version:1,generatedAt:new Date().toISOString(),events:(r=t.events,(i=t.trimStartMs??0)>0?W(r.flatMap(e=>{let t=e.tMs-i,r="durationMs"in e?e.durationMs:void 0;return("number"==typeof r?t+r:t)<=0?[]:[{...e,tMs:Math.max(0,t)}]})):W(r))},a.writeFileSync(o,JSON.stringify(n,null,2)),o);return s.telemetryPath=d,d}function J(e){let t=o.dirname(c(import.meta.url)),r=[c(new URL(`./${e}`,import.meta.url)),o.resolve(t,`../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(t,`../../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(process.cwd(),`ios-runner/AgentDeviceRunner/RecordingScripts/${e}`)];for(let e of r)if(a.existsSync(e))return e;throw new d("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 X(e){var t;let r,i,{videoPath:n,scriptPath:s,scriptArgs:c,commandDescription:u}=e;await z(n),await G(n);let m=(t=n,r=o.parse(t),i=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,o.join(r.dir,`.${r.name}.agent-device-${i}${r.ext||".mp4"}`));try{let e=await R({sourcePath:s});await l(e,["--input",n,"--output",m,...c],{timeoutMs:12e4,env:$()}),await G(m),a.renameSync(m,n)}catch(t){let e=t instanceof d?t:new d("COMMAND_FAILED",String(t),void 0,t instanceof Error?t:void 0);throw new d("COMMAND_FAILED",u,{...e.details,videoPath:n,script:s},e)}finally{a.rmSync(m,{force:!0})}}async function Z(e){let{videoPath:t,trimStartMs:i}=e;i>0&&await X({videoPath:t,scriptPath:r??=J("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(i)],commandDescription:"Failed to trim the start of the iOS recording"})}async function Q(e){let{videoPath:r,telemetryPath:i,targetLabel:a="recording"}=e;await X({videoPath:r,scriptPath:t??=J("recording-overlay.swift"),scriptArgs:["--events",i],commandDescription:`Failed to add touch overlays to the ${a}`})}async function Y(e){let{videoPath:t,quality:r,targetLabel:a="recording"}=e;await X({videoPath:t,scriptPath:i??=J("recording-resize.swift"),scriptArgs:["--quality",String(r)],commandDescription:`Failed to resize the ${a}`})}function ee(e){return e instanceof Error?e.message:String(e)}function et(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function er(e,t,r=Date.now()){let i=Math.max(0,r-t.startedAt);return i>=1e3?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(i)}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:i,targetLabel:a}=e,o=B({recording:t,trimStartMs:i});if(!t.showTouches)return void b({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void b({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 M("record_stop_overlay_export",()=>r.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:o,targetLabel:a}),{targetLabel:a,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${ee(e)}`}}function ea(e,t){if(1===t)return e;let r=o.parse(e),i=r.ext||".mp4";return o.join(r.dir,`${r.name}.part-${String(t).padStart(3,"0")}${i}`)}function eo(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function en(e){let{recording:t,startNextChunk:r,finishCurrentChunk:i}=e;if(t.stopping)return;let a=await i();if(a)throw Error(a);if(t.stopping)return;let n=eo(t),s=n.length+1,c=await r(o.posix.dirname(t.remotePath));t.remotePath=c.remotePath,t.remotePid=c.remotePid,n.push({index:s,path:ea(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 es(e){let{recording:t,deps:r}=e;eo(t).length<=1?await ei({recording:t,deps:r,targetLabel:"Android recording"}):(B({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 ec(e){for(let t of e.chunks){let r=await ed({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 ed(e){let t,{deps:r,deviceId:i,remotePath:o,outPath:n}=e;for(let e=0;e<2;e+=1){el(n);let s=C(i),c=await x(o,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=et(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(b({level:"debug",phase:"record_stop_android_pull_validation",data:{deviceId:i,remotePath:o,outPath:n,attempt:e+1,fileSize:function(e){try{return a.statSync(e).size}catch{return 0}}(n),playable:t}}),t)return;b({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:i,remotePath:o,outPath:n,attempt:e+1}})}e<1&&await A(750)}return t?`failed to copy recording from device: ${t}`:(el(n),"failed to copy recording from device: pulled file is not a playable MP4")}function el(e){try{a.rmSync(e,{force:!0})}catch{}}async function eu(e,t,r){return await I(C(e),t,r)}async function em(e,t){let r=await eu(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 ef(e,t){for(let r=0;r<40;r+=1){if(!await em(e,t))return!0;await A(250)}return!await em(e,t)}async function ep(e,t){let r,i=0;for(let a=0;a<20;a+=1){let a=await eu(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===a.exitCode?a.stdout.trim():"";if(o.length>0&&o===r){if((i+=1)>=4)return}else i=0;r=o,await A(250)}}async function eh(e,t,r){for(let i=0;i<8;i+=1){let a=await eu(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===a.exitCode?Number(a.stdout.trim()):NaN;if(Number.isFinite(o)&&o>0)return!0;if(!await em(e,r))break;if(i+1>=2)return!0;await A(250)}return!1}async function ew(e){let{deviceId:t,quality:r}=e;if(void 0===r||r>=10)return;let i=await eu(t,["shell","wm","size"],{allowFailure:!0}),a=i.stdout.match(/Override size:\s*(\d+)x(\d+)/)??i.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(0!==i.exitCode||!a)throw Error(`failed to resolve Android screen size for recording quality: ${et(i,"adb shell wm size")}`);return{width:eg(Number(a[1]),r),height:eg(Number(a[2]),r)}}function eg(e,t){return Math.max(2,2*Math.round(e*t/10/2))}async function ey(e,t){await eu(e,["shell","rm","-f",t],{allowFailure:!0})}async function e_(e,t){let r=await eu(e,["shell","kill","-9",t],{allowFailure:!0});return b({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 em(e,t))&&await ef(e,t)}async function ev(e){var t;let r,i,{device:a,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`,i=["/sdcard","/data/local/tmp"],(n&&i.includes(n)?[n,...i.filter(e=>e!==n)]:i).map(e=>`${e}/${r}`))){let t=await eu(a.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: ${et(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 ey(a.id,e);continue}if(b({level:"debug",phase:"record_start_android_started",data:{deviceId:a.id,remotePath:e,remotePid:r}}),await eh(a.id,e,r))return{remotePath:e,remotePid:r,startedAt:Date.now()};s="failed to start recording: Android screenrecord did not begin producing frames",await e_(a.id,r),await ey(a.id,e)}return{error:h("COMMAND_FAILED",s)}}async function eP(e){let t,{device:r,recordingBase:i}=e;try{t=await ew({deviceId:r.id,quality:i.quality})}catch(e){return h("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let a=await ev({device:r,recordingSize:t});if("error"in a)return a.error;let o={platform:"android",remotePath:a.remotePath,remotePid:a.remotePid,chunks:[{index:1,path:i.outPath,remotePath:a.remotePath}],...i,startedAt:a.startedAt};return!function e(t){let{recording:r,startNextChunk:i,finishCurrentChunk:a}=t,o=setTimeout(()=>{r.rotationPromise=en({recording:r,startNextChunk:i,finishCurrentChunk:a}).catch(e=>{r.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{r.rotationPromise=void 0,r.stopping||r.rotationFailedReason||e({recording:r,startNextChunk:i,finishCurrentChunk:a})})},17e4);o.unref?.(),r.rotationTimer=o}({recording:o,finishCurrentChunk:async()=>await eS({device:r,recording:o,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let i=await ev({device:r,recordingSize:t,preferredRemoteDir:e});if("error"in i)throw Error(i.error.ok?"failed to start next Android recording chunk":i.error.error.message);return i}}),o}async function eS(e){let{device:t,recording:r,waitForRemoteFileStability:i=!0}=e;await em(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 a=await eu(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(b({level:"debug",phase:"record_stop_android_signal",data:{deviceId:t.id,remotePath:r.remotePath,remotePid:r.remotePid,exitCode:a.exitCode,stdout:a.stdout.trim(),stderr:a.stderr.trim()}}),0!==a.exitCode)return await eA(t.id,r.remotePid,a);let o=await eM(t.id,r.remotePid);if(o)return o;i&&await ep(t.id,r.remotePath)}async function eA(e,t,r){if(await em(e,t)&&!await e_(e,t))return`failed to stop recording: ${et(r,"adb shell kill")}`}async function eM(e,t){if(!await ef(e,t)&&!await e_(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function eb(e){let t,{deps:r,device:i,recording:a,stopRequestedAt:o}=e;b({level:"debug",phase:"record_stop_android_enter",data:{deviceId:i.id,remotePath:a.remotePath,remotePid:a.remotePid}}),a.stopping=!0,a.rotationTimer&&(clearTimeout(a.rotationTimer),a.rotationTimer=void 0),await a.rotationPromise;let n=await eS({device:i,recording:a});if(a.rotationFailedReason&&!n&&(a.warning??=`Android recording chunk rotation failed: ${a.rotationFailedReason}`),!n){let e=await ec({deps:r,deviceId:i.id,chunks:eo(a)});if(e)return await s(),h("COMMAND_FAILED",eC(e,a,o));await es({recording:a,deps:r})}if(await s(),n)return h("COMMAND_FAILED",eC(n,a,o));if(t)return h("COMMAND_FAILED",t);return null;async function s(){for(let e of eo(a)){let r=await eu(i.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});b({level:"debug",phase:"record_stop_android_cleanup",data:{deviceId:i.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: ${et(r,"adb shell rm")}`)}}}function eC(e,t,r){return er(e,t,r).message}function eI(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function ex(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath,requestId:e.meta?.requestId}}async function eD(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,n=eI(r);try{await o.runIosRunnerCommand(i,{command:"recordStop",appBundleId:n},ex(t,a,r))}catch(e){b({level:"warn",phase:"record_stop_runner_failed",data:{platform:i.platform,kind:i.kind,deviceId:i.id,session:r.name,error:ee(e)}})}}async function e$(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,n=eI(r);if(n)try{let e=await o.runIosRunnerCommand(i,{command:"snapshot",appBundleId:n,interactiveOnly:!0,depth:1},ex(t,a,r)),s=Date.now();if("number"==typeof e.currentUptimeMs&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0)return b({level:"debug",phase:"record_start_gesture_clock_anchor",data:{source:"warm_snapshot"}}),{gestureClockOriginAtMs:s,gestureClockOriginUptimeMs:e.currentUptimeMs};return}catch(e){b({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:i.id,session:r.name,appBundleId:n,error:ee(e)}});return}}async function eR(e){let t,r,{req:i,activeSession:a,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=ex(i,s,a),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(i){var g,y;if(!ee(i).toLowerCase().includes("recording already in progress"))return h("COMMAND_FAILED",`failed to start recording: ${ee(i)}`);b({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:a.name,error:ee(i)}});let e=(g=n.id,y=a.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 h("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 h("COMMAND_FAILED",`failed to start recording: ${ee(e)}`)}}return{platform:"ios-device-runner",remotePath:f,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...l}}async function ek(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}=e;try{await o.runIosRunnerCommand(i,{command:"recordStart",outPath:s.outPath,fps:n,quality:s.quality,appBundleId:c},ex(t,a,r))}catch(e){return h("COMMAND_FAILED",`failed to start recording: ${ee(e)}`)}return{platform:"macos-runner",...s}}async function eN(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,recording:n}=e;await eD({req:t,activeSession:r,device:i,logPath:a,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of P)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",i.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 h("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 eE(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,recording:n}=e;return await eD({req:t,activeSession:r,device:i,logPath:a,deps:o}),await ei({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eF(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let i=await eO(r.wait,5e3);return i||(await eL(t,r,"SIGINT"),(i=await eO(r.wait,2e3))||(r.child.kill("SIGTERM"),await eL(t,r,"SIGTERM"),i=await eO(r.wait,2e3)))?i:(r.child.kill("SIGKILL"),await eL(t,r,"SIGKILL"),await eO(r.wait,2e3))}async function eO(e,t){return await Promise.race([e,A(t).then(()=>null)])}async function eL(e,t,r){await eU(e,t,r)||await eT(e,t.outPath,r)}async function eT(e,t,r){let i,a=`simctl.*recordVideo.*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`;try{i=await e.runCmd("pgrep",["-f",a],{allowFailure:!0})}catch(e){b({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:ee(e)}});return}let o=eq(eG(i.stdout)),n=eK(o,r);b({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_recorders",data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:n,pgrepExitCode:i.exitCode}})}async function eU(e,t,r){let i=t.recorderPid??t.child.pid;if("number"!=typeof i||!Number.isInteger(i)||i<=0)return b({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let a=await ez(e,i,t.outPath,r),o=eq([i,...a.pids]),n=eK(o,r);return b({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_owned_recorder",data:{outPath:t.outPath,signal:r,recorderPid:i,childPidCount:a.pids.length,matchedPidCount:o.length,signaled:n,pgrepExitCode:a.exitCode}}),n>0}async function ez(e,t,r,i){let a;try{a=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return b({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:i,parentPid:t,error:ee(e)}}),{pids:[]}}return{pids:eG(a.stdout),exitCode:a.exitCode}}function eq(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eK(e,t){let r=0;for(let i of e)try{process.kill(i,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 eV(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await A(350)}async function eH(e){for(let t=0;t<2;t+=1){try{if(a.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)break;await A(250)}return Date.now()}async function ej(e){let t,r,{req:i,activeSession:a,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e,l=c.showTouches?await e$({req:i,activeSession:a,device:o,logPath:n,deps:s}):void 0,{child:u,wait:m}=s.startIosSimulatorRecording({device:o,outPath:d}),f=await eH(d);if(l)t=l.gestureClockOriginAtMs,r=l.gestureClockOriginUptimeMs;else if(c.showTouches)try{let e=Date.now(),c=await s.runIosRunnerCommand(o,{command:"uptime",appBundleId:eI(a)},ex(i,n,a)),d=Date.now();t=Math.round((e+d)/2),r="number"==typeof c.currentUptimeMs?c.currentUptimeMs:void 0}catch{}return{platform:"ios",child:u,wait:m,...c,recorderPid:u.pid,startedAt:f,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function eW(e){let t,{req:r,sessionName:i,sessionStore:n,activeSession:s,device:c,logPath:d,deps:l}=e;if(s.recording)return h("INVALID_ARGS","recording already in progress");let u=r.flags?.fps,f=r.flags?.quality;if(void 0!==u&&(!Number.isInteger(u)||u<1||u>120))return h("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==f&&(!Number.isInteger(f)||f<5||f>10))return h("INVALID_ARGS","quality must be an integer between 5 and 10");if(!p("record",c))return h("UNSUPPORTED_OPERATION","record is not supported on this device");let w=r.positionals?.[1]??`./recording-${Date.now()}.mp4`,g=m.expandHome(w,r.meta?.cwd),y={outPath:g,clientOutPath:r.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),quality:r.flags?.quality,showTouches:r.flags?.hideTouches!==!0,gestureEvents:[]};if(a.mkdirSync(o.dirname(g),{recursive:!0}),a.rmSync(g,{force:!0}),"ios"===c.platform&&"device"===c.kind){let e=eI(s);if(!e)return h("INVALID_ARGS","record on physical iOS devices requires an active app session; run open <app> first");t=await eR({req:r,activeSession:s,sessionStore:n,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:y,appBundleId:e})}else if("macos"===c.platform){let e=eI(s);if(!e)return h("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:y,appBundleId:e})}else t="ios"===c.platform?await ej({req:r,activeSession:s,device:c,logPath:d,deps:l,recordingBase:y,resolvedOut:g}):await eP({device:c,recordingBase:y});if("ok"in t)return t;s.recording=t,n.set(i,s);let _=n.ensureSessionDir(i);return n.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??w,sessionStateDir:_,showTouches:t.showTouches}}}async function eB(e){let{deps:t,device:r,recording:i,stopRequestedAt:a}=e;if("android"===i.platform)return await eb({deps:t,device:r,recording:i,stopRequestedAt:a});await M("record_stop_tail_settle",()=>t.waitForRecordingTail(i),{platform:i.platform,gestureEventCount:i.gestureEvents.length});let o=await M("record_stop_ios_simulator_process",()=>eF({deps:t,recording:i}),{outPath:i.outPath});if(!o)return eJ("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",i,a);if(0!==o.exitCode)return eJ(`failed to stop recording: ${et(o,"simctl recordVideo")}`,i,a);if(await M("record_stop_video_stable",()=>t.waitForStableFile(i.outPath,{pollMs:150,attempts:12}),{outPath:i.outPath}),!await M("record_stop_video_playable_check",()=>t.isPlayableVideo(i.outPath),{outPath:i.outPath}))return eJ(`failed to stop recording: ${i.outPath} was not finalized into a playable video`,i,a);if(void 0!==i.quality&&i.quality<10){let e=i.quality;try{await M("record_stop_resize",()=>t.resizeRecording({videoPath:i.outPath,quality:e,targetLabel:"iOS recording"}),{outPath:i.outPath,quality:e})}catch(e){i.overlayWarning=`failed to resize recording: ${ee(e)}`}}return await M("record_stop_finalize_overlay",()=>ei({recording:i,deps:t,targetLabel:"iOS recording"}),{outPath:i.outPath,showTouches:i.showTouches,gestureEventCount:i.gestureEvents.length}),null}function eJ(e,t,r){let i=er(e,t,r);return function(e){try{a.rmSync(e,{force:!0})}catch{}}(t.outPath),h("COMMAND_FAILED",i.message)}async function eX(e){var t;let r,i,{req:a,activeSession:n,device:s,logPath:c,deps:d}=e;if(!n.recording)return h("INVALID_ARGS","no active recording");let l=n.recording,u=Date.now(),m=l.invalidatedReason;n.recording=void 0;let f="ios-device-runner"===l.platform?await eN({req:a,activeSession:n,device:s,logPath:c,deps:d,recording:l}):"macos-runner"===l.platform?await eE({req:a,activeSession:n,device:s,logPath:c,deps:d,recording:l}):await eB({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 h("COMMAND_FAILED",m);return r="android"===(t=l).platform?t.chunks:void 0,i=[{field:"outPath",path:t.outPath,localPath:t.clientOutPath,fileName:o.basename(t.clientOutPath??t.outPath)}],r&&r.length>1&&i.push(...r.slice(1).map(e=>({field:"chunkPath",path:e.path,localPath:eZ(t,e.index),fileName:o.basename(eZ(t,e.index)??e.path)}))),t.telemetryPath&&i.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return j(e.clientOutPath)}(t),fileName:o.basename(t.telemetryPath)}),{ok:!0,data:{recording:"stopped",outPath:t.outPath,telemetryPath:t.telemetryPath,artifacts:i,showTouches:t.showTouches,warning:t.warning,overlayWarning:t.overlayWarning,chunks:r?.map(e=>({index:e.index,path:eZ(t,e.index)??e.path}))}}}function eZ(e,t){if("android"===e.platform&&e.clientOutPath)return ea(e.clientOutPath,t)}function eQ(e,t,r,i={}){r.recordOnlySession&&(i.writeLog&&e.writeSessionLog(r),e.delete(t))}async function eY(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await u(t,r):await l(e,t,r),startIosSimulatorRecording:e=>D().startIosSimulatorRecording(e),runIosRunnerCommand:f,waitForRecordingTail:eV,waitForStableFile:z,isPlayableVideo:q,trimRecordingStart:Z,resizeRecording:Y,overlayRecordingTouches:Q},n=i.get(r),s=n?.device??await v(t.flags??{});n||await g(s);let c=n??{name:y(t),sessionScope:_(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return h("INVALID_ARGS","record requires start|stop");if("start"===d)return eW({req:t,sessionName:r,sessionStore:i,activeSession:c,device:s,logPath:a,deps:o});let m=await eX({req:t,activeSession:c,device:s,logPath:a,deps:o});return m.ok?(i.recordAction(c,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:m.data?.outPath,showTouches:m.data?.showTouches}}),eQ(i,r,c,{writeLog:!0})):eQ(i,r,c),m}export{eY as handleRecordCommand};
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 H(e){try{let t=a.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=function(e){try{let t=a.openSync(e,"r");try{let e=a.fstatSync(t).size,r=0,i=[];for(;r+8<=e&&i.length<16;){let e=Buffer.alloc(8);if(8>a.readSync(t,e,0,8,r))break;let o=e.readUInt32BE(0),n=e.toString("latin1",4,8);if(i.push(n),1===o){let e=Buffer.alloc(8);if(8>a.readSync(t,e,0,8,r+8))break;o=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(o)||o<=0)break;r+=o}return i}finally{a.closeSync(t)}}catch{return[]}}(e);return t.includes("ftyp")&&t.includes("moov")}function j(e){let t=o.parse(e);return o.join(t.dir,`${t.name}.gesture-telemetry.json`)}function W(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function B(e){var t,r,i;let o,n,{recording:s,trimStartMs:c}=e,d=(o=j((t={videoPath:s.outPath,events:s.gestureEvents,trimStartMs:c}).videoPath),n={version:1,generatedAt:new Date().toISOString(),events:(r=t.events,(i=t.trimStartMs??0)>0?W(r.flatMap(e=>{let t=e.tMs-i,r="durationMs"in e?e.durationMs:void 0;return("number"==typeof r?t+r:t)<=0?[]:[{...e,tMs:Math.max(0,t)}]})):W(r))},a.writeFileSync(o,JSON.stringify(n,null,2)),o);return s.telemetryPath=d,d}function X(e){let t=o.dirname(c(import.meta.url)),r=[c(new URL(`./${e}`,import.meta.url)),o.resolve(t,`../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(t,`../../../ios-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(process.cwd(),`ios-runner/AgentDeviceRunner/RecordingScripts/${e}`)];for(let e of r)if(a.existsSync(e))return e;throw new d("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 J(e){var t;let r,i,{videoPath:n,scriptPath:s,scriptArgs:c,commandDescription:u}=e;await z(n),await G(n);let m=(t=n,r=o.parse(t),i=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,o.join(r.dir,`.${r.name}.agent-device-${i}${r.ext||".mp4"}`));try{let e=await R({sourcePath:s});await l(e,["--input",n,"--output",m,...c],{timeoutMs:12e4,env:$()}),await G(m),a.renameSync(m,n)}catch(t){let e=t instanceof d?t:new d("COMMAND_FAILED",String(t),void 0,t instanceof Error?t:void 0);throw new d("COMMAND_FAILED",u,{...e.details,videoPath:n,script:s},e)}finally{a.rmSync(m,{force:!0})}}async function Z(e){let{videoPath:t,trimStartMs:i}=e;i>0&&await J({videoPath:t,scriptPath:r??=X("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(i)],commandDescription:"Failed to trim the start of the iOS recording"})}async function Q(e){let{videoPath:r,telemetryPath:i,targetLabel:a="recording"}=e;await J({videoPath:r,scriptPath:t??=X("recording-overlay.swift"),scriptArgs:["--events",i],commandDescription:`Failed to add touch overlays to the ${a}`})}async function Y(e){let{videoPath:t,quality:r,targetLabel:a="recording"}=e;await J({videoPath:t,scriptPath:i??=X("recording-resize.swift"),scriptArgs:["--quality",String(r)],commandDescription:`Failed to resize the ${a}`})}function ee(e){return e instanceof Error?e.message:String(e)}function et(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function er(e,t,r=Date.now()){let i=Math.max(0,r-t.startedAt);return i>=1e3?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(i)}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:i,targetLabel:a}=e,o=B({recording:t,trimStartMs:i});if(!t.showTouches)return void b({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void b({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 M("record_stop_overlay_export",()=>r.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:o,targetLabel:a}),{targetLabel:a,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${ee(e)}`}}function ea(e,t){if(1===t)return e;let r=o.parse(e),i=r.ext||".mp4";return o.join(r.dir,`${r.name}.part-${String(t).padStart(3,"0")}${i}`)}function eo(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function en(e){let{recording:t,startNextChunk:r,finishCurrentChunk:i}=e;if(t.stopping)return;let a=await i();if(a)throw Error(a);if(t.stopping)return;let n=eo(t),s=n.length+1,c=await r(o.posix.dirname(t.remotePath));t.remotePath=c.remotePath,t.remotePid=c.remotePid,n.push({index:s,path:ea(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 es(e){let{recording:t,deps:r}=e;eo(t).length<=1?await ei({recording:t,deps:r,targetLabel:"Android recording"}):(B({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 ec(e){for(let t of e.chunks){let r=await ed({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 ed(e){let t,{deps:r,deviceId:i,remotePath:o,outPath:n}=e;for(let e=0;e<2;e+=1){el(n);let s=C(i),c=await x(o,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=et(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(b({level:"debug",phase:"record_stop_android_pull_validation",data:{deviceId:i,remotePath:o,outPath:n,attempt:e+1,fileSize:function(e){try{return a.statSync(e).size}catch{return 0}}(n),playable:t}}),t)return;b({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:i,remotePath:o,outPath:n,attempt:e+1}})}e<1&&await A(750)}return t?`failed to copy recording from device: ${t}`:(el(n),"failed to copy recording from device: pulled file is not a playable MP4")}function el(e){try{a.rmSync(e,{force:!0})}catch{}}async function eu(e,t,r){return await I(C(e),t,r)}async function em(e,t){let r=await eu(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 ef(e,t){for(let r=0;r<40;r+=1){if(!await em(e,t))return!0;await A(250)}return!await em(e,t)}async function ep(e,t){let r,i=0;for(let a=0;a<20;a+=1){let a=await eu(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===a.exitCode?a.stdout.trim():"";if(o.length>0&&o===r){if((i+=1)>=4)return}else i=0;r=o,await A(250)}}async function eh(e,t,r){for(let i=0;i<8;i+=1){let a=await eu(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===a.exitCode?Number(a.stdout.trim()):NaN;if(Number.isFinite(o)&&o>0)return!0;if(!await em(e,r))break;if(i+1>=2)return!0;await A(250)}return!1}async function ew(e){let{deviceId:t,quality:r}=e;if(void 0===r||r>=10)return;let i=await eu(t,["shell","wm","size"],{allowFailure:!0}),a=i.stdout.match(/Override size:\s*(\d+)x(\d+)/)??i.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(0!==i.exitCode||!a)throw Error(`failed to resolve Android screen size for recording quality: ${et(i,"adb shell wm size")}`);return{width:eg(Number(a[1]),r),height:eg(Number(a[2]),r)}}function eg(e,t){return Math.max(2,2*Math.round(e*t/10/2))}async function ey(e,t){await eu(e,["shell","rm","-f",t],{allowFailure:!0})}async function e_(e,t){let r=await eu(e,["shell","kill","-9",t],{allowFailure:!0});return b({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 em(e,t))&&await ef(e,t)}async function ev(e){var t;let r,i,{device:a,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`,i=["/sdcard","/data/local/tmp"],(n&&i.includes(n)?[n,...i.filter(e=>e!==n)]:i).map(e=>`${e}/${r}`))){let t=await eu(a.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: ${et(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 ey(a.id,e);continue}if(b({level:"debug",phase:"record_start_android_started",data:{deviceId:a.id,remotePath:e,remotePid:r}}),await eh(a.id,e,r))return{remotePath:e,remotePid:r,startedAt:Date.now()};s="failed to start recording: Android screenrecord did not begin producing frames",await e_(a.id,r),await ey(a.id,e)}return{error:h("COMMAND_FAILED",s)}}async function eP(e){let t,{device:r,recordingBase:i}=e;try{t=await ew({deviceId:r.id,quality:i.quality})}catch(e){return h("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let a=await ev({device:r,recordingSize:t});if("error"in a)return a.error;let o={platform:"android",remotePath:a.remotePath,remotePid:a.remotePid,chunks:[{index:1,path:i.outPath,remotePath:a.remotePath}],...i,startedAt:a.startedAt};return!function e(t){let{recording:r,startNextChunk:i,finishCurrentChunk:a}=t,o=setTimeout(()=>{r.rotationPromise=en({recording:r,startNextChunk:i,finishCurrentChunk:a}).catch(e=>{r.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{r.rotationPromise=void 0,r.stopping||r.rotationFailedReason||e({recording:r,startNextChunk:i,finishCurrentChunk:a})})},17e4);o.unref?.(),r.rotationTimer=o}({recording:o,finishCurrentChunk:async()=>await eS({device:r,recording:o,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let i=await ev({device:r,recordingSize:t,preferredRemoteDir:e});if("error"in i)throw Error(i.error.ok?"failed to start next Android recording chunk":i.error.error.message);return i}}),o}async function eS(e){let{device:t,recording:r,waitForRemoteFileStability:i=!0}=e;await em(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 a=await eu(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(b({level:"debug",phase:"record_stop_android_signal",data:{deviceId:t.id,remotePath:r.remotePath,remotePid:r.remotePid,exitCode:a.exitCode,stdout:a.stdout.trim(),stderr:a.stderr.trim()}}),0!==a.exitCode)return await eA(t.id,r.remotePid,a);let o=await eM(t.id,r.remotePid);if(o)return o;i&&await ep(t.id,r.remotePath)}async function eA(e,t,r){if(await em(e,t)&&!await e_(e,t))return`failed to stop recording: ${et(r,"adb shell kill")}`}async function eM(e,t){if(!await ef(e,t)&&!await e_(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function eb(e){let t,{deps:r,device:i,recording:a,stopRequestedAt:o}=e;b({level:"debug",phase:"record_stop_android_enter",data:{deviceId:i.id,remotePath:a.remotePath,remotePid:a.remotePid}}),a.stopping=!0,a.rotationTimer&&(clearTimeout(a.rotationTimer),a.rotationTimer=void 0),await a.rotationPromise;let n=await eS({device:i,recording:a});if(a.rotationFailedReason&&!n&&(a.warning??=`Android recording chunk rotation failed: ${a.rotationFailedReason}`),!n){let e=await ec({deps:r,deviceId:i.id,chunks:eo(a)});if(e)return await s(),h("COMMAND_FAILED",eC(e,a,o));await es({recording:a,deps:r})}if(await s(),n)return h("COMMAND_FAILED",eC(n,a,o));if(t)return h("COMMAND_FAILED",t);return null;async function s(){for(let e of eo(a)){let r=await eu(i.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});b({level:"debug",phase:"record_stop_android_cleanup",data:{deviceId:i.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: ${et(r,"adb shell rm")}`)}}}function eC(e,t,r){return er(e,t,r).message}function eI(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function ex(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath,requestId:e.meta?.requestId,iosXctestrunFile:e.flags?.iosXctestrunFile,iosXctestDerivedDataPath:e.flags?.iosXctestDerivedDataPath,iosXctestEnvDir:e.flags?.iosXctestEnvDir}}async function eD(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,n=eI(r);try{await o.runIosRunnerCommand(i,{command:"recordStop",appBundleId:n},ex(t,a,r))}catch(e){b({level:"warn",phase:"record_stop_runner_failed",data:{platform:i.platform,kind:i.kind,deviceId:i.id,session:r.name,error:ee(e)}})}}async function e$(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,n=eI(r);if(n)try{let e=await o.runIosRunnerCommand(i,{command:"snapshot",appBundleId:n,interactiveOnly:!0,depth:1},ex(t,a,r)),s=Date.now();if("number"==typeof e.currentUptimeMs&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0)return b({level:"debug",phase:"record_start_gesture_clock_anchor",data:{source:"warm_snapshot"}}),{gestureClockOriginAtMs:s,gestureClockOriginUptimeMs:e.currentUptimeMs};return}catch(e){b({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:i.id,session:r.name,appBundleId:n,error:ee(e)}});return}}async function eR(e){let t,r,{req:i,activeSession:a,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=ex(i,s,a),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(i){var g,y;if(!ee(i).toLowerCase().includes("recording already in progress"))return h("COMMAND_FAILED",`failed to start recording: ${ee(i)}`);b({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:a.name,error:ee(i)}});let e=(g=n.id,y=a.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 h("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 h("COMMAND_FAILED",`failed to start recording: ${ee(e)}`)}}return{platform:"ios-device-runner",remotePath:f,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...l}}async function ek(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}=e;try{await o.runIosRunnerCommand(i,{command:"recordStart",outPath:s.outPath,fps:n,quality:s.quality,appBundleId:c},ex(t,a,r))}catch(e){return h("COMMAND_FAILED",`failed to start recording: ${ee(e)}`)}return{platform:"macos-runner",...s}}async function eE(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,recording:n}=e;await eD({req:t,activeSession:r,device:i,logPath:a,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of P)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",i.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 h("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 eN(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o,recording:n}=e;return await eD({req:t,activeSession:r,device:i,logPath:a,deps:o}),await ei({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eF(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let i=await eO(r.wait,5e3);return i||(await eL(t,r,"SIGINT"),(i=await eO(r.wait,2e3))||(r.child.kill("SIGTERM"),await eL(t,r,"SIGTERM"),i=await eO(r.wait,2e3)))?i:(r.child.kill("SIGKILL"),await eL(t,r,"SIGKILL"),await eO(r.wait,2e3))}async function eO(e,t){return await Promise.race([e,A(t).then(()=>null)])}async function eL(e,t,r){await eU(e,t,r)||await eT(e,t.outPath,r)}async function eT(e,t,r){let i,a=`simctl.*recordVideo.*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`;try{i=await e.runCmd("pgrep",["-f",a],{allowFailure:!0})}catch(e){b({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:ee(e)}});return}let o=eq(eG(i.stdout)),n=eK(o,r);b({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_recorders",data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:n,pgrepExitCode:i.exitCode}})}async function eU(e,t,r){let i=t.recorderPid??t.child.pid;if("number"!=typeof i||!Number.isInteger(i)||i<=0)return b({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let a=await ez(e,i,t.outPath,r),o=eq([i,...a.pids]),n=eK(o,r);return b({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_owned_recorder",data:{outPath:t.outPath,signal:r,recorderPid:i,childPidCount:a.pids.length,matchedPidCount:o.length,signaled:n,pgrepExitCode:a.exitCode}}),n>0}async function ez(e,t,r,i){let a;try{a=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return b({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:i,parentPid:t,error:ee(e)}}),{pids:[]}}return{pids:eG(a.stdout),exitCode:a.exitCode}}function eq(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eK(e,t){let r=0;for(let i of e)try{process.kill(i,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 eV(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await A(350)}async function eH(e){for(let t=0;t<2;t+=1){try{if(a.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)break;await A(250)}return Date.now()}async function ej(e){let t,r,{req:i,activeSession:a,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e,l=c.showTouches?await e$({req:i,activeSession:a,device:o,logPath:n,deps:s}):void 0,{child:u,wait:m}=s.startIosSimulatorRecording({device:o,outPath:d}),f=await eH(d);if(l)t=l.gestureClockOriginAtMs,r=l.gestureClockOriginUptimeMs;else if(c.showTouches)try{let e=Date.now(),c=await s.runIosRunnerCommand(o,{command:"uptime",appBundleId:eI(a)},ex(i,n,a)),d=Date.now();t=Math.round((e+d)/2),r="number"==typeof c.currentUptimeMs?c.currentUptimeMs:void 0}catch{}return{platform:"ios",child:u,wait:m,...c,recorderPid:u.pid,startedAt:f,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function eW(e){let t,{req:r,sessionName:i,sessionStore:n,activeSession:s,device:c,logPath:d,deps:l}=e;if(s.recording)return h("INVALID_ARGS","recording already in progress");let u=r.flags?.fps,f=r.flags?.quality;if(void 0!==u&&(!Number.isInteger(u)||u<1||u>120))return h("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==f&&(!Number.isInteger(f)||f<5||f>10))return h("INVALID_ARGS","quality must be an integer between 5 and 10");if(!p("record",c))return h("UNSUPPORTED_OPERATION","record is not supported on this device");let w=r.positionals?.[1]??`./recording-${Date.now()}.mp4`,g=m.expandHome(w,r.meta?.cwd),y={outPath:g,clientOutPath:r.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),quality:r.flags?.quality,showTouches:r.flags?.hideTouches!==!0,gestureEvents:[]};if(a.mkdirSync(o.dirname(g),{recursive:!0}),a.rmSync(g,{force:!0}),"ios"===c.platform&&"device"===c.kind){let e=eI(s);if(!e)return h("INVALID_ARGS","record on physical iOS devices requires an active app session; run open <app> first");t=await eR({req:r,activeSession:s,sessionStore:n,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:y,appBundleId:e})}else if("macos"===c.platform){let e=eI(s);if(!e)return h("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:y,appBundleId:e})}else t="ios"===c.platform?await ej({req:r,activeSession:s,device:c,logPath:d,deps:l,recordingBase:y,resolvedOut:g}):await eP({device:c,recordingBase:y});if("ok"in t)return t;s.recording=t,n.set(i,s);let _=n.ensureSessionDir(i);return n.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??w,sessionStateDir:_,showTouches:t.showTouches}}}async function eB(e){let{deps:t,device:r,recording:i,stopRequestedAt:a}=e;if("android"===i.platform)return await eb({deps:t,device:r,recording:i,stopRequestedAt:a});await M("record_stop_tail_settle",()=>t.waitForRecordingTail(i),{platform:i.platform,gestureEventCount:i.gestureEvents.length});let o=await M("record_stop_ios_simulator_process",()=>eF({deps:t,recording:i}),{outPath:i.outPath});if(!o)return eX("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",i,a);if(0!==o.exitCode)return eX(`failed to stop recording: ${et(o,"simctl recordVideo")}`,i,a);if(await M("record_stop_video_stable",()=>t.waitForStableFile(i.outPath,{pollMs:150,attempts:12}),{outPath:i.outPath}),!await M("record_stop_video_playable_check",()=>t.isPlayableVideo(i.outPath),{outPath:i.outPath}))return eX(`failed to stop recording: ${i.outPath} was not finalized into a playable video`,i,a);if(void 0!==i.quality&&i.quality<10){let e=i.quality;try{await M("record_stop_resize",()=>t.resizeRecording({videoPath:i.outPath,quality:e,targetLabel:"iOS recording"}),{outPath:i.outPath,quality:e})}catch(e){i.overlayWarning=`failed to resize recording: ${ee(e)}`}}return await M("record_stop_finalize_overlay",()=>ei({recording:i,deps:t,targetLabel:"iOS recording"}),{outPath:i.outPath,showTouches:i.showTouches,gestureEventCount:i.gestureEvents.length}),null}function eX(e,t,r){let i=er(e,t,r);return function(e){try{a.rmSync(e,{force:!0})}catch{}}(t.outPath),h("COMMAND_FAILED",i.message)}async function eJ(e){var t;let r,i,{req:a,activeSession:n,device:s,logPath:c,deps:d}=e;if(!n.recording)return h("INVALID_ARGS","no active recording");let l=n.recording,u=Date.now(),m=l.invalidatedReason;n.recording=void 0;let f="ios-device-runner"===l.platform?await eE({req:a,activeSession:n,device:s,logPath:c,deps:d,recording:l}):"macos-runner"===l.platform?await eN({req:a,activeSession:n,device:s,logPath:c,deps:d,recording:l}):await eB({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 h("COMMAND_FAILED",m);return r="android"===(t=l).platform?t.chunks:void 0,i=[{field:"outPath",path:t.outPath,localPath:t.clientOutPath,fileName:o.basename(t.clientOutPath??t.outPath)}],r&&r.length>1&&i.push(...r.slice(1).map(e=>({field:"chunkPath",path:e.path,localPath:eZ(t,e.index),fileName:o.basename(eZ(t,e.index)??e.path)}))),t.telemetryPath&&i.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return j(e.clientOutPath)}(t),fileName:o.basename(t.telemetryPath)}),{ok:!0,data:{recording:"stopped",outPath:t.outPath,telemetryPath:t.telemetryPath,artifacts:i,showTouches:t.showTouches,warning:t.warning,overlayWarning:t.overlayWarning,chunks:r?.map(e=>({index:e.index,path:eZ(t,e.index)??e.path}))}}}function eZ(e,t){if("android"===e.platform&&e.clientOutPath)return ea(e.clientOutPath,t)}function eQ(e,t,r,i={}){r.recordOnlySession&&(i.writeLog&&e.writeSessionLog(r),e.delete(t))}async function eY(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await u(t,r):await l(e,t,r),startIosSimulatorRecording:e=>D().startIosSimulatorRecording(e),runIosRunnerCommand:f,waitForRecordingTail:eV,waitForStableFile:z,isPlayableVideo:q,trimRecordingStart:Z,resizeRecording:Y,overlayRecordingTouches:Q},n=i.get(r),s=n?.device??await v(t.flags??{});n||await g(s);let c=n??{name:y(t),sessionScope:_(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return h("INVALID_ARGS","record requires start|stop");if("start"===d)return eW({req:t,sessionName:r,sessionStore:i,activeSession:c,device:s,logPath:a,deps:o});let m=await eJ({req:t,activeSession:c,device:s,logPath:a,deps:o});return m.ok?(i.recordAction(c,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:m.data?.outPath,showTouches:m.data?.showTouches}}),eQ(i,r,c,{writeLog:!0})):eQ(i,r,c),m}export{eY as handleRecordCommand};
@@ -1 +1 @@
1
- import t from"node:fs";import e from"node:path";import{SessionStore as r,errorResponse as a}from"./2415.js";import{handleRecordCommand as o}from"./record-trace-recording.js";async function i(i){let{req:n,sessionName:s,sessionStore:c,logPath:l}=i,d=n.command;if("record"===d)return o({req:n,sessionName:s,sessionStore:c,logPath:l});if("trace"===d){let o=(n.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(o))return a("INVALID_ARGS","trace requires start|stop");let i=c.get(s);if(!i)return a("SESSION_NOT_FOUND","No active session");if("start"===o){if(i.trace)return a("INVALID_ARGS","trace already in progress");let o=n.positionals?.[1]??c.defaultTracePath(i),s=r.expandHome(o);return t.mkdirSync(e.dirname(s),{recursive:!0}),t.appendFileSync(s,""),i.trace={outPath:s,startedAt:Date.now()},c.recordAction(i,{command:d,positionals:n.positionals??[],flags:n.flags??{},result:{action:"start",outPath:s}}),{ok:!0,data:{trace:"started",outPath:s}}}if(!i.trace)return a("INVALID_ARGS","no active trace");let l=i.trace.outPath;if(n.positionals?.[1]){let a=r.expandHome(n.positionals[1]);t.mkdirSync(e.dirname(a),{recursive:!0}),t.existsSync(l)?t.renameSync(l,a):t.appendFileSync(a,""),l=a}return i.trace=void 0,c.recordAction(i,{command:d,positionals:n.positionals??[],flags:n.flags??{},result:{action:"stop",outPath:l}}),{ok:!0,data:{trace:"stopped",outPath:l}}}return null}export{i as handleRecordTraceCommands};
1
+ import t from"node:fs";import e from"node:path";import{SessionStore as r,errorResponse as a}from"./9722.js";import{handleRecordCommand as o}from"./record-trace-recording.js";async function i(i){let{req:n,sessionName:s,sessionStore:c,logPath:l}=i,d=n.command;if("record"===d)return o({req:n,sessionName:s,sessionStore:c,logPath:l});if("trace"===d){let o=(n.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(o))return a("INVALID_ARGS","trace requires start|stop");let i=c.get(s);if(!i)return a("SESSION_NOT_FOUND","No active session");if("start"===o){if(i.trace)return a("INVALID_ARGS","trace already in progress");let o=n.positionals?.[1]??c.defaultTracePath(i),s=r.expandHome(o);return t.mkdirSync(e.dirname(s),{recursive:!0}),t.appendFileSync(s,""),i.trace={outPath:s,startedAt:Date.now()},c.recordAction(i,{command:d,positionals:n.positionals??[],flags:n.flags??{},result:{action:"start",outPath:s}}),{ok:!0,data:{trace:"started",outPath:s}}}if(!i.trace)return a("INVALID_ARGS","no active trace");let l=i.trace.outPath;if(n.positionals?.[1]){let a=r.expandHome(n.positionals[1]);t.mkdirSync(e.dirname(a),{recursive:!0}),t.existsSync(l)?t.renameSync(l,a):t.appendFileSync(a,""),l=a}return i.trace=void 0,c.recordAction(i,{command:d,positionals:n.positionals??[],flags:n.flags??{},result:{action:"stop",outPath:l}}),{ok:!0,data:{trace:"stopped",outPath:l}}}return null}export{i as handleRecordTraceCommands};
@@ -1 +1 @@
1
- import{createScopedProvider as r,buildSimctlArgsForDevice as o}from"./2415.js";import{runCmdBackground as e}from"./9818.js";let i={startIosSimulatorRecording:({device:r,outPath:i})=>e("xcrun",o(r,["io",r.id,"recordVideo",i]),{allowFailure:!0})},n=r(i,function(r={}){return{...i,...r}});function t(r){return n.resolve(r)}async function u(r,o){return await n.run(r,o)}export{t as resolveRecordingProvider,u as withRecordingProvider};
1
+ import{createScopedProvider as r,buildSimctlArgsForDevice as o}from"./9722.js";import{runCmdBackground as e}from"./8875.js";let i={startIosSimulatorRecording:({device:r,outPath:i})=>e("xcrun",o(r,["io",r.id,"recordVideo",i]),{allowFailure:!0})},n=r(i,function(r={}){return{...i,...r}});function t(r){return n.resolve(r)}async function u(r,o){return await n.run(r,o)}export{t as resolveRecordingProvider,u as withRecordingProvider};
@@ -1,16 +1,16 @@
1
- declare const DAEMON_SERVER_MODES: readonly ["socket", "http", "dual"];
1
+ declare const DAEMON_SERVER_MODES: readonly ['socket', 'http', 'dual'];
2
2
 
3
- declare const DAEMON_TRANSPORT_PREFERENCES: readonly ["auto", "socket", "http"];
3
+ declare const DAEMON_TRANSPORT_PREFERENCES: readonly ['auto', 'socket', 'http'];
4
4
 
5
5
  declare type DaemonServerMode = (typeof DAEMON_SERVER_MODES)[number];
6
6
 
7
7
  declare type DaemonTransportPreference = (typeof DAEMON_TRANSPORT_PREFERENCES)[number];
8
8
 
9
- declare const DEVICE_TARGETS: readonly ["mobile", "tv", "desktop"];
9
+ declare const DEVICE_TARGETS: readonly ['mobile', 'tv', 'desktop'];
10
10
 
11
11
  declare type DeviceTarget = (typeof DEVICE_TARGETS)[number];
12
12
 
13
- declare const LEASE_BACKENDS: readonly ["ios-simulator", "ios-instance", "android-instance"];
13
+ declare const LEASE_BACKENDS: readonly ['ios-simulator', 'ios-instance', 'android-instance'];
14
14
 
15
15
  declare type LeaseBackend = (typeof LEASE_BACKENDS)[number];
16
16
 
@@ -72,7 +72,7 @@ export declare function resolveRemoteConfigPath(options: RemoteConfigProfileOpti
72
72
 
73
73
  export declare function resolveRemoteConfigProfile(options: RemoteConfigProfileOptions): ResolvedRemoteConfigProfile;
74
74
 
75
- declare const SESSION_ISOLATION_MODES: readonly ["none", "tenant"];
75
+ declare const SESSION_ISOLATION_MODES: readonly ['none', 'tenant'];
76
76
 
77
77
  declare type SessionIsolationMode = (typeof SESSION_ISOLATION_MODES)[number];
78
78
 
@@ -1 +1 @@
1
- export{resolveRemoteConfigPath,resolveRemoteConfigProfile}from"./208.js";
1
+ export{resolveRemoteConfigPath,resolveRemoteConfigProfile}from"./4723.js";
@@ -1 +1 @@
1
- var e={};e.d=(o,r)=>{for(var t in r)e.o(r,t)&&!e.o(o,t)&&Object.defineProperty(o,t,{enumerable:!0,get:r[t]})},e.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),e.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};export{e as __webpack_require__};
1
+ var e={};e.d=(r,o,t)=>{var a=(o,t)=>{for(var a in o)e.o(o,a)&&!e.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,[t]:o[a]})};a(o,"get"),a(t,"value")},e.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};export{e as __webpack_require__};
@@ -1 +1 @@
1
- import{createDaemonRuntimeSessionStore as e,setSessionSnapshot as t,captureSnapshot as r,dispatchCommand as n,runIosRunnerCommand as s,isCommandSupportedOnDevice as o,errorResponse as i,ensureDeviceReady as a,stopIosRunnerSession as l,resolveRunnerAppBundleId as u,getActiveAndroidSnapshotFreshness as c,resolveTargetDevice as d,context_contextFromFlags as f}from"./2415.js";import{closeIosApp as p}from"./apps.js";import{emitDiagnostic as m}from"./7599.js";import{asAppError as g,normalizeError as h,AppError as y}from"./9152.js";import{evaluateIsPredicate as w,isSupportedPredicate as _,localCommandPolicy as S,createAgentDevice as x}from"./123.js";import{tryParseSelectorChain as k,extractNodeReadText as I,prefersValueForReadableText as v,findNodeByLabel as N,normalizeType as A,splitIsSelectorArgs as P}from"./7847.js";import{resolveRectCenter as R,isSparseSnapshotQualityVerdict as b,parseWaitPositionals as E}from"./6133.js";import{getAndroidAppState as q}from"./8806.js";import{buildSnapshotPresentationKey as C,isApplePlatform as M,snapshotPresentationOptionsFromFlags as D}from"./9616.js";import{parseFindArgs as O}from"./7556.js";async function $(e,t,r){let n=e.get(t),s=n?.device??await d(r??{});return n||await a(s),{session:n,device:s}}async function L(e,t,r){let n=!e&&"ios"===t.platform;try{return await r()}finally{n&&(await l(t.id),await U(t))}}async function U(e){let t=u();await p(e,t).catch(r=>{m({level:"debug",phase:"ios_sessionless_runner_host_close_failed",data:{deviceId:e.id,bundleId:t,error:r instanceof Error?r.message:String(r)}})})}function K(e,t,r,n){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:n})}function T(e){let{session:t,sessionName:r,device:n,snapshot:s,appBundleId:o}=e;return t?{...t,snapshot:s,lastComparisonSafeSnapshot:s?.comparisonSafe===!0?s:t.lastComparisonSafeSnapshot}:{name:r,device:n,createdAt:Date.now(),appBundleId:o,snapshot:s,...s?.comparisonSafe===!0?{lastComparisonSafeSnapshot:s}:{},actions:[]}}function G(e,t={}){return{artifacts:function(e,t={}){let r=!0===t.plural?"do":"does";return{resolveInput:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not resolve input artifacts`)},reserveOutput:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not reserve output artifacts`)},createTempFile:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not create temporary files`)}}}(e,t),policy:S()}}async function V(e){let{device:t,node:r,flags:s,appBundleId:o,traceOutPath:i,surface:a,contextFromFlags:l}=e,u=I(r),c=R(r.rect);if(!c||"ios"===t.platform&&u&&!v(r.type??""))return u;try{let e=await n(t,"read",[String(c.x),String(c.y)],void 0,{...l(s,o,i),surface:a}),d=e&&"object"==typeof e?e:void 0,f="string"==typeof d?.text?d.text:"";if(f.trim())return f;return m({level:"warn",phase:"interaction_read_fallback",data:{reason:"empty_backend_text",nodeRef:r.ref,surface:a,platform:t.platform}}),u}catch(e){return m({level:"warn",phase:"interaction_read_fallback",data:{reason:"backend_read_failed",nodeRef:r.ref,surface:a,platform:t.platform,error:e instanceof Error?e.message:String(e)}}),u}}let F=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function B(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,n]of F)void 0!==e[r]&&t.push(n);return t}(t);return 0===r.length?null:i("INVALID_ARGS",`${e} @ref does not support ${r.join(", ")}.`)}async function j(e,t){let r=await H(e);if(r)throw new y("COMMAND_FAILED",`press ${t} left ${e.appBundleId} and foregrounded ${r.foregroundPackage}. The tap likely escaped the app.`,r)}async function H(e){var t;if("android"!==e.device.platform||!e.appBundleId)return null;let r=await q(e.device),n=r.package?.trim();return n&&n!==e.appBundleId&&("com.android.settings"===(t=n)||"com.android.systemui"===t||"com.google.android.permissioncontroller"===t||t.includes("launcher"))?{expectedPackage:e.appBundleId,foregroundPackage:n,activity:r.activity,hint:"com.google.android.permissioncontroller"===n?"Dismiss or allow the permission prompt, then retry the smoke assertion.":"Use screenshot as visual truth, then take a fresh snapshot -i before retrying."}:null}function W(e){return"COMMAND_FAILED"===e.code&&"string"==typeof e.details?.expectedPackage&&"string"==typeof e.details?.foregroundPackage}function z(e,t){let r=Array.isArray(e.selectorChain)?e.selectorChain:void 0,n=Y(e),s=n?.kind==="ref"?Z(n.ref):void 0,o=n?.kind==="selector"?n.selector:void 0,i={...s?{ref:s}:{},...o?{selector:o}:{},...r?{selectorChain:r}:{}};if("attrs"===t)return i;let a="string"==typeof e.text?e.text:"";return{...i,text:a,refLabel:function(e){let t=e.trim();if(!(!t||t.length>80||/[\r\n]/.test(t)))return t}(a)}}function Q(e){let t=Y(e);return{...t?.kind==="ref"?{ref:Z(t.ref)}:{},...t?.kind==="selector"?{selector:t.selector}:{},..."string"==typeof e.text?{text:e.text}:{},...e.node&&"object"==typeof e.node?{node:e.node}:{}}}function J(e){let{selectorChain:t,...r}=e;return r}function X(e,t,r,n){let s=e.get(t);s&&e.recordAction(s,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:n})}function Y(e){let t=e.target;return t&&"object"==typeof t?"ref"===t.kind&&"string"==typeof t.ref?{kind:"ref",ref:t.ref}:"selector"===t.kind&&"string"==typeof t.selector?{kind:"selector",selector:t.selector}:void 0:void 0}function Z(e){return e.startsWith("@")?e.slice(1):e}let ee=["application","window","tabbar","scrollbar","image"],et=new Set(["tab bar"]);async function er(e,t){var r;if(t.ok||(r=t.error.message,!/^wait timed out for (?:selector|text): /i.test(r)))return t;let n=await en(e).catch(()=>null);return n?i(t.error.code,`${t.error.message}. Current surface: ${n.summary}.`,{...t.error.details??{},currentSurface:n.details}):t}async function en(e){let t=[...(await r({device:e.device,session:e.session,flags:{...e.req.flags,snapshotInteractiveOnly:!0},logPath:e.logPath??""})).snapshot.nodes].sort(eo),n=es(t,6,{includeIdentifiers:!0});if(0===n.length)return null;let s=es(t.filter(e=>!el(e)),4,{includeIdentifiers:!1}),o=es(t.filter(eu),4,{includeIdentifiers:!0});return{summary:(s.length>0?s:n.slice(0,4)).join(", "),details:{labels:n,...o.length>0?{buttons:o}:{}}}}function es(e,t,r){let n=new Set,s=[];for(let o of e){let e=ea(o,r);if(!(!e||n.has(e))&&(n.add(e),s.push(e),s.length>=t))break}return s}function eo(e,t){var r,n;return ei(e)-ei(t)||(r=e,n=t,r.rect&&n.rect?r.rect.y-n.rect.y||r.rect.x-n.rect.x:r.rect?-1:n.rect?1:(r.depth??0)-(n.depth??0)||r.index-n.index)}function ei(e){let t=!!ea(e,{includeIdentifiers:!1});return 2*!!el(e)+ +!t}function ea(e,t){let r=(t.includeIdentifiers?[e.label,e.value,e.identifier]:[e.label,e.value]).map(e=>"string"==typeof e?e.trim():"").find(e=>e.length>0);return r?r.replace(/\s+/g," ").slice(0,80):""}function el(e){let t=A(`${e.type??""} ${e.role??""} ${e.subrole??""}`),r=`${e.label??""} ${e.value??""}`.trim().toLowerCase();return ee.some(e=>t.includes(e))||et.has(r)||r.endsWith(".fill")}function eu(e){return A(`${e.type??""} ${e.role??""} ${e.subrole??""}`).includes("button")}function ec(e){var t;let{session:r,selectorExpression:n}=e;if(!r||"ios"!==r.device.platform||r.postGestureStabilization)return null;let s=k(n);if(!s||1!==s.selectors.length)return null;let o=s.selectors[0];if(!o||1!==o.terms.length)return null;let i=o.terms[0];return i&&"string"==typeof i.value&&("id"===(t=i.key)||"label"===t||"text"===t||"value"===t)?{key:i.key,value:i.value,raw:o.raw}:null}function ed(e,t={}){let r=g(e);if("ELEMENT_NOT_FOUND"===r.code)return!0===t.allowElementNotFound;if("COMMAND_FAILED"!==r.code)return!1;let n=r.message.toLowerCase();return n.includes("fetch failed")||n.includes("timed out")||n.includes("timeout")||n.includes("runner did not accept connection")||n.includes("invalid runner response")}async function ef(e){var t;let{req:r}=e;if("find"!==r.command)return null;let n=r.positionals??[];if(0===n.length)return i("INVALID_ARGS","find requires a locator or text");let s=O(n);if(!s.query)return i("INVALID_ARGS","find requires a value");if(r.flags?.findFirst&&r.flags?.findLast)return i("INVALID_ARGS","find accepts only one of --first or --last");let o=s.action;if("exists"!==(t=o)&&"wait"!==t&&"get_text"!==t&&"get_attrs"!==t)return null;let a=await ev(e,{requireSession:!1,capability:"find"});return a.ok?await eP(async()=>{let t=await a.runtime.selectors.find({session:e.sessionName,requestId:r.meta?.requestId,locator:s.locator,query:s.query,action:o,timeoutMs:s.timeoutMs});return X(e.sessionStore,e.sessionName,r,function(e,t){if("exists"===t)return{found:!0};if("wait"===t)return{found:!0,waitedMs:e.waitedMs};let r="string"==typeof e.ref?e.ref:void 0;return"get_attrs"===t?{ref:r,action:"get attrs"}:{ref:r,action:"get text",text:"string"==typeof e.text?e.text:""}}(t,o)),"found"===t.kind?{found:!0,..."number"==typeof t.waitedMs?{waitedMs:t.waitedMs}:{}}:{..."string"==typeof t.ref?{ref:t.ref}:{},..."string"==typeof t.text?{text:t.text}:{},...t.node&&"object"==typeof t.node?{node:t.node}:{}}}):a.response}async function ep(e){let{req:t}=e;if("get"!==t.command)return null;let r=t.positionals?.[0];if("text"!==r&&"attrs"!==r)return i("INVALID_ARGS","get only supports text or attrs");let n=function(e){let t=e.positionals?.[1]??"";if(t.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:e.positionals.length>2?e.positionals.slice(2).join(" ").trim():""}};let r=e.positionals?.slice(1).join(" ").trim()??"";return r?{ok:!0,target:{kind:"selector",selector:r}}:{ok:!1,response:i("INVALID_ARGS","get requires @ref or selector expression")}}(t);if(!n.ok)return n.response;if("ref"===n.target.kind){let e=B("get",t.flags);if(e)return e}if("selector"===n.target.kind){let t=await eh(e,r,n.target.selector);if(t)return t}let s=await ev(e,{requireSession:!0,capability:"get"});return s.ok?await eP(async()=>{let o=await s.runtime.selectors.get({session:e.sessionName,requestId:t.meta?.requestId,property:r,target:n.target});return X(e.sessionStore,e.sessionName,t,z(o,r)),Q(o)}):s.response}async function em(e){let{req:t}=e;if("is"!==t.command)return null;let r=(t.positionals?.[0]??"").toLowerCase();if(!_(r))return i("INVALID_ARGS","is requires predicate: visible|hidden|exists|editable|selected|text");let{split:n}=P(t.positionals??[]);if(!n)return i("INVALID_ARGS","is requires a selector expression");let s=n.rest.join(" ").trim();if("text"===r&&!s)return i("INVALID_ARGS","is text requires expected text value");if("text"!==r&&n.rest.length>0)return i("INVALID_ARGS",`is ${r} does not accept trailing values`);let o=await ey(e,r,n.selectorExpression,s);if(o)return o;let a=await ev(e,{requireSession:!0,capability:"is"});if(!a.ok)return a.response;let l=await eP(async()=>{let o=await a.runtime.selectors.is({session:e.sessionName,requestId:t.meta?.requestId,predicate:r,selector:n.selectorExpression,expectedText:s});return X(e.sessionStore,e.sessionName,t,o),J(o)});return await eR(e,l,`is ${r}`)}async function eg(e){let{req:t,sessionName:r,sessionStore:n}=e,s=E(t.positionals??[]);if(!s)return i("INVALID_ARGS","wait requires a duration or text");let{session:a,device:l}=await $(n,r,t.flags);if("sleep"!==s.kind&&!o("wait",l))return i("UNSUPPORTED_OPERATION","wait is not supported on this device");if("selector"===s.kind){let t=await ew({...e,session:a,device:l,selectorExpression:s.selectorExpression,timeoutMs:s.timeoutMs});if(t)return t}let u=async()=>{let o=eI({...e,session:a,device:l}),i=await eP(async()=>{let e=await o.selectors.wait({session:r,requestId:t.meta?.requestId,target:function(e,t){if("sleep"===e.kind)return{kind:"sleep",durationMs:e.durationMs};if("selector"===e.kind)return{kind:"selector",selector:e.selectorExpression,timeoutMs:e.timeoutMs};if("ref"===e.kind){if(!t?.snapshot)throw new y("INVALID_ARGS","Ref wait requires an existing snapshot in session.");return{kind:"ref",ref:e.rawRef,timeoutMs:e.timeoutMs}}if(!e.text)throw new y("INVALID_ARGS","wait requires text");return{kind:"text",text:e.text,timeoutMs:e.timeoutMs}}(s,a)});return X(n,r,t,e),{waitedMs:e.waitedMs,..."string"==typeof e.text?{text:e.text}:{},..."string"==typeof e.selector?{selector:e.selector}:{}}}),u=await er({req:t,logPath:e.logPath,session:a,device:l},i);return await eR(e,u,"wait")};return"sleep"===s.kind?await u():await L(a,l,u)}async function eh(e,t,r){let n=e.sessionStore.get(e.sessionName),s=ec({session:n,selectorExpression:r});if(!n||!s||"text"===t&&"id"!==s.key)return null;let o=await ex(e,n,s);if(ek(o))return o.response;if(!o)return null;let i=function(e,t,r){if(!r.found||!r.node)return null;let n={target:{kind:"selector",selector:t},node:r.node,selectorChain:[t]};return"attrs"===e?{kind:"attrs",...n}:"string"!=typeof r.text?null:{kind:"text",...n,text:r.text}}(t,s.raw,o);return i?(X(e.sessionStore,e.sessionName,e.req,z(i,t)),{ok:!0,data:Q(i)}):null}async function ey(e,t,r,n){var s,o,i,a,l;let u;if("hidden"===t)return null;let c=await e_(e,r);if(ek(c))return c.response;if(!c?.result.found||!c.result.node)return null;let d="exists"===t?{predicate:t,pass:!0,selector:c.selector.raw,matches:1,selectorChain:[c.selector.raw]}:(s=t,o=n,i=c.selector.raw,a=c.session,u=w({predicate:s,node:l=c.result.node,nodes:[l],expectedText:o,platform:a.device.platform}),{predicate:s,pass:u.pass,selector:i,..."text"===s?{text:u.actualText}:{},selectorChain:[i]});return d?(X(e.sessionStore,e.sessionName,e.req,d),{ok:!0,data:J(d)}):null}async function ew(e){let t=ec({session:e.session,selectorExpression:e.selectorExpression});if(!e.session||!t)return null;let r=Date.now(),n=await ex(e,e.session,t);if(ek(n))return n.response;if(!n?.found)return null;let s={kind:"selector",selector:t.raw,waitedMs:Date.now()-r,selectorChain:[t.raw]};return X(e.sessionStore,e.sessionName,e.req,s),await er({req:e.req,logPath:e.logPath,session:e.session,device:e.device},{ok:!0,data:s})}async function e_(e,t){let r=e.sessionStore.get(e.sessionName),n=ec({session:r,selectorExpression:t});if(!r||!n)return null;let s=await ex(e,r,n);return ek(s)?s:s?{session:r,selector:n,result:s}:null}async function eS(e,t,r){let n=await s(t.device,{command:"querySelector",selectorKey:r.key,selectorValue:r.value,appBundleId:t.appBundleId},{verbose:!!e.req.flags?.verbose,logPath:e.logPath,traceLogPath:t.trace?.outPath,requestId:e.req.meta?.requestId}),o=!0===n.found,i=function(e){let t=e.nodes;if(!Array.isArray(t))return;let r=t[0];if(r&&"object"==typeof r)return r}(n);return{found:o,..."string"==typeof n.text?{text:n.text}:{},...i?{node:i}:{}}}async function ex(e,t,r){try{return await eS(e,t,r)}catch(e){if(ed(e,{allowElementNotFound:!0}))return null;return{kind:"error",response:{ok:!1,error:h(e)}}}}function ek(e){return null!==e&&"kind"in e&&"error"===e.kind}function eI(n){return x({backend:function(e){let n,{req:s,session:o,device:i,logPath:a,sessionName:l,sessionStore:u}=e,d=0;return{platform:i.platform,captureSnapshot:async(e,f)=>{var p;let m,g={...s.flags,...(p=f,m={},p?.interactiveOnly!==void 0&&(m.snapshotInteractiveOnly=p.interactiveOnly),p?.scope!==void 0&&(m.snapshotScope=p.scope),p?.depth!==void 0&&(m.snapshotDepth=p.depth),p?.raw!==void 0&&(m.snapshotRaw=p.raw),m)},h=f?.scope??s.flags?.snapshotScope,y=Date.now(),w=C(D(g)),_="wait"===s.command||"find"===s.command;if(!_&&n&&y-d<750&&!c(o)&&!o?.postGestureStabilization)return n;if(!_&&o?.snapshot&&y-o.snapshot.createdAt<750&&o.snapshot.presentationKey===w&&!c(o)&&!o.postGestureStabilization)return d=o.snapshot.createdAt,n={snapshot:o.snapshot};let S=await r({device:i,session:o,flags:g,outPath:s.flags?.out,logPath:a??"",snapshotScope:h});return o&&!b(S.snapshot.snapshotQuality)&&(t(o,S.snapshot),u.set(l,o)),d=y,n={snapshot:S.snapshot}},readText:async(t,r)=>({text:await V({device:i,node:r,flags:s.flags,appBundleId:o?.appBundleId,traceOutPath:o?.trace?.outPath,surface:o?.surface,contextFromFlags:e.contextFromFlags??((e,t,r)=>f(a??"",e,t,r))})}),findText:async(t,r)=>({found:await eN(e,r)})}}(n),...G("selector commands",{plural:!0}),sessions:e({sessionName:n.sessionName,getSession:()=>n.session,recordOptions:{includeSnapshot:!0},setRecord:e=>{n.session&&e.snapshot&&(t(n.session,e.snapshot),n.sessionStore.set(n.sessionName,n.session))}})})}async function ev(e,t){let r=e.sessionStore.get(e.sessionName);if(!r&&t.requireSession)return{ok:!1,response:i("SESSION_NOT_FOUND","No active session. Run open first.")};let n=r?.device??await d(e.req.flags??{});return(r||await a(n),o(t.capability,n))?{ok:!0,runtime:eI({...e,session:r,device:n})}:{ok:!1,response:i("UNSUPPORTED_OPERATION",`${t.capability} is not supported on this device`)}}async function eN(e,t){let{device:r,session:n,req:o,logPath:i}=e;if("macos"===r.platform&&n?.surface&&"app"!==n.surface)return!!N((await eA(e)).nodes,t);if(M(r.platform)&&n?.appBundleId){let e=await s(r,{command:"findText",text:t,appBundleId:n?.appBundleId},{verbose:o.flags?.verbose,logPath:i,traceLogPath:n?.trace?.outPath,requestId:o.meta?.requestId});return e?.found===!0}return!!N((await eA(e)).nodes,t)}async function eA(e){let n=await r({device:e.device,session:e.session,flags:{...e.req.flags,snapshotInteractiveOnly:!1},outPath:e.req.flags?.out,logPath:e.logPath??""});return e.session&&!b(n.snapshot.snapshotQuality)&&(t(e.session,n.snapshot),e.sessionStore.set(e.sessionName,e.session)),n.snapshot}async function eP(e){try{return{ok:!0,data:await e()}}catch(t){let e=g(t);return i(e.code,e.message,e.details)}}async function eR(e,t,r){var n;let s;if(t.ok)return t;let o=e.sessionStore.get(e.sessionName);if(!o)return t;try{s=await H(o)}catch{return t}return s?i(t.error.code,`${r} failed because ${"com.google.android.permissioncontroller"===(n=s).foregroundPackage?`Android permission dialog is blocking ${n.expectedPackage}`:`${n.foregroundPackage} is foreground instead of ${n.expectedPackage}`}.`,{...t.error.details??{},...s,blockedBy:"android_foreground_surface",originalMessage:t.error.message}):t}export{j as assertAndroidPressStayedInApp,T as buildSnapshotSession,G as createDaemonRuntimePolicy,ef as dispatchFindReadOnlyViaRuntime,ep as dispatchGetViaRuntime,em as dispatchIsViaRuntime,eg as dispatchWaitViaRuntime,W as isAndroidEscapeError,ed as isDirectIosSelectorFallbackError,ec as readSimpleIosSelectorTarget,V as readTextForNode,K as recordIfSession,B as refSnapshotFlagGuardResponse,$ as resolveSessionDevice,L as withSessionlessRunnerCleanup};
1
+ import{createDaemonRuntimeSessionStore as e,setSessionSnapshot as t,captureSnapshot as r,dispatchCommand as s,runIosRunnerCommand as n,isCommandSupportedOnDevice as o,errorResponse as i,ensureDeviceReady as a,stopIosRunnerSession as l,resolveRunnerAppBundleId as u,getActiveAndroidSnapshotFreshness as c,resolveTargetDevice as d,context_contextFromFlags as f}from"./9722.js";import{closeIosApp as p}from"./apps.js";import{emitDiagnostic as m}from"./432.js";import{asAppError as g,normalizeError as h,AppError as y}from"./733.js";import{evaluateIsPredicate as w,isSupportedPredicate as _,localCommandPolicy as S,createAgentDevice as v}from"./5299.js";import{tryParseSelectorChain as x,extractNodeReadText as k,prefersValueForReadableText as I,findNodeByLabel as N,normalizeType as A,splitIsSelectorArgs as P}from"./9836.js";import{resolveRectCenter as R,isSparseSnapshotQualityVerdict as b,parseWaitPositionals as D}from"./9873.js";import{getAndroidAppState as E}from"./3340.js";import{buildSnapshotPresentationKey as q,isApplePlatform as C,snapshotPresentationOptionsFromFlags as M}from"./4291.js";import{parseFindArgs as O}from"./587.js";async function $(e,t,r){let s=e.get(t),n=s?.device??await d(r??{});return s||await a(n),{session:s,device:n}}async function L(e,t,r){let s=!e&&"ios"===t.platform;try{return await r()}finally{s&&(await l(t.id),await U(t))}}async function U(e){let t=u();await p(e,t).catch(r=>{m({level:"debug",phase:"ios_sessionless_runner_host_close_failed",data:{deviceId:e.id,bundleId:t,error:r instanceof Error?r.message:String(r)}})})}function K(e,t,r,s){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:s})}function F(e){let{session:t,sessionName:r,device:s,snapshot:n,appBundleId:o}=e;return t?{...t,snapshot:n,lastComparisonSafeSnapshot:n?.comparisonSafe===!0?n:t.lastComparisonSafeSnapshot}:{name:r,device:s,createdAt:Date.now(),appBundleId:o,snapshot:n,...n?.comparisonSafe===!0?{lastComparisonSafeSnapshot:n}:{},actions:[]}}function T(e,t={}){return{artifacts:function(e,t={}){let r=!0===t.plural?"do":"does";return{resolveInput:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not resolve input artifacts`)},reserveOutput:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not reserve output artifacts`)},createTempFile:async()=>{throw new y("UNSUPPORTED_OPERATION",`${e} ${r} not create temporary files`)}}}(e,t),policy:S()}}async function G(e){let{device:t,node:r,flags:n,appBundleId:o,traceOutPath:i,surface:a,contextFromFlags:l}=e,u=k(r),c=R(r.rect);if(!c||"ios"===t.platform&&u&&!I(r.type??""))return u;try{let e=await s(t,"read",[String(c.x),String(c.y)],void 0,{...l(n,o,i),surface:a}),d=e&&"object"==typeof e?e:void 0,f="string"==typeof d?.text?d.text:"";if(f.trim())return f;return m({level:"warn",phase:"interaction_read_fallback",data:{reason:"empty_backend_text",nodeRef:r.ref,surface:a,platform:t.platform}}),u}catch(e){return m({level:"warn",phase:"interaction_read_fallback",data:{reason:"backend_read_failed",nodeRef:r.ref,surface:a,platform:t.platform,error:e instanceof Error?e.message:String(e)}}),u}}let V=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function B(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,s]of V)void 0!==e[r]&&t.push(s);return t}(t);return 0===r.length?null:i("INVALID_ARGS",`${e} @ref does not support ${r.join(", ")}.`)}async function X(e,t){let r=await j(e);if(r)throw new y("COMMAND_FAILED",`press ${t} left ${e.appBundleId} and foregrounded ${r.foregroundPackage}. The tap likely escaped the app.`,r)}async function j(e){var t;if("android"!==e.device.platform||!e.appBundleId)return null;let r=await E(e.device),s=r.package?.trim();return s&&s!==e.appBundleId&&("com.android.settings"===(t=s)||"com.android.systemui"===t||"com.google.android.permissioncontroller"===t||t.includes("launcher"))?{expectedPackage:e.appBundleId,foregroundPackage:s,activity:r.activity,hint:"com.google.android.permissioncontroller"===s?"Dismiss or allow the permission prompt, then retry the smoke assertion.":"Use screenshot as visual truth, then take a fresh snapshot -i before retrying."}:null}function H(e){return"COMMAND_FAILED"===e.code&&"string"==typeof e.details?.expectedPackage&&"string"==typeof e.details?.foregroundPackage}function W(e,t){let r=Array.isArray(e.selectorChain)?e.selectorChain:void 0,s=Y(e),n=s?.kind==="ref"?Z(s.ref):void 0,o=s?.kind==="selector"?s.selector:void 0,i={...n?{ref:n}:{},...o?{selector:o}:{},...r?{selectorChain:r}:{}};if("attrs"===t)return i;let a="string"==typeof e.text?e.text:"";return{...i,text:a,refLabel:function(e){let t=e.trim();if(!(!t||t.length>80||/[\r\n]/.test(t)))return t}(a)}}function z(e){let t=Y(e);return{...t?.kind==="ref"?{ref:Z(t.ref)}:{},...t?.kind==="selector"?{selector:t.selector}:{},..."string"==typeof e.text?{text:e.text}:{},...e.node&&"object"==typeof e.node?{node:e.node}:{}}}function Q(e){let{selectorChain:t,...r}=e;return r}function J(e,t,r,s){let n=e.get(t);n&&e.recordAction(n,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:s})}function Y(e){let t=e.target;return t&&"object"==typeof t?"ref"===t.kind&&"string"==typeof t.ref?{kind:"ref",ref:t.ref}:"selector"===t.kind&&"string"==typeof t.selector?{kind:"selector",selector:t.selector}:void 0:void 0}function Z(e){return e.startsWith("@")?e.slice(1):e}let ee=["application","window","tabbar","scrollbar","image"],et=new Set(["tab bar"]);async function er(e,t){var r;if(t.ok||(r=t.error.message,!/^wait timed out for (?:selector|text): /i.test(r)))return t;let s=await es(e).catch(()=>null);return s?i(t.error.code,`${t.error.message}. Current surface: ${s.summary}.`,{...t.error.details??{},currentSurface:s.details}):t}async function es(e){let t=[...(await r({device:e.device,session:e.session,flags:{...e.req.flags,snapshotInteractiveOnly:!0},logPath:e.logPath??""})).snapshot.nodes].sort(eo),s=en(t,6,{includeIdentifiers:!0});if(0===s.length)return null;let n=en(t.filter(e=>!el(e)),4,{includeIdentifiers:!1}),o=en(t.filter(eu),4,{includeIdentifiers:!0});return{summary:(n.length>0?n:s.slice(0,4)).join(", "),details:{labels:s,...o.length>0?{buttons:o}:{}}}}function en(e,t,r){let s=new Set,n=[];for(let o of e){let e=ea(o,r);if(!(!e||s.has(e))&&(s.add(e),n.push(e),n.length>=t))break}return n}function eo(e,t){var r,s;return ei(e)-ei(t)||(r=e,s=t,r.rect&&s.rect?r.rect.y-s.rect.y||r.rect.x-s.rect.x:r.rect?-1:s.rect?1:(r.depth??0)-(s.depth??0)||r.index-s.index)}function ei(e){let t=!!ea(e,{includeIdentifiers:!1});return 2*!!el(e)+ +!t}function ea(e,t){let r=(t.includeIdentifiers?[e.label,e.value,e.identifier]:[e.label,e.value]).map(e=>"string"==typeof e?e.trim():"").find(e=>e.length>0);return r?r.replace(/\s+/g," ").slice(0,80):""}function el(e){let t=A(`${e.type??""} ${e.role??""} ${e.subrole??""}`),r=`${e.label??""} ${e.value??""}`.trim().toLowerCase();return ee.some(e=>t.includes(e))||et.has(r)||r.endsWith(".fill")}function eu(e){return A(`${e.type??""} ${e.role??""} ${e.subrole??""}`).includes("button")}function ec(e){var t;let{session:r,selectorExpression:s}=e;if(!r||"ios"!==r.device.platform||r.postGestureStabilization)return null;let n=x(s);if(!n||1!==n.selectors.length)return null;let o=n.selectors[0];if(!o||1!==o.terms.length)return null;let i=o.terms[0];return i&&"string"==typeof i.value&&("id"===(t=i.key)||"label"===t||"text"===t||"value"===t)?{key:i.key,value:i.value,raw:o.raw}:null}function ed(e,t={}){let r=g(e);if("ELEMENT_NOT_FOUND"===r.code)return!0===t.allowElementNotFound;if("COMMAND_FAILED"!==r.code)return!1;let s=r.message.toLowerCase();return s.includes("fetch failed")||s.includes("timed out")||s.includes("timeout")||s.includes("runner did not accept connection")||s.includes("invalid runner response")}async function ef(e){var t;let{req:r}=e;if("find"!==r.command)return null;let s=r.positionals??[];if(0===s.length)return i("INVALID_ARGS","find requires a locator or text");let n=O(s);if(!n.query)return i("INVALID_ARGS","find requires a value");if(r.flags?.findFirst&&r.flags?.findLast)return i("INVALID_ARGS","find accepts only one of --first or --last");let o=n.action;if("exists"!==(t=o)&&"wait"!==t&&"get_text"!==t&&"get_attrs"!==t)return null;let a=await eI(e,{requireSession:!1,capability:"find"});return a.ok?await eP(async()=>{let t=await a.runtime.selectors.find({session:e.sessionName,requestId:r.meta?.requestId,locator:n.locator,query:n.query,action:o,timeoutMs:n.timeoutMs});return J(e.sessionStore,e.sessionName,r,function(e,t){if("exists"===t)return{found:!0};if("wait"===t)return{found:!0,waitedMs:e.waitedMs};let r="string"==typeof e.ref?e.ref:void 0;return"get_attrs"===t?{ref:r,action:"get attrs"}:{ref:r,action:"get text",text:"string"==typeof e.text?e.text:""}}(t,o)),"found"===t.kind?{found:!0,..."number"==typeof t.waitedMs?{waitedMs:t.waitedMs}:{}}:{..."string"==typeof t.ref?{ref:t.ref}:{},..."string"==typeof t.text?{text:t.text}:{},...t.node&&"object"==typeof t.node?{node:t.node}:{}}}):a.response}async function ep(e){let{req:t}=e;if("get"!==t.command)return null;let r=t.positionals?.[0];if("text"!==r&&"attrs"!==r)return i("INVALID_ARGS","get only supports text or attrs");let s=function(e){let t=e.positionals?.[1]??"";if(t.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:e.positionals.length>2?e.positionals.slice(2).join(" ").trim():""}};let r=e.positionals?.slice(1).join(" ").trim()??"";return r?{ok:!0,target:{kind:"selector",selector:r}}:{ok:!1,response:i("INVALID_ARGS","get requires @ref or selector expression")}}(t);if(!s.ok)return s.response;if("ref"===s.target.kind){let e=B("get",t.flags);if(e)return e}if("selector"===s.target.kind){let t=await eh(e,r,s.target.selector);if(t)return t}let n=await eI(e,{requireSession:!0,capability:"get"});return n.ok?await eP(async()=>{let o=await n.runtime.selectors.get({session:e.sessionName,requestId:t.meta?.requestId,property:r,target:s.target});return J(e.sessionStore,e.sessionName,t,W(o,r)),z(o)}):n.response}async function em(e){let{req:t}=e;if("is"!==t.command)return null;let r=(t.positionals?.[0]??"").toLowerCase();if(!_(r))return i("INVALID_ARGS","is requires predicate: visible|hidden|exists|editable|selected|text");let{split:s}=P(t.positionals??[]);if(!s)return i("INVALID_ARGS","is requires a selector expression");let n=s.rest.join(" ").trim();if("text"===r&&!n)return i("INVALID_ARGS","is text requires expected text value");if("text"!==r&&s.rest.length>0)return i("INVALID_ARGS",`is ${r} does not accept trailing values`);let o=await ey(e,r,s.selectorExpression,n);if(o)return o;let a=await eI(e,{requireSession:!0,capability:"is"});if(!a.ok)return a.response;let l=await eP(async()=>{let o=await a.runtime.selectors.is({session:e.sessionName,requestId:t.meta?.requestId,predicate:r,selector:s.selectorExpression,expectedText:n});return J(e.sessionStore,e.sessionName,t,o),Q(o)});return await eR(e,l,`is ${r}`)}async function eg(e){let{req:t,sessionName:r,sessionStore:s}=e,n=D(t.positionals??[]);if(!n)return i("INVALID_ARGS","wait requires a duration or text");let{session:a,device:l}=await $(s,r,t.flags);if("sleep"!==n.kind&&!o("wait",l))return i("UNSUPPORTED_OPERATION","wait is not supported on this device");if("selector"===n.kind){let t=await ew({...e,session:a,device:l,selectorExpression:n.selectorExpression,timeoutMs:n.timeoutMs});if(t)return t}let u=async()=>{let o=ek({...e,session:a,device:l}),i=await eP(async()=>{let e=await o.selectors.wait({session:r,requestId:t.meta?.requestId,target:function(e,t){if("sleep"===e.kind)return{kind:"sleep",durationMs:e.durationMs};if("selector"===e.kind)return{kind:"selector",selector:e.selectorExpression,timeoutMs:e.timeoutMs};if("ref"===e.kind){if(!t?.snapshot)throw new y("INVALID_ARGS","Ref wait requires an existing snapshot in session.");return{kind:"ref",ref:e.rawRef,timeoutMs:e.timeoutMs}}if(!e.text)throw new y("INVALID_ARGS","wait requires text");return{kind:"text",text:e.text,timeoutMs:e.timeoutMs}}(n,a)});return J(s,r,t,e),{waitedMs:e.waitedMs,..."string"==typeof e.text?{text:e.text}:{},..."string"==typeof e.selector?{selector:e.selector}:{}}}),u=await er({req:t,logPath:e.logPath,session:a,device:l},i);return await eR(e,u,"wait")};return"sleep"===n.kind?await u():await L(a,l,u)}async function eh(e,t,r){let s=e.sessionStore.get(e.sessionName),n=ec({session:s,selectorExpression:r});if(!s||!n||"text"===t&&"id"!==n.key)return null;let o=await ev(e,s,n);if(ex(o))return o.response;if(!o)return null;let i=function(e,t,r){if(!r.found||!r.node)return null;let s={target:{kind:"selector",selector:t},node:r.node,selectorChain:[t]};return"attrs"===e?{kind:"attrs",...s}:"string"!=typeof r.text?null:{kind:"text",...s,text:r.text}}(t,n.raw,o);return i?(J(e.sessionStore,e.sessionName,e.req,W(i,t)),{ok:!0,data:z(i)}):null}async function ey(e,t,r,s){var n,o,i,a,l;let u;if("hidden"===t)return null;let c=await e_(e,r);if(ex(c))return c.response;if(!c?.result.found||!c.result.node)return null;let d="exists"===t?{predicate:t,pass:!0,selector:c.selector.raw,matches:1,selectorChain:[c.selector.raw]}:(n=t,o=s,i=c.selector.raw,a=c.session,u=w({predicate:n,node:l=c.result.node,nodes:[l],expectedText:o,platform:a.device.platform}),{predicate:n,pass:u.pass,selector:i,..."text"===n?{text:u.actualText}:{},selectorChain:[i]});return d?(J(e.sessionStore,e.sessionName,e.req,d),{ok:!0,data:Q(d)}):null}async function ew(e){let t=ec({session:e.session,selectorExpression:e.selectorExpression});if(!e.session||!t)return null;let r=Date.now(),s=await ev(e,e.session,t);if(ex(s))return s.response;if(!s?.found)return null;let n={kind:"selector",selector:t.raw,waitedMs:Date.now()-r,selectorChain:[t.raw]};return J(e.sessionStore,e.sessionName,e.req,n),await er({req:e.req,logPath:e.logPath,session:e.session,device:e.device},{ok:!0,data:n})}async function e_(e,t){let r=e.sessionStore.get(e.sessionName),s=ec({session:r,selectorExpression:t});if(!r||!s)return null;let n=await ev(e,r,s);return ex(n)?n:n?{session:r,selector:s,result:n}:null}async function eS(e,t,r){let s=await n(t.device,{command:"querySelector",selectorKey:r.key,selectorValue:r.value,appBundleId:t.appBundleId},{verbose:!!e.req.flags?.verbose,logPath:e.logPath,traceLogPath:t.trace?.outPath,requestId:e.req.meta?.requestId,iosXctestrunFile:e.req.flags?.iosXctestrunFile,iosXctestDerivedDataPath:e.req.flags?.iosXctestDerivedDataPath,iosXctestEnvDir:e.req.flags?.iosXctestEnvDir}),o=!0===s.found,i=function(e){let t=e.nodes;if(!Array.isArray(t))return;let r=t[0];if(r&&"object"==typeof r)return r}(s);return{found:o,..."string"==typeof s.text?{text:s.text}:{},...i?{node:i}:{}}}async function ev(e,t,r){try{return await eS(e,t,r)}catch(e){if(ed(e,{allowElementNotFound:!0}))return null;return{kind:"error",response:{ok:!1,error:h(e)}}}}function ex(e){return null!==e&&"kind"in e&&"error"===e.kind}function ek(s){return v({backend:function(e){let s,{req:n,session:o,device:i,logPath:a,sessionName:l,sessionStore:u}=e,d=0;return{platform:i.platform,captureSnapshot:async(e,f)=>{var p;let m,g={...n.flags,...(p=f,m={},p?.interactiveOnly!==void 0&&(m.snapshotInteractiveOnly=p.interactiveOnly),p?.scope!==void 0&&(m.snapshotScope=p.scope),p?.depth!==void 0&&(m.snapshotDepth=p.depth),p?.raw!==void 0&&(m.snapshotRaw=p.raw),m)},h=f?.scope??n.flags?.snapshotScope,y=Date.now(),w=q(M(g)),_="wait"===n.command||"find"===n.command;if(!_&&s&&y-d<750&&!c(o)&&!o?.postGestureStabilization)return s;if(!_&&o?.snapshot&&y-o.snapshot.createdAt<750&&o.snapshot.presentationKey===w&&!c(o)&&!o.postGestureStabilization)return d=o.snapshot.createdAt,s={snapshot:o.snapshot};let S=await r({device:i,session:o,flags:g,outPath:n.flags?.out,logPath:a??"",snapshotScope:h});return o&&!b(S.snapshot.snapshotQuality)&&(t(o,S.snapshot),u.set(l,o)),d=y,s={snapshot:S.snapshot}},readText:async(t,r)=>({text:await G({device:i,node:r,flags:n.flags,appBundleId:o?.appBundleId,traceOutPath:o?.trace?.outPath,surface:o?.surface,contextFromFlags:e.contextFromFlags??((e,t,r)=>f(a??"",e,t,r))})}),findText:async(t,r)=>({found:await eN(e,r)})}}(s),...T("selector commands",{plural:!0}),sessions:e({sessionName:s.sessionName,getSession:()=>s.session,recordOptions:{includeSnapshot:!0},setRecord:e=>{s.session&&e.snapshot&&(t(s.session,e.snapshot),s.sessionStore.set(s.sessionName,s.session))}})})}async function eI(e,t){let r=e.sessionStore.get(e.sessionName);if(!r&&t.requireSession)return{ok:!1,response:i("SESSION_NOT_FOUND","No active session. Run open first.")};let s=r?.device??await d(e.req.flags??{});return(r||await a(s),o(t.capability,s))?{ok:!0,runtime:ek({...e,session:r,device:s})}:{ok:!1,response:i("UNSUPPORTED_OPERATION",`${t.capability} is not supported on this device`)}}async function eN(e,t){let{device:r,session:s,req:o,logPath:i}=e;if("macos"===r.platform&&s?.surface&&"app"!==s.surface)return!!N((await eA(e)).nodes,t);if(C(r.platform)&&s?.appBundleId){let e=await n(r,{command:"findText",text:t,appBundleId:s?.appBundleId},{verbose:o.flags?.verbose,logPath:i,traceLogPath:s?.trace?.outPath,requestId:o.meta?.requestId,iosXctestrunFile:o.flags?.iosXctestrunFile,iosXctestDerivedDataPath:o.flags?.iosXctestDerivedDataPath,iosXctestEnvDir:o.flags?.iosXctestEnvDir});return e?.found===!0}return!!N((await eA(e)).nodes,t)}async function eA(e){let s=await r({device:e.device,session:e.session,flags:{...e.req.flags,snapshotInteractiveOnly:!1},outPath:e.req.flags?.out,logPath:e.logPath??""});return e.session&&!b(s.snapshot.snapshotQuality)&&(t(e.session,s.snapshot),e.sessionStore.set(e.sessionName,e.session)),s.snapshot}async function eP(e){try{return{ok:!0,data:await e()}}catch(t){let e=g(t);return i(e.code,e.message,e.details)}}async function eR(e,t,r){var s;let n;if(t.ok)return t;let o=e.sessionStore.get(e.sessionName);if(!o)return t;try{n=await j(o)}catch{return t}return n?i(t.error.code,`${r} failed because ${"com.google.android.permissioncontroller"===(s=n).foregroundPackage?`Android permission dialog is blocking ${s.expectedPackage}`:`${s.foregroundPackage} is foreground instead of ${s.expectedPackage}`}.`,{...t.error.details??{},...n,blockedBy:"android_foreground_surface",originalMessage:t.error.message}):t}export{X as assertAndroidPressStayedInApp,F as buildSnapshotSession,T as createDaemonRuntimePolicy,ef as dispatchFindReadOnlyViaRuntime,ep as dispatchGetViaRuntime,em as dispatchIsViaRuntime,eg as dispatchWaitViaRuntime,H as isAndroidEscapeError,ed as isDirectIosSelectorFallbackError,ec as readSimpleIosSelectorTarget,G as readTextForNode,K as recordIfSession,B as refSnapshotFlagGuardResponse,$ as resolveSessionDevice,L as withSessionlessRunnerCleanup};
@@ -22,7 +22,7 @@ export declare function parseSelectorChain(expression: string): SelectorChain;
22
22
 
23
23
  declare type Platform = (typeof PLATFORMS)[number];
24
24
 
25
- declare const PLATFORMS: readonly ["ios", "macos", "android", "linux"];
25
+ declare const PLATFORMS: readonly ['ios', 'macos', 'android', 'linux'];
26
26
 
27
27
  declare type RawSnapshotNode = {
28
28
  index: number;
@@ -1 +1 @@
1
- export{findSelectorChainMatch,formatSelectorFailure,isNodeEditable,isNodeVisible,isSelectorToken,parseSelectorChain,resolveSelectorChain,tryParseSelectorChain}from"./7847.js";
1
+ export{findSelectorChainMatch,formatSelectorFailure,isNodeEditable,isNodeVisible,isSelectorToken,parseSelectorChain,resolveSelectorChain,tryParseSelectorChain}from"./9836.js";
@@ -1,2 +1,2 @@
1
- import{formatCliOutput as t}from"./cli-output.js";import{listMcpCommandMetadata as r,isCommandName as e}from"./5611.js";import{readVersion as n}from"./9671.js";let i=function(r={}){return{execute:async(n,i)=>{var u;if(!e(n))throw Error(`Unknown command tool: ${n}`);let c=!(u=i)||"object"!=typeof u||Array.isArray(u)?{client:{},outputFormat:"optimized"}:{client:function(t){let r=t.stateDir,e={};if(void 0!==r&&("string"!=typeof r||0===r.length))throw Error("Expected stateDir to be a non-empty string.");return"string"==typeof r&&(e.stateDir=r),e}(u),outputFormat:function(t){if(void 0===t)return"optimized";if("optimized"!==t&&"json"!==t)throw Error('Expected mcpOutputFormat to be "optimized" or "json".');return t}(u.mcpOutputFormat)},p=function(t){if(!t||"object"!=typeof t||Array.isArray(t))return t;let{stateDir:r,mcpOutputFormat:e,...n}=t;return n}(i),f=await o(r,c.client),l=await (r.runCommand??s)(f,n,p);return{isError:!1,structuredContent:l,content:[{type:"text",text:function(r){if("json"===r.outputFormat)return a(r.result);let e=t({name:r.name,input:r.input,result:r.result});return"string"==typeof e?.text?e.text:a(e?.data??r.result)}({name:n,input:p,result:l,outputFormat:c.outputFormat})}]}}}}();async function o(t,r){if(t.createClient)return await t.createClient(r);let{createAgentDeviceClient:e}=await import("./9542.js");return e(r)}async function s(t,r,e){let n=await import("./command-surface.js");return await n.runCommand(t,r,e)}function a(t){return"string"==typeof t?t:JSON.stringify(t,null,2)}async function u(t){if("2.0"!==t.jsonrpc||"string"!=typeof t.method)return f(t.id??null,-32600,"Invalid JSON-RPC request.");if(void 0===t.id)return null;try{var r,e;return r=t.id,e=await c(t.method,t.params),{jsonrpc:"2.0",id:r,result:e}}catch(r){if(r instanceof l)return f(t.id,-32601,r.message);return f(t.id,-32602,r instanceof Error?r.message:String(r))}}async function c(t,e){switch(t){case"initialize":return{protocolVersion:"2025-11-25",capabilities:{tools:{}},serverInfo:{name:"agent-device",version:n()}};case"ping":return{};case"tools/list":return{tools:r().map(t=>{var r;return{name:t.name,description:t.description,inputSchema:{...r=t.inputSchema,properties:{...r.properties,stateDir:{type:"string",description:"Agent-device state directory."},mcpOutputFormat:{type:"string",enum:["optimized","json"],description:"MCP text content format. Defaults to optimized agent-friendly text; use json for JSON text. Structured content is always returned separately."}}}}})};case"tools/call":return await p(e);default:throw new l(`Unsupported MCP method: ${t}`)}}async function p(t){let r=function(t){if(!t||"object"!=typeof t||Array.isArray(t))throw Error("Expected object parameters.");return t}(t),e=function(t,r){let e=t[r];if("string"!=typeof e||0===e.length)throw Error(`Expected ${r} to be a non-empty string.`);return e}(r,"name");try{return await i.execute(e,r.arguments)}catch(t){return function(t,r=!1){return{isError:r,content:[{type:"text",text:t}]}}(t instanceof Error?t.message:String(t),!0)}}function f(t,r,e){return{jsonrpc:"2.0",id:t,error:{code:r,message:e}}}class l extends Error{}async function m(){let t=function(t={}){let r=t.handlePayload??d,e=t.write??h,n=Promise.resolve();return{push:t=>{var i;let o=Array.isArray(i=t)?1===i.length?i[0]?.id??null:null:i.id??null;n=n.then(async()=>{let n=await r(t);n&&e(n)}).catch(t=>{e({jsonrpc:"2.0",id:o,error:{code:-32603,message:t instanceof Error?t.message:String(t)}})})},idle:async()=>{await n}}}(),r=new g(r=>{t.push(r)});process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{try{r.push(t)}catch(t){h({jsonrpc:"2.0",id:null,error:{code:-32700,message:t instanceof Error?t.message:String(t)}})}}),await new Promise(t=>{process.stdin.on("end",t),process.stdin.on("close",t),process.stdin.resume()}),await t.idle()}function d(t){return Array.isArray(t)?y(t):u(t)}async function y(t){let r=[];for(let n of t){var e;r.push(...(e=await u(n))?[e]:[])}return r.length>0?r:null}class g{buffer="";sink;constructor(t){this.sink=t}push(t){for(this.buffer+=t;;){let t=this.tryReadLineMessage();if(void 0!==t){this.emit(t);continue}break}}tryReadLineMessage(){let t=this.buffer.indexOf("\n");if(-1===t)return;let r=this.buffer.slice(0,t).trim();return this.buffer=this.buffer.slice(t+1),r.length>0?r:void 0}emit(t){let r=JSON.parse(t);Array.isArray(r),this.sink(r)}}function h(t){process.stdout.write(`${JSON.stringify(t)}
1
+ import{formatCliOutput as t}from"./cli-output.js";import{listMcpCommandMetadata as r,isCommandName as e}from"./2948.js";import{readVersion as n}from"./7244.js";let i=function(r={}){return{execute:async(n,i)=>{var u;if(!e(n))throw Error(`Unknown command tool: ${n}`);let c=!(u=i)||"object"!=typeof u||Array.isArray(u)?{client:{},outputFormat:"optimized"}:{client:function(t){let r=t.stateDir,e={};if(void 0!==r&&("string"!=typeof r||0===r.length))throw Error("Expected stateDir to be a non-empty string.");return"string"==typeof r&&(e.stateDir=r),e}(u),outputFormat:function(t){if(void 0===t)return"optimized";if("optimized"!==t&&"json"!==t)throw Error('Expected mcpOutputFormat to be "optimized" or "json".');return t}(u.mcpOutputFormat)},p=function(t){if(!t||"object"!=typeof t||Array.isArray(t))return t;let{stateDir:r,mcpOutputFormat:e,...n}=t;return n}(i),f=await o(r,c.client),l=await (r.runCommand??s)(f,n,p);return{isError:!1,structuredContent:l,content:[{type:"text",text:function(r){if("json"===r.outputFormat)return a(r.result);let e=t({name:r.name,input:r.input,result:r.result});return"string"==typeof e?.text?e.text:a(e?.data??r.result)}({name:n,input:p,result:l,outputFormat:c.outputFormat})}]}}}}();async function o(t,r){if(t.createClient)return await t.createClient(r);let{createAgentDeviceClient:e}=await import("./9919.js");return e(r)}async function s(t,r,e){let n=await import("./command-surface.js");return await n.runCommand(t,r,e)}function a(t){return"string"==typeof t?t:JSON.stringify(t,null,2)}async function u(t){if("2.0"!==t.jsonrpc||"string"!=typeof t.method)return f(t.id??null,-32600,"Invalid JSON-RPC request.");if(void 0===t.id)return null;try{var r,e;return r=t.id,e=await c(t.method,t.params),{jsonrpc:"2.0",id:r,result:e}}catch(r){if(r instanceof l)return f(t.id,-32601,r.message);return f(t.id,-32602,r instanceof Error?r.message:String(r))}}async function c(t,e){switch(t){case"initialize":return{protocolVersion:"2025-11-25",capabilities:{tools:{}},serverInfo:{name:"agent-device",version:n()}};case"ping":return{};case"tools/list":return{tools:r().map(t=>{var r;return{name:t.name,description:t.description,inputSchema:{...r=t.inputSchema,properties:{...r.properties,stateDir:{type:"string",description:"Agent-device state directory."},mcpOutputFormat:{type:"string",enum:["optimized","json"],description:"MCP text content format. Defaults to optimized agent-friendly text; use json for JSON text. Structured content is always returned separately."}}}}})};case"tools/call":return await p(e);default:throw new l(`Unsupported MCP method: ${t}`)}}async function p(t){let r=function(t){if(!t||"object"!=typeof t||Array.isArray(t))throw Error("Expected object parameters.");return t}(t),e=function(t,r){let e=t[r];if("string"!=typeof e||0===e.length)throw Error(`Expected ${r} to be a non-empty string.`);return e}(r,"name");try{return await i.execute(e,r.arguments)}catch(t){return function(t,r=!1){return{isError:r,content:[{type:"text",text:t}]}}(t instanceof Error?t.message:String(t),!0)}}function f(t,r,e){return{jsonrpc:"2.0",id:t,error:{code:r,message:e}}}class l extends Error{}async function m(){let t=function(t={}){let r=t.handlePayload??d,e=t.write??h,n=Promise.resolve();return{push:t=>{var i;let o=Array.isArray(i=t)?1===i.length?i[0]?.id??null:null:i.id??null;n=n.then(async()=>{let n=await r(t);n&&e(n)}).catch(t=>{e({jsonrpc:"2.0",id:o,error:{code:-32603,message:t instanceof Error?t.message:String(t)}})})},idle:async()=>{await n}}}(),r=new g(r=>{t.push(r)});process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{try{r.push(t)}catch(t){h({jsonrpc:"2.0",id:null,error:{code:-32700,message:t instanceof Error?t.message:String(t)}})}}),await new Promise(t=>{process.stdin.on("end",t),process.stdin.on("close",t),process.stdin.resume()}),await t.idle()}function d(t){return Array.isArray(t)?y(t):u(t)}async function y(t){let r=[];for(let n of t){var e;r.push(...(e=await u(n))?[e]:[])}return r.length>0?r:null}class g{buffer="";sink;constructor(t){this.sink=t}push(t){for(this.buffer+=t;;){let t=this.tryReadLineMessage();if(void 0!==t){this.emit(t);continue}break}}tryReadLineMessage(){let t=this.buffer.indexOf("\n");if(-1===t)return;let r=this.buffer.slice(0,t).trim();return this.buffer=this.buffer.slice(t+1),r.length>0?r:void 0}emit(t){let r=JSON.parse(t);Array.isArray(r),this.sink(r)}}function h(t){process.stdout.write(`${JSON.stringify(t)}
2
2
  `)}export{m as runAgentDeviceMcpServer};