agent-device 0.19.1 → 0.19.3

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 (88) hide show
  1. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.apk +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.1.manifest.json → agent-device-android-multitouch-helper-0.19.3.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.1.apk → agent-device-android-snapshot-helper-0.19.3.apk} +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.3.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.1.manifest.json → agent-device-android-snapshot-helper-0.19.3.manifest.json} +6 -6
  7. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +7 -0
  8. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +99 -30
  9. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +9 -1
  10. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +21 -8
  11. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +10 -0
  12. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +1 -0
  13. package/dist/src/agent-browser-tool.js +1 -1
  14. package/dist/src/android-adb.js +1 -1
  15. package/dist/src/android-input-ownership.js +1 -1
  16. package/dist/src/android.js +1 -1
  17. package/dist/src/app-lifecycle.js +1 -1
  18. package/dist/src/apple-runner-options.js +1 -1
  19. package/dist/src/apps.js +5 -5
  20. package/dist/src/audio-probe.js +1 -1
  21. package/dist/src/cli-help.js +34 -19
  22. package/dist/src/cli-runner.js +1 -1
  23. package/dist/src/cli.js +11 -11
  24. package/dist/src/client.js +2 -2
  25. package/dist/src/contracts.js +1 -1
  26. package/dist/src/debug-symbols.js +1 -1
  27. package/dist/src/device-input-state.js +1 -1
  28. package/dist/src/devices2.js +1 -1
  29. package/dist/src/find.js +1 -1
  30. package/dist/src/generic.js +1 -1
  31. package/dist/src/helper.js +1 -1
  32. package/dist/src/index.d.ts +29 -0
  33. package/dist/src/index.js +1 -1
  34. package/dist/src/input-actions.js +1 -1
  35. package/dist/src/input-actions2.js +1 -1
  36. package/dist/src/install-source2.js +1 -1
  37. package/dist/src/interaction-snapshot.js +1 -1
  38. package/dist/src/interaction.js +1 -1
  39. package/dist/src/interactor.js +2 -2
  40. package/dist/src/internal/bin.js +1 -1
  41. package/dist/src/internal/daemon.js +20 -16
  42. package/dist/src/internal/png-worker.js +1 -1
  43. package/dist/src/lease.js +1 -1
  44. package/dist/src/linux.js +1 -1
  45. package/dist/src/notifications.js +1 -1
  46. package/dist/src/png-worker-contract.js +1 -1
  47. package/dist/src/points.js +3 -3
  48. package/dist/src/providers.js +1 -1
  49. package/dist/src/react-native.js +1 -1
  50. package/dist/src/record-trace-recording.js +2 -2
  51. package/dist/src/record-trace.js +1 -1
  52. package/dist/src/registry.js +24 -24
  53. package/dist/src/reporting.js +3 -3
  54. package/dist/src/runner-client.js +1 -1
  55. package/dist/src/runner-sequence.js +1 -1
  56. package/dist/src/runtime-transport.js +1 -1
  57. package/dist/src/runtime.js +2 -2
  58. package/dist/src/sdk-android-adb.js +3 -3
  59. package/dist/src/sdk-app-inventory.js +1 -1
  60. package/dist/src/sdk-batch-runner.js +2 -2
  61. package/dist/src/sdk-batch.js +2 -2
  62. package/dist/src/sdk-contracts.js +2 -2
  63. package/dist/src/sdk-device.js +1 -0
  64. package/dist/src/sdk-finders.js +1 -1
  65. package/dist/src/sdk-io.js +1 -1
  66. package/dist/src/sdk-remote-config.js +1 -1
  67. package/dist/src/sdk-selectors.js +1 -1
  68. package/dist/src/selector-runtime.js +1 -1
  69. package/dist/src/selectors.js +1 -1
  70. package/dist/src/server.js +2 -2
  71. package/dist/src/session.js +10 -10
  72. package/dist/src/setting-state.js +1 -1
  73. package/dist/src/simctl.js +1 -1
  74. package/dist/src/simulator.js +1 -1
  75. package/dist/src/snapshot-diagnostics.js +1 -1
  76. package/dist/src/snapshot.js +1 -1
  77. package/dist/src/snapshot2.js +2 -2
  78. package/dist/src/tool-provider.js +2 -2
  79. package/dist/src/tool-provider2.js +1 -1
  80. package/dist/src/tv-remote.js +9 -9
  81. package/dist/src/version.js +1 -1
  82. package/dist/src/web.js +1 -1
  83. package/package.json +11 -3
  84. package/server.json +2 -2
  85. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.1.apk +0 -0
  86. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.1.apk.sha256 +0 -1
  87. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.1.apk.sha256 +0 -1
  88. package/dist/src/snapshot-helper.js +0 -5
@@ -1 +1 @@
1
- import{B as e}from"../sdk-contracts.js";import{i as t,n,r,t as i}from"../png-worker-contract.js";import{parentPort as a}from"node:worker_threads";function o(e){switch(e.kind){case`decode`:{let t=r(i(e.png),e.label);return{kind:`decode`,width:t.width,height:t.height,data:t.data}}case`encode`:{let n=new t({width:e.width,height:e.height,data:i(e.data)});return{kind:`encode`,png:t.sync.write(n)}}case`diff-pixels`:return{kind:`diff-pixels`,...n(e)}}}function s(e){return e.buffer instanceof ArrayBuffer&&e.byteOffset===0&&e.byteLength===e.buffer.byteLength}function c(e){return l(e).filter(s).map(e=>e.buffer)}function l(e){switch(e.kind){case`decode`:return[e.data];case`encode`:return[e.png];case`diff-pixels`:return[e.diffData,e.diffMask]}}const u=a;u&&u.on(`message`,t=>{let n;try{n={id:t.id,ok:!0,result:o(t)}}catch(r){n={id:t.id,ok:!1,error:e(r)}}u.postMessage(n,n.ok?c(n.result):[])});export{c as resultTransferList};
1
+ import{S as e}from"../sdk-contracts.js";import{i as t,n,r,t as i}from"../png-worker-contract.js";import{parentPort as a}from"node:worker_threads";function o(e){switch(e.kind){case`decode`:{let t=r(i(e.png),e.label);return{kind:`decode`,width:t.width,height:t.height,data:t.data}}case`encode`:{let n=new t({width:e.width,height:e.height,data:i(e.data)});return{kind:`encode`,png:t.sync.write(n)}}case`diff-pixels`:return{kind:`diff-pixels`,...n(e)}}}function s(e){return e.buffer instanceof ArrayBuffer&&e.byteOffset===0&&e.byteLength===e.buffer.byteLength}function c(e){return l(e).filter(s).map(e=>e.buffer)}function l(e){switch(e.kind){case`decode`:return[e.data];case`encode`:return[e.png];case`diff-pixels`:return[e.diffData,e.diffMask]}}const u=a;u&&u.on(`message`,t=>{let n;try{n={id:t.id,ok:!0,result:o(t)}}catch(r){n={id:t.id,ok:!1,error:e(r)}}u.postMessage(n,n.ok?c(n.result):[])});export{c as resultTransferList};
package/dist/src/lease.js CHANGED
@@ -1 +1 @@
1
- import{F as e}from"./sdk-contracts.js";import{In as t,On as n,Pn as r,Qn as i,jn as a}from"./tv-remote.js";import{Bt as o,Vt as s,yn as c}from"./internal/daemon.js";async function l(e){let{req:n,sessionName:c,sessionStore:l,leaseRegistry:d,leaseLifecycleProvider:f,cloudArtifactProvider:p}=e,m=o(n);switch(n.command){case i.artifacts:return{ok:!0,data:await u(n,s(n,l.get(c)),p)};case`lease_allocate`:{let e=d.allocateLease(a(m)),r;try{r=await f?.allocate?.(e,{req:n})}catch(n){throw d.releaseLease(t({leaseId:e.leaseId,tenantId:e.tenantId,runId:e.runId,leaseBackend:e.backend,leaseProvider:e.leaseProvider,deviceKey:e.deviceKey,clientId:e.clientId})),n}return{ok:!0,data:{lease:e,...r?{provider:r}:{}}}}case`lease_heartbeat`:{let e=d.heartbeatLease(r(m)),t=await f?.heartbeat?.(e,{req:n});return{ok:!0,data:{lease:e,...t?{provider:t}:{}}}}case`lease_release`:{let e=d.releaseLease(t(m)),r=e.lease?await f?.release?.(e.lease,{req:n}):void 0;return{ok:!0,data:{released:e.released,...r?{provider:r}:{}}}}default:return null}}async function u(e,t,n){let r=m(e.flags,`providerSessionId`);return d(t,r)?await f(t.tenantId):await p(t,r,n)}function d(e,t){return n(e)||!e.leaseProvider&&!t}async function f(e){let t=await c(e);return{source:`daemon`,status:`ready`,artifacts:t,...t.length===0?{message:`No daemon artifacts available.`}:{}}}async function p(t,n,r){if(!t.leaseProvider)throw new e(`INVALID_ARGS`,`artifacts requires --provider for provider session lookup or an active cloud connection.`);if(!t.leaseId&&!n)throw new e(`INVALID_ARGS`,`artifacts requires an active cloud lease or --provider-session <id>.`);let i=await r?.listCloudArtifacts?.({provider:t.leaseProvider,leaseId:t.leaseId,providerSessionId:n});if(!i)throw new e(`UNSUPPORTED_OPERATION`,`Cloud artifacts are not available for provider "${t.leaseProvider}".`);return i}function m(e,t){let n=e?.[t];return typeof n==`string`&&n.length>0?n:void 0}export{l as handleLeaseCommands};
1
+ import{_ as e}from"./sdk-contracts.js";import{En as t,Mn as n,Pn as r,Xn as i,kn as a}from"./tv-remote.js";import{Gt as o,Kt as s,wn as c}from"./internal/daemon.js";async function l(e){let{req:t,sessionName:c,sessionStore:l,leaseRegistry:d,leaseLifecycleProvider:f,cloudArtifactProvider:p}=e,m=o(t);switch(t.command){case i.artifacts:return{ok:!0,data:await u(t,s(t,l.get(c)),p)};case`lease_allocate`:{let e=d.allocateLease(a(m)),n;try{n=await f?.allocate?.(e,{req:t})}catch(t){throw d.releaseLease(r({leaseId:e.leaseId,tenantId:e.tenantId,runId:e.runId,leaseBackend:e.backend,leaseProvider:e.leaseProvider,deviceKey:e.deviceKey,clientId:e.clientId})),t}return{ok:!0,data:{lease:e,...n?{provider:n}:{}}}}case`lease_heartbeat`:{let e=d.heartbeatLease(n(m)),r=await f?.heartbeat?.(e,{req:t});return{ok:!0,data:{lease:e,...r?{provider:r}:{}}}}case`lease_release`:{let e=d.releaseLease(r(m)),n=e.lease?await f?.release?.(e.lease,{req:t}):void 0;return{ok:!0,data:{released:e.released,...n?{provider:n}:{}}}}default:return null}}async function u(e,t,n){let r=m(e.flags,`providerSessionId`);return d(t,r)?await f(t.tenantId):await p(t,r,n)}function d(e,n){return t(e)||!e.leaseProvider&&!n}async function f(e){let t=await c(e);return{source:`daemon`,status:`ready`,artifacts:t,...t.length===0?{message:`No daemon artifacts available.`}:{}}}async function p(t,n,r){if(!t.leaseProvider)throw new e(`INVALID_ARGS`,`artifacts requires --provider for provider session lookup or an active cloud connection.`);if(!t.leaseId&&!n)throw new e(`INVALID_ARGS`,`artifacts requires an active cloud lease or --provider-session <id>.`);let i=await r?.listCloudArtifacts?.({provider:t.leaseProvider,leaseId:t.leaseId,providerSessionId:n});if(!i)throw new e(`UNSUPPORTED_OPERATION`,`Cloud artifacts are not available for provider "${t.leaseProvider}".`);return i}function m(e,t){let n=e?.[t];return typeof n==`string`&&n.length>0?n:void 0}export{l as handleLeaseCommands};
package/dist/src/linux.js CHANGED
@@ -1 +1 @@
1
- import{F as e}from"./sdk-contracts.js";import{F as t}from"./sdk-android-adb.js";import{t as n}from"./snapshot.js";import{t as r}from"./tool-provider2.js";import{doubleClickLinux as i,fillLinux as a,focusLinux as o,longPressLinux as s,pressLinux as c,scrollLinux as l,sendKey as u,swipeLinux as d,typeLinux as f}from"./input-actions2.js";async function p(e){await r().desktop.openTarget(e)}async function m(e){await r().desktop.closeApp(e)}async function h(){await u(`alt+Left`,[`56:1`,`105:1`,`105:0`,`56:0`])}async function g(){await u(`super+d`,[`125:1`,`32:1`,`32:0`,`125:0`])}async function _(){return await r().clipboard.readText()}async function v(e){await r().clipboard.writeText(e)}async function y(e,t){await r().screenshot.capture(e,t)}function b(){return{open:e=>p(e),openDevice:()=>Promise.resolve(),close:e=>m(e),tap:(e,t)=>c(e,t),doubleTap:(e,t)=>i(e,t),swipe:(e,t,n,r,i)=>d(e,t,n,r,i),pan:(e,t,n,r,i)=>d(e,t,n,r,i),fling:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture fling not supported on Linux`)},longPress:(e,t,n)=>s(e,t,n),focus:(e,t)=>o(e,t),type:(e,t)=>f(e,t),fill:(e,t,n,r)=>a(e,t,n,r),scroll:(e,t)=>l(e,t),pinch:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture pinch not supported on Linux`)},screenshot:(e,t)=>y(e,t),snapshot:async e=>{let r=await t(`snapshot_capture`,async()=>await n(e?.surface),{backend:`linux-atspi`});return{nodes:r.nodes??[],truncated:r.truncated??!1,backend:`linux-atspi`}},back:()=>h(),home:()=>g(),rotate:()=>{throw new e(`UNSUPPORTED_OPERATION`,`rotate not supported on Linux`)},rotateGesture:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture rotate not supported on Linux`)},transformGesture:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture transform not supported on Linux`)},appSwitcher:()=>{throw new e(`UNSUPPORTED_OPERATION`,`appSwitcher not yet supported on Linux`)},tvRemote:()=>{throw new e(`UNSUPPORTED_OPERATION`,`tv-remote not supported on Linux`)},readClipboard:()=>_(),writeClipboard:e=>v(e),setSetting:()=>{throw new e(`UNSUPPORTED_OPERATION`,`setSetting not supported on Linux`)}}}export{b as createLinuxInteractor};
1
+ import{_ as e}from"./sdk-contracts.js";import{F as t}from"./sdk-android-adb.js";import{t as n}from"./snapshot.js";import{t as r}from"./tool-provider2.js";import{doubleClickLinux as i,fillLinux as a,focusLinux as o,longPressLinux as s,pressLinux as c,scrollLinux as l,sendKey as u,swipeLinux as d,typeLinux as f}from"./input-actions2.js";async function p(e){await r().desktop.openTarget(e)}async function m(e){await r().desktop.closeApp(e)}async function h(){await u(`alt+Left`,[`56:1`,`105:1`,`105:0`,`56:0`])}async function g(){await u(`super+d`,[`125:1`,`32:1`,`32:0`,`125:0`])}async function _(){return await r().clipboard.readText()}async function v(e){await r().clipboard.writeText(e)}async function y(e,t){await r().screenshot.capture(e,t)}function b(){return{open:e=>p(e),openDevice:()=>Promise.resolve(),close:e=>m(e),tap:(e,t)=>c(e,t),doubleTap:(e,t)=>i(e,t),swipe:(e,t,n,r,i)=>d(e,t,n,r,i),pan:(e,t,n,r,i)=>d(e,t,n,r,i),fling:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture fling not supported on Linux`)},longPress:(e,t,n)=>s(e,t,n),focus:(e,t)=>o(e,t),type:(e,t)=>f(e,t),fill:(e,t,n,r)=>a(e,t,n,r),scroll:(e,t)=>l(e,t),pinch:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture pinch not supported on Linux`)},screenshot:(e,t)=>y(e,t),snapshot:async e=>{let r=await t(`snapshot_capture`,async()=>await n(e?.surface),{backend:`linux-atspi`});return{nodes:r.nodes??[],truncated:r.truncated??!1,backend:`linux-atspi`}},back:()=>h(),home:()=>g(),rotate:()=>{throw new e(`UNSUPPORTED_OPERATION`,`rotate not supported on Linux`)},rotateGesture:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture rotate not supported on Linux`)},transformGesture:()=>{throw new e(`UNSUPPORTED_OPERATION`,`gesture transform not supported on Linux`)},appSwitcher:()=>{throw new e(`UNSUPPORTED_OPERATION`,`appSwitcher not yet supported on Linux`)},tvRemote:()=>{throw new e(`UNSUPPORTED_OPERATION`,`tv-remote not supported on Linux`)},readClipboard:()=>_(),writeClipboard:e=>v(e),setSetting:()=>{throw new e(`UNSUPPORTED_OPERATION`,`setSetting not supported on Linux`)}}}export{b as createLinuxInteractor};
@@ -1 +1 @@
1
- import{F as e}from"./sdk-contracts.js";import{p as t}from"./android-input-ownership.js";async function n(n,i,a){let o=typeof a.action==`string`&&a.action.trim()?a.action.trim():`${i}.TEST_PUSH`,s=[`shell`,`am`,`broadcast`,`-a`,o,`-p`,i],c=typeof a.receiver==`string`?a.receiver.trim():``;c&&s.push(`-n`,c);let l=a.extras;if(l!==void 0&&(typeof l!=`object`||!l||Array.isArray(l)))throw new e(`INVALID_ARGS`,`Android push payload extras must be an object`);let u=l??{},d=0;for(let[e,t]of Object.entries(u))e&&(r(s,e,t),d+=1);return await t(n,s),{action:o,extrasCount:d}}function r(t,n,r){if(typeof r==`string`){t.push(`--es`,n,r);return}if(typeof r==`boolean`){t.push(`--ez`,n,r?`true`:`false`);return}if(typeof r==`number`&&Number.isFinite(r)){if(Number.isInteger(r)){t.push(`--ei`,n,String(r));return}t.push(`--ef`,n,String(r));return}throw new e(`INVALID_ARGS`,`Unsupported Android broadcast extra type for "${n}". Use string, boolean, or number.`)}export{n as pushAndroidNotification};
1
+ import{_ as e}from"./sdk-contracts.js";import{p as t}from"./android-input-ownership.js";async function n(n,i,a){let o=typeof a.action==`string`&&a.action.trim()?a.action.trim():`${i}.TEST_PUSH`,s=[`shell`,`am`,`broadcast`,`-a`,o,`-p`,i],c=typeof a.receiver==`string`?a.receiver.trim():``;c&&s.push(`-n`,c);let l=a.extras;if(l!==void 0&&(typeof l!=`object`||!l||Array.isArray(l)))throw new e(`INVALID_ARGS`,`Android push payload extras must be an object`);let u=l??{},d=0;for(let[e,t]of Object.entries(u))e&&(r(s,e,t),d+=1);return await t(n,s),{action:o,extrasCount:d}}function r(t,n,r){if(typeof r==`string`){t.push(`--es`,n,r);return}if(typeof r==`boolean`){t.push(`--ez`,n,r?`true`:`false`);return}if(typeof r==`number`&&Number.isFinite(r)){if(Number.isInteger(r)){t.push(`--ei`,n,String(r));return}t.push(`--ef`,n,String(r));return}throw new e(`INVALID_ARGS`,`Unsupported Android broadcast extra type for "${n}". Use string, boolean, or number.`)}export{n as pushAndroidNotification};
@@ -1 +1 @@
1
- import{F as e}from"./sdk-contracts.js";import{deflateSync as t,inflateSync as n}from"node:zlib";const r=Buffer.from([137,80,78,71,13,10,26,10]),i=new Map([[0,1],[2,3],[3,1],[4,2],[6,4]]),a=new Map([[0,new Set([1,2,4,8,16])],[2,new Set([8,16])],[3,new Set([1,2,4,8])],[4,new Set([8,16])],[6,new Set([8,16])]]),o=[{x:0,y:0,dx:8,dy:8},{x:4,y:0,dx:8,dy:8},{x:0,y:4,dx:4,dy:8},{x:2,y:0,dx:4,dy:4},{x:0,y:2,dx:2,dy:4},{x:1,y:0,dx:2,dy:2},{x:0,y:1,dx:1,dy:2}];var s=class{width;height;data;static sync={read:c,write:p};constructor(e){this.width=I(e.width,`width`),this.height=I(e.height,`height`);let t=this.width*this.height*4;if(this.data=e.data?Buffer.from(e.data):Buffer.alloc(t),this.data.length!==t)throw Error(`PNG data length must be ${t} bytes`)}};function c(e){let{metadata:t,idatChunks:n}=l(e);if(!t)throw Error(`PNG is missing IHDR`);if(n.length===0)throw Error(`PNG is missing IDAT`);let r=f(n,t);return new s({width:t.width,height:t.height,data:t.interlace===1?b(r,t):y(g(r,t),t)})}function l(e){let t,n=[];for(let r of d(e))if(r.type===`IHDR`?t=m(r.data):r.type===`IDAT`?n.push(Buffer.from(r.data)):t=u(r,t),r.type===`IEND`)break;return{metadata:t,idatChunks:n}}function u(e,t){if(e.type===`PLTE`){if(!t)throw Error(`PNG PLTE appeared before IHDR`);t.palette=Buffer.from(e.data)}else if(e.type===`tRNS`){if(!t)throw Error(`PNG tRNS appeared before IHDR`);t.transparency=Buffer.from(e.data)}return t}function*d(e){if(!e.subarray(0,r.length).equals(r))throw Error(`Invalid PNG signature`);let t=r.length;for(;t<e.length;){if(t+12>e.length)throw Error(`Truncated PNG chunk`);let n=e.readUInt32BE(t),r=e.toString(`ascii`,t+4,t+8),i=t+8,a=i+n;if(a+4>e.length)throw Error(`Truncated PNG ${r} chunk`);let o=e.subarray(i,a),s=e.readUInt32BE(a);if(P(e.subarray(t+4,a))!==s)throw Error(`Invalid PNG ${r} chunk CRC`);t=a+4,yield{type:r,data:o}}}function f(e,t){let r=x(t);try{let t=n(Buffer.concat(e),{maxOutputLength:r});if(t.length!==r)throw Error(`PNG pixel data is truncated`);return t}catch(e){throw L(e)?Error(`PNG pixel data exceeds expected length ${r}`):e}}function p(e){let n=e.width*4,i=Buffer.alloc((n+1)*e.height);for(let t=0;t<e.height;t+=1){let r=t*(n+1);i[r]=0,e.data.copy(i,r+1,t*n,(t+1)*n)}let a=Buffer.alloc(13);return a.writeUInt32BE(e.width,0),a.writeUInt32BE(e.height,4),a[8]=8,a[9]=6,a[10]=0,a[11]=0,a[12]=0,Buffer.concat([r,N(`IHDR`,a),N(`IDAT`,t(i)),N(`IEND`,Buffer.alloc(0))])}function m(e){if(e.length!==13)throw Error(`Invalid PNG IHDR length`);let t=e.readUInt32BE(0),n=e.readUInt32BE(4),r=e[8],i=e[9],o=e[10],s=e[11],c=e[12];if(!h(i))throw Error(`Unsupported PNG color type ${i}`);if(!a.get(i)?.has(r))throw Error(`Unsupported PNG color type ${i} with bit depth ${r}`);if(o!==0)throw Error(`Unsupported PNG compression method ${o}`);if(s!==0)throw Error(`Unsupported PNG filter method ${s}`);if(c!==0&&c!==1)throw Error(`Unsupported PNG interlace method ${c}`);return{width:I(t,`width`),height:I(n,`height`),bitDepth:r,colorType:i,interlace:c}}function h(e){return i.has(e)}function g(e,t){return _({inflated:e,offset:0,scanlineLength:O(t),height:t.height,bytesPerPixel:k(t)}).raw}function _(e){let{inflated:t,offset:n,scanlineLength:r,height:i,bytesPerPixel:a}=e,o=n+(r+1)*i;if(t.length<o)throw Error(`PNG pixel data is truncated`);let s=Buffer.alloc(r*i);for(let e=0;e<i;e+=1){let i=n+e*(r+1),o=e*r,c=t[i];for(let n=0;n<r;n+=1){let l=t[i+1+n],u=n>=a?s[o+n-a]:0,d=e>0?s[o+n-r]:0,f=e>0&&n>=a?s[o+n-r-a]:0;s[o+n]=v(c,l,u,d,f)}}return{raw:s,offset:o}}function v(e,t,n,r,i){if(e===0)return t;if(e===1)return t+n&255;if(e===2)return t+r&255;if(e===3)return t+Math.floor((n+r)/2)&255;if(e===4)return t+F(n,r,i)&255;throw Error(`Unsupported PNG filter type ${e}`)}function y(e,t){let n=Buffer.alloc(t.width*t.height*4),r=O(t);for(let i=0;i<t.height;i+=1){let a=e.subarray(i*r,(i+1)*r);for(let e=0;e<t.width;e+=1){let r=(i*t.width+e)*4,[o,s,c,l]=w(a,e,t);n[r]=o,n[r+1]=s,n[r+2]=c,n[r+3]=l}}return n}function b(e,t){let n=Buffer.alloc(t.width*t.height*4),r=0;for(let i of o){let a=C(t.width,i.x,i.dx),o=C(t.height,i.y,i.dy);if(a===0||o===0)continue;let s={...t,width:a,height:o,interlace:0},c=_({inflated:e,offset:r,scanlineLength:O(s),height:o,bytesPerPixel:k(s)});r=c.offset;let l=O(s);for(let e=0;e<o;e+=1){let r=c.raw.subarray(e*l,(e+1)*l);for(let o=0;o<a;o+=1){let a=i.x+o*i.dx,c=((i.y+e*i.dy)*t.width+a)*4,[l,u,d,f]=w(r,o,s);n[c]=l,n[c+1]=u,n[c+2]=d,n[c+3]=f}}}return n}function x(e){if(e.interlace===0)return S(e,e.height);let t=0;for(let n of o){let r=C(e.width,n.x,n.dx),i=C(e.height,n.y,n.dy);r===0||i===0||(t+=S({...e,width:r,height:i},i))}return t}function S(e,t){return(O(e)+1)*t}function C(e,t,n){return e<=t?0:Math.floor((e-t+n-1)/n)}function w(e,t,n){if(n.colorType===3)return T(e,t,n);if(n.bitDepth<8)return E(e,t,n);let r=n.bitDepth===16?2:1,a=t*i.get(n.colorType)*r,o=t=>n.bitDepth===16?e.readUInt16BE(a+t*2):e[a+t*r],s=e=>A(o(e),n.bitDepth);if(n.colorType===0){let e=s(0);return[e,e,e,j(o(0),n)?0:255]}if(n.colorType===2)return[s(0),s(1),s(2),M(o(0),o(1),o(2),n)?0:255];if(n.colorType===4){let e=s(0);return[e,e,e,s(1)]}return[s(0),s(1),s(2),s(3)]}function T(e,t,n){if(!n.palette)throw Error(`Indexed PNG is missing PLTE`);let r=D(e,t,n.bitDepth),i=r*3;if(i+2>=n.palette.length)throw Error(`Indexed PNG palette is invalid`);return[n.palette[i],n.palette[i+1],n.palette[i+2],n.transparency?.[r]??255]}function E(e,t,n){let r=D(e,t,n.bitDepth),i=(1<<n.bitDepth)-1,a=Math.round(r/i*255);return[a,a,a,n.transparency&&n.transparency.length>=2&&r===n.transparency.readUInt16BE(0)?0:255]}function D(e,t,n){let r=t*n;return e[Math.floor(r/8)]>>8-n-r%8&(1<<n)-1}function O(e){let t=i.get(e.colorType);return Math.ceil(e.width*t*e.bitDepth/8)}function k(e){let t=i.get(e.colorType);return Math.max(1,Math.ceil(t*e.bitDepth/8))}function A(e,t){return t===16?Math.round(e/65535*255):e}function j(e,t){return!t.transparency||t.transparency.length<2?!1:e===t.transparency.readUInt16BE(0)}function M(e,t,n,r){return!r.transparency||r.transparency.length<6?!1:e===r.transparency.readUInt16BE(0)&&t===r.transparency.readUInt16BE(2)&&n===r.transparency.readUInt16BE(4)}function N(e,t){let n=Buffer.from(e,`ascii`),r=Buffer.alloc(8+t.length+4);return r.writeUInt32BE(t.length,0),n.copy(r,4),t.copy(r,8),r.writeUInt32BE(P(Buffer.concat([n,t])),8+t.length),r}function P(e){let t=4294967295;for(let n of e){t^=n;for(let e=0;e<8;e+=1)t=t&1?3988292384^t>>>1:t>>>1}return(t^4294967295)>>>0}function F(e,t,n){let r=e+t-n,i=Math.abs(r-e),a=Math.abs(r-t),o=Math.abs(r-n);return i<=a&&i<=o?e:a<=o?t:n}function I(e,t){if(!Number.isInteger(e)||e<1)throw Error(`PNG ${t} must be positive`);return e}function L(e){return e instanceof Error&&`code`in e&&e.code===`ERR_BUFFER_TOO_LARGE`}function R(t,n){try{return s.sync.read(t)}catch(t){throw new e(`COMMAND_FAILED`,`Failed to decode ${n} as PNG`,{label:n,reason:t instanceof Error?t.message:String(t)})}}const z=.78,B={r:220,g:0,b:0};function V(e){let{baselineData:t,currentData:n,maxColorDistance:r}=e,i=e.width*e.height,a=Buffer.alloc(i*4),o=new Uint8Array(i),s=0;for(let e=0,i=0;e<t.length;e+=4,i+=1){let c=t[e]-n[e],l=t[e+1]-n[e+1],u=t[e+2]-n[e+2];if(Math.sqrt(c**2+l**2+u**2)>r){s+=1,o[i]=1;let t=H(n,e);a[e]=U(t,B.r,z),a[e+1]=U(t,B.g,z),a[e+2]=U(t,B.b,z),a[e+3]=255;continue}let d=H(n,e);a[e]=d,a[e+1]=d,a[e+2]=d,a[e+3]=255}return{diffData:a,diffMask:o,differentPixels:s}}function H(e,t){return U(Math.round(e[t]*.299+e[t+1]*.587+e[t+2]*.114),255,.72)}function U(e,t,n){return Math.round(e*(1-n)+t*n)}function W(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}export{s as i,V as n,R as r,W as t};
1
+ import{_ as e}from"./sdk-contracts.js";import{deflateSync as t,inflateSync as n}from"node:zlib";const r=Buffer.from([137,80,78,71,13,10,26,10]),i=new Map([[0,1],[2,3],[3,1],[4,2],[6,4]]),a=new Map([[0,new Set([1,2,4,8,16])],[2,new Set([8,16])],[3,new Set([1,2,4,8])],[4,new Set([8,16])],[6,new Set([8,16])]]),o=[{x:0,y:0,dx:8,dy:8},{x:4,y:0,dx:8,dy:8},{x:0,y:4,dx:4,dy:8},{x:2,y:0,dx:4,dy:4},{x:0,y:2,dx:2,dy:4},{x:1,y:0,dx:2,dy:2},{x:0,y:1,dx:1,dy:2}];var s=class{width;height;data;static sync={read:c,write:p};constructor(e){this.width=I(e.width,`width`),this.height=I(e.height,`height`);let t=this.width*this.height*4;if(this.data=e.data?Buffer.from(e.data):Buffer.alloc(t),this.data.length!==t)throw Error(`PNG data length must be ${t} bytes`)}};function c(e){let{metadata:t,idatChunks:n}=l(e);if(!t)throw Error(`PNG is missing IHDR`);if(n.length===0)throw Error(`PNG is missing IDAT`);let r=f(n,t);return new s({width:t.width,height:t.height,data:t.interlace===1?b(r,t):y(g(r,t),t)})}function l(e){let t,n=[];for(let r of d(e))if(r.type===`IHDR`?t=m(r.data):r.type===`IDAT`?n.push(Buffer.from(r.data)):t=u(r,t),r.type===`IEND`)break;return{metadata:t,idatChunks:n}}function u(e,t){if(e.type===`PLTE`){if(!t)throw Error(`PNG PLTE appeared before IHDR`);t.palette=Buffer.from(e.data)}else if(e.type===`tRNS`){if(!t)throw Error(`PNG tRNS appeared before IHDR`);t.transparency=Buffer.from(e.data)}return t}function*d(e){if(!e.subarray(0,r.length).equals(r))throw Error(`Invalid PNG signature`);let t=r.length;for(;t<e.length;){if(t+12>e.length)throw Error(`Truncated PNG chunk`);let n=e.readUInt32BE(t),r=e.toString(`ascii`,t+4,t+8),i=t+8,a=i+n;if(a+4>e.length)throw Error(`Truncated PNG ${r} chunk`);let o=e.subarray(i,a),s=e.readUInt32BE(a);if(P(e.subarray(t+4,a))!==s)throw Error(`Invalid PNG ${r} chunk CRC`);t=a+4,yield{type:r,data:o}}}function f(e,t){let r=x(t);try{let t=n(Buffer.concat(e),{maxOutputLength:r});if(t.length!==r)throw Error(`PNG pixel data is truncated`);return t}catch(e){throw L(e)?Error(`PNG pixel data exceeds expected length ${r}`):e}}function p(e){let n=e.width*4,i=Buffer.alloc((n+1)*e.height);for(let t=0;t<e.height;t+=1){let r=t*(n+1);i[r]=0,e.data.copy(i,r+1,t*n,(t+1)*n)}let a=Buffer.alloc(13);return a.writeUInt32BE(e.width,0),a.writeUInt32BE(e.height,4),a[8]=8,a[9]=6,a[10]=0,a[11]=0,a[12]=0,Buffer.concat([r,N(`IHDR`,a),N(`IDAT`,t(i)),N(`IEND`,Buffer.alloc(0))])}function m(e){if(e.length!==13)throw Error(`Invalid PNG IHDR length`);let t=e.readUInt32BE(0),n=e.readUInt32BE(4),r=e[8],i=e[9],o=e[10],s=e[11],c=e[12];if(!h(i))throw Error(`Unsupported PNG color type ${i}`);if(!a.get(i)?.has(r))throw Error(`Unsupported PNG color type ${i} with bit depth ${r}`);if(o!==0)throw Error(`Unsupported PNG compression method ${o}`);if(s!==0)throw Error(`Unsupported PNG filter method ${s}`);if(c!==0&&c!==1)throw Error(`Unsupported PNG interlace method ${c}`);return{width:I(t,`width`),height:I(n,`height`),bitDepth:r,colorType:i,interlace:c}}function h(e){return i.has(e)}function g(e,t){return _({inflated:e,offset:0,scanlineLength:O(t),height:t.height,bytesPerPixel:k(t)}).raw}function _(e){let{inflated:t,offset:n,scanlineLength:r,height:i,bytesPerPixel:a}=e,o=n+(r+1)*i;if(t.length<o)throw Error(`PNG pixel data is truncated`);let s=Buffer.alloc(r*i);for(let e=0;e<i;e+=1){let i=n+e*(r+1),o=e*r,c=t[i];for(let n=0;n<r;n+=1){let l=t[i+1+n],u=n>=a?s[o+n-a]:0,d=e>0?s[o+n-r]:0,f=e>0&&n>=a?s[o+n-r-a]:0;s[o+n]=v(c,l,u,d,f)}}return{raw:s,offset:o}}function v(e,t,n,r,i){if(e===0)return t;if(e===1)return t+n&255;if(e===2)return t+r&255;if(e===3)return t+Math.floor((n+r)/2)&255;if(e===4)return t+F(n,r,i)&255;throw Error(`Unsupported PNG filter type ${e}`)}function y(e,t){let n=Buffer.alloc(t.width*t.height*4),r=O(t);for(let i=0;i<t.height;i+=1){let a=e.subarray(i*r,(i+1)*r);for(let e=0;e<t.width;e+=1){let r=(i*t.width+e)*4,[o,s,c,l]=w(a,e,t);n[r]=o,n[r+1]=s,n[r+2]=c,n[r+3]=l}}return n}function b(e,t){let n=Buffer.alloc(t.width*t.height*4),r=0;for(let i of o){let a=C(t.width,i.x,i.dx),o=C(t.height,i.y,i.dy);if(a===0||o===0)continue;let s={...t,width:a,height:o,interlace:0},c=_({inflated:e,offset:r,scanlineLength:O(s),height:o,bytesPerPixel:k(s)});r=c.offset;let l=O(s);for(let e=0;e<o;e+=1){let r=c.raw.subarray(e*l,(e+1)*l);for(let o=0;o<a;o+=1){let a=i.x+o*i.dx,c=((i.y+e*i.dy)*t.width+a)*4,[l,u,d,f]=w(r,o,s);n[c]=l,n[c+1]=u,n[c+2]=d,n[c+3]=f}}}return n}function x(e){if(e.interlace===0)return S(e,e.height);let t=0;for(let n of o){let r=C(e.width,n.x,n.dx),i=C(e.height,n.y,n.dy);r===0||i===0||(t+=S({...e,width:r,height:i},i))}return t}function S(e,t){return(O(e)+1)*t}function C(e,t,n){return e<=t?0:Math.floor((e-t+n-1)/n)}function w(e,t,n){if(n.colorType===3)return T(e,t,n);if(n.bitDepth<8)return E(e,t,n);let r=n.bitDepth===16?2:1,a=t*i.get(n.colorType)*r,o=t=>n.bitDepth===16?e.readUInt16BE(a+t*2):e[a+t*r],s=e=>A(o(e),n.bitDepth);if(n.colorType===0){let e=s(0);return[e,e,e,j(o(0),n)?0:255]}if(n.colorType===2)return[s(0),s(1),s(2),M(o(0),o(1),o(2),n)?0:255];if(n.colorType===4){let e=s(0);return[e,e,e,s(1)]}return[s(0),s(1),s(2),s(3)]}function T(e,t,n){if(!n.palette)throw Error(`Indexed PNG is missing PLTE`);let r=D(e,t,n.bitDepth),i=r*3;if(i+2>=n.palette.length)throw Error(`Indexed PNG palette is invalid`);return[n.palette[i],n.palette[i+1],n.palette[i+2],n.transparency?.[r]??255]}function E(e,t,n){let r=D(e,t,n.bitDepth),i=(1<<n.bitDepth)-1,a=Math.round(r/i*255);return[a,a,a,n.transparency&&n.transparency.length>=2&&r===n.transparency.readUInt16BE(0)?0:255]}function D(e,t,n){let r=t*n;return e[Math.floor(r/8)]>>8-n-r%8&(1<<n)-1}function O(e){let t=i.get(e.colorType);return Math.ceil(e.width*t*e.bitDepth/8)}function k(e){let t=i.get(e.colorType);return Math.max(1,Math.ceil(t*e.bitDepth/8))}function A(e,t){return t===16?Math.round(e/65535*255):e}function j(e,t){return!t.transparency||t.transparency.length<2?!1:e===t.transparency.readUInt16BE(0)}function M(e,t,n,r){return!r.transparency||r.transparency.length<6?!1:e===r.transparency.readUInt16BE(0)&&t===r.transparency.readUInt16BE(2)&&n===r.transparency.readUInt16BE(4)}function N(e,t){let n=Buffer.from(e,`ascii`),r=Buffer.alloc(8+t.length+4);return r.writeUInt32BE(t.length,0),n.copy(r,4),t.copy(r,8),r.writeUInt32BE(P(Buffer.concat([n,t])),8+t.length),r}function P(e){let t=4294967295;for(let n of e){t^=n;for(let e=0;e<8;e+=1)t=t&1?3988292384^t>>>1:t>>>1}return(t^4294967295)>>>0}function F(e,t,n){let r=e+t-n,i=Math.abs(r-e),a=Math.abs(r-t),o=Math.abs(r-n);return i<=a&&i<=o?e:a<=o?t:n}function I(e,t){if(!Number.isInteger(e)||e<1)throw Error(`PNG ${t} must be positive`);return e}function L(e){return e instanceof Error&&`code`in e&&e.code===`ERR_BUFFER_TOO_LARGE`}function R(t,n){try{return s.sync.read(t)}catch(t){throw new e(`COMMAND_FAILED`,`Failed to decode ${n} as PNG`,{label:n,reason:t instanceof Error?t.message:String(t)})}}const z=.78,B={r:220,g:0,b:0};function V(e){let{baselineData:t,currentData:n,maxColorDistance:r}=e,i=e.width*e.height,a=Buffer.alloc(i*4),o=new Uint8Array(i),s=0;for(let e=0,i=0;e<t.length;e+=4,i+=1){let c=t[e]-n[e],l=t[e+1]-n[e+1],u=t[e+2]-n[e+2];if(Math.sqrt(c**2+l**2+u**2)>r){s+=1,o[i]=1;let t=H(n,e);a[e]=U(t,B.r,z),a[e+1]=U(t,B.g,z),a[e+2]=U(t,B.b,z),a[e+3]=255;continue}let d=H(n,e);a[e]=d,a[e+1]=d,a[e+2]=d,a[e+3]=255}return{diffData:a,diffMask:o,differentPixels:s}}function H(e,t){return U(Math.round(e[t]*.299+e[t+1]*.587+e[t+2]*.114),255,.72)}function U(e,t,n){return Math.round(e*(1-n)+t*n)}function W(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}export{s as i,V as n,R as r,W as t};
@@ -1,4 +1,4 @@
1
- import{F as e,b as t,l as n}from"./sdk-contracts.js";import{Nt as r,Pt as i,bn as a,d as o}from"./tv-remote.js";import{a as s,f as c,i as ee,l,m as u,p as d,u as f}from"./providers.js";import p from"node:fs";import{parseAllDocuments as m,stringify as h}from"yaml";const g=/^[A-Z_][A-Z0-9_]*$/,_=/(\\\$\{)|\$\{([A-Za-z_][A-Za-z0-9_.]*)(?::-((?:[^}\\]|\\.)*))?\}/g;function v(e){return e.startsWith(`AD_`)}function y(t){return new e(`INVALID_ARGS`,`The AD_* namespace is reserved for built-in variables. Rename ${t} to avoid the AD_ prefix.`)}function te(e){let t={};if(e.builtins)for(let[n,r]of Object.entries(e.builtins))t[n]=r;let n=[e.fileEnv,e.shellEnv,e.cliEnv];for(let e of n)if(e)for(let[n,r]of Object.entries(e)){if(v(n))throw y(n);t[n]=r}return{values:t}}function ne(e,t){Object.assign(e.values,t)}function b(e){let t={};for(let[n,r]of Object.entries(e)){if(typeof r!=`string`||!n.startsWith(`AD_VAR_`))continue;let e=n.slice(7);e.length!==0&&g.test(e)&&(v(e)||(t[e]=r))}return t}function x(t){let n={};for(let r of t){let t=r.indexOf(`=`);if(t<=0)throw new e(`INVALID_ARGS`,`Invalid -e entry "${r}": expected KEY=VALUE.`);let i=r.slice(0,t);if(!g.test(i))throw new e(`INVALID_ARGS`,`Invalid -e key "${i}": keys must be uppercase letters, digits, and underscores (e.g. APP_ID).`);if(v(i))throw y(i);n[i]=r.slice(t+1)}return n}function S(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function C(e){if(e&&typeof e==`object`&&!Array.isArray(e)){let t={};for(let[n,r]of Object.entries(e))typeof r==`string`&&(t[n]=r);return t}return process.env}function w(t,n,r){return t.replace(_,(t,i,a,o)=>{if(i)return"${";if(!a)return t;if(Object.prototype.hasOwnProperty.call(n.values,a))return String(n.values[a]);if(o!==void 0)return o.replace(/\\(.)/g,`$1`);throw new e(`INVALID_ARGS`,`Unresolved variable \${${a}} at ${r.file}:${r.line}.`)})}function T(e,t,n){return{...e,positionals:(e.positionals??[]).map(e=>w(e,t,n)),flags:D(e.flags,t,n)??{},runtime:D(e.runtime,t,n),replayControl:E(e.replayControl,t,n)}}function E(e,t,n){if(!e)return e;switch(e.kind){case`maestroRunFlowWhen`:return{...e,selector:w(e.selector,t,n)};case`retry`:return e}return e}function D(e,t,n){return e&&O(e,t,n)}function O(e,t,n){return typeof e==`string`?w(e,t,n):Array.isArray(e)?e.map(e=>O(e,t,n)):e&&typeof e==`object`?Object.fromEntries(Object.entries(e).map(([e,r])=>[e,O(r,t,n)])):e}const k=new Set(n.filter(e=>e!==`web`)),A=new Set([`mobile`,`tv`,`desktop`]);function j(t){let n=[],r=[],i=t.split(/\r?\n/),a=!1;for(let[t,o]of i.entries()){let i=o.trim();if(i.length===0||i.startsWith(`#`))continue;if(N(i)){if(a)throw new e(`INVALID_ARGS`,`env directives must precede all actions (line ${t+1}).`);continue}let s=R(o);s&&(n.push(s),r.push(t+1),a=!0)}return{actions:n,actionLines:r}}function M(e){let t=e.split(/\r?\n/),n={};for(let[e,r]of t.entries()){let t=r.trim();if(t.length===0||t.startsWith(`#`))continue;if(N(t)){I(n,t,e+1);continue}if(!t.startsWith(`context `))break;let i=t.match(/(?:^|\s)platform=([^\s]+)/);if(i){let e=i[1];e&&k.has(e)&&L(n,`platform`,e)}let a=t.match(/(?:^|\s)target=([^\s]+)/);if(a){let e=a[1];e&&A.has(e)&&L(n,`target`,e)}let o=t.match(/(?:^|\s)timeout=(\d+)/);if(o){let e=Number(o[1]);Number.isFinite(e)&&e>=1&&L(n,`timeoutMs`,Math.floor(e))}let s=t.match(/(?:^|\s)retries=(\d+)/);if(s){let e=Number(s[1]);Number.isFinite(e)&&e>=0&&L(n,`retries`,Math.floor(e))}}return n}function N(e){return e===`env`||e.startsWith(`env `)||e.startsWith(`env `)}function P(t,n){let r=t.slice(3).replace(/^[\s]+/,``),i=r.indexOf(`=`);if(i<=0)throw new e(`INVALID_ARGS`,`Invalid env directive on line ${n}: expected "env KEY=VALUE".`);let a=r.slice(0,i);if(!g.test(a))throw new e(`INVALID_ARGS`,`Invalid env key "${a}" on line ${n}: keys must be uppercase letters, digits, and underscores (e.g. APP_ID).`);if(a.startsWith(`AD_`))throw new e(`INVALID_ARGS`,`Invalid env key "${a}" on line ${n}: the AD_* namespace is reserved for built-in variables. Rename ${a} to avoid the AD_ prefix.`);return{key:a,value:F(r.slice(i+1),n)}}function F(t,n){if(t.length===0)return``;if(t.startsWith(`"`))try{let e=JSON.parse(t);if(typeof e!=`string`)throw Error(`not a string literal`);return e}catch{throw new e(`INVALID_ARGS`,`Invalid quoted env value on line ${n}.`)}return t}function I(t,n,r){let{key:i,value:a}=P(n,r),o=t.env??{};if(Object.prototype.hasOwnProperty.call(o,i))throw new e(`INVALID_ARGS`,`Duplicate env directive "${i}" on line ${r}.`);o[i]=a,t.env=o}function L(t,n,r){let i=t[n];if(i!==void 0)throw new e(`INVALID_ARGS`,i===r?`Duplicate replay test metadata "${n}" in context header.`:`Conflicting replay test metadata "${n}" in context header: ${String(i)} vs ${String(r)}.`);t[n]=r}function R(e){let t=e.trim();if(t.length===0||t.startsWith(`#`))return null;let[n,...r]=V(t);if(n===void 0||n===`context`)return null;let i={ts:Date.now(),command:n,positionals:[],flags:{}};if(n===`snapshot`){i.positionals=[];for(let e=0;e<r.length;e+=1){let t=r[e];if(t===`-i`){i.flags.snapshotInteractiveOnly=!0;continue}if(t!==`-c`){if(t===`--raw`){i.flags.snapshotRaw=!0;continue}if(t===`--force-full`){i.flags.snapshotForceFull=!0;continue}if((t===`-d`||t===`--depth`)&&e+1<r.length){let t=Number(r[e+1]);Number.isFinite(t)&&t>=0&&(i.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if((t===`-s`||t===`--scope`)&&e+1<r.length){i.flags.snapshotScope=r[e+1],e+=1;continue}if(t===`--backend`&&e+1<r.length){e+=1;continue}}}return i}if(n===`open`){let e=s(r);return i.positionals=e.positionals,Object.assign(i.flags,e.flags),i.runtime=e.runtime,i}if(n===`runtime`){let e=c(r);return i.positionals=e.positionals,Object.assign(i.flags,e.flags),i}if(f(n)){let e=d(n,r);Object.assign(i.flags,e.flags);let t=e.positionals[0];if(t===void 0)return i;if(t.startsWith(`@`))return i.positionals=[u(t)],e.positionals[1]&&(i.result={refLabel:e.positionals[1]}),i;let a=e.positionals[0],o=e.positionals[1];return B(a)&&B(o)&&e.positionals.length>=2?(i.positionals=[a,o],i):(i.positionals=[e.positionals.join(` `)],i)}if(n===`fill`){let e=d(n,r);if(Object.assign(i.flags,e.flags),!z(e.positionals))return i.positionals=e.positionals,i;let[t,a,...o]=e.positionals;if(t.startsWith(`@`)){let e=u(t);return o.length>0?(i.positionals=[e,o.join(` `)],i.result={refLabel:a},i):(i.positionals=[e,a],i)}return i.positionals=[t,[a,...o].join(` `)],i}if(n===`get`){let e=r[0],t=r[1];return e===void 0||t===void 0?(i.positionals=r,i):t.startsWith(`@`)?(i.positionals=[e,u(t)],r[2]&&(i.result={refLabel:r[2]}),i):(i.positionals=[e,r.slice(1).join(` `)],i)}if(n===`swipe`||n===`type`){let e=d(n,r);return Object.assign(i.flags,e.flags),i.positionals=e.positionals,i}if(n===`record`){let e=[];for(let t=0;t<r.length;t+=1){let n=r[t];if(n===`--hide-touches`){i.flags.hideTouches=!0;continue}if(n===`--fps`&&t+1<r.length){let e=Number(r[t+1]);Number.isFinite(e)&&(i.flags.fps=Math.floor(e)),t+=1;continue}if(n===`--quality`&&t+1<r.length){let e=r[t+1],n=o(e);n!==void 0&&(i.flags.quality=n),t+=1;continue}if(n===`--max-size`&&t+1<r.length){let e=Number(r[t+1]);Number.isFinite(e)&&(i.flags.screenshotMaxSize=Math.floor(e)),t+=1;continue}e.push(n)}return i.positionals=e,i}if(n===`screenshot`){let e=[];for(let t=0;t<r.length;t+=1){let n=r[t],o=a({args:r,index:t,flags:i.flags});if(o.handled){t=o.nextIndex;continue}e.push(n)}return i.positionals=e,i}return i.positionals=n===`wait`||n===`longpress`?r.map(e=>u(e)):r,i}function z(e){return e.length>=2}function B(e){return e?!Number.isNaN(Number(e)):!1}function V(e){let t=[],n=0;for(;n<e.length&&(n=H(e,n),!(n>=e.length));){let r=e[n]===`"`?U(e,n):W(e,n);t.push(r.value),n=r.nextCursor}return t}function H(e,t){let n=t;for(;n<e.length&&/\s/.test(e.charAt(n));)n+=1;return n}function U(t,n){let r=n+1,i=!1,a=r;for(;a<t.length;a+=1){let e=t.charAt(a);if(e===`"`&&!i)break;if(i){i=!1;continue}i=e===`\\`}if(a>=t.length)throw new e(`INVALID_ARGS`,`Invalid replay script line: ${t}`);return{value:JSON.parse(t.slice(n,a+1)),nextCursor:a+1}}function W(e,t){let n=t;for(;n<e.length&&!/\s/.test(e.charAt(n));)n+=1;return{value:e.slice(t,n),nextCursor:n}}function G(e,n,r){let i=[];if(r){let e=r.device.kind?` kind=${r.device.kind}`:``,n=r.device.target?` target=${r.device.target}`:``;i.push(`context platform=${t(r.device)}${n} device=${l(r.device.name)}${e} theme=unknown`)}for(let e of n)i.push(K(e));let a=`${i.join(`
2
- `)}\n`,o=`${e}.tmp-${process.pid}-${Date.now()}`;p.writeFileSync(o,a),p.renameSync(o,e)}function K(e){return ee(e,{runtimeIncludeAllPositionals:!0})}function q(t){let n=m(t);for(let t of n)if(t.errors.length>0)throw new e(`INVALID_ARGS`,`Invalid Maestro YAML flow: ${t.errors[0]?.message??`Invalid Maestro YAML flow.`}`);return n.map(e=>e.toJSON()).filter(e=>e!==null)}function J(e){return`${e.map(e=>h(e).trimEnd()).join(`
1
+ import{_ as e}from"./sdk-contracts.js";import{Mt as t,d as n,jt as r,vn as i}from"./tv-remote.js";import{m as a,r as o}from"./sdk-device.js";import{a as s,f as c,i as ee,l,m as u,p as d,u as f}from"./providers.js";import p from"node:fs";import{parseAllDocuments as m,stringify as h}from"yaml";const g=/^[A-Z_][A-Z0-9_]*$/,_=/(\\\$\{)|\$\{([A-Za-z_][A-Za-z0-9_.]*)(?::-((?:[^}\\]|\\.)*))?\}/g;function v(e){return e.startsWith(`AD_`)}function y(t){return new e(`INVALID_ARGS`,`The AD_* namespace is reserved for built-in variables. Rename ${t} to avoid the AD_ prefix.`)}function te(e){let t={};if(e.builtins)for(let[n,r]of Object.entries(e.builtins))t[n]=r;let n=[e.fileEnv,e.shellEnv,e.cliEnv];for(let e of n)if(e)for(let[n,r]of Object.entries(e)){if(v(n))throw y(n);t[n]=r}return{values:t}}function ne(e,t){Object.assign(e.values,t)}function b(e){let t={};for(let[n,r]of Object.entries(e)){if(typeof r!=`string`||!n.startsWith(`AD_VAR_`))continue;let e=n.slice(7);e.length!==0&&g.test(e)&&(v(e)||(t[e]=r))}return t}function x(t){let n={};for(let r of t){let t=r.indexOf(`=`);if(t<=0)throw new e(`INVALID_ARGS`,`Invalid -e entry "${r}": expected KEY=VALUE.`);let i=r.slice(0,t);if(!g.test(i))throw new e(`INVALID_ARGS`,`Invalid -e key "${i}": keys must be uppercase letters, digits, and underscores (e.g. APP_ID).`);if(v(i))throw y(i);n[i]=r.slice(t+1)}return n}function S(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function C(e){if(e&&typeof e==`object`&&!Array.isArray(e)){let t={};for(let[n,r]of Object.entries(e))typeof r==`string`&&(t[n]=r);return t}return process.env}function w(t,n,r){return t.replace(_,(t,i,a,o)=>{if(i)return"${";if(!a)return t;if(Object.prototype.hasOwnProperty.call(n.values,a))return String(n.values[a]);if(o!==void 0)return o.replace(/\\(.)/g,`$1`);throw new e(`INVALID_ARGS`,`Unresolved variable \${${a}} at ${r.file}:${r.line}.`)})}function T(e,t,n){return{...e,positionals:(e.positionals??[]).map(e=>w(e,t,n)),flags:D(e.flags,t,n)??{},runtime:D(e.runtime,t,n),replayControl:E(e.replayControl,t,n)}}function E(e,t,n){if(!e)return e;switch(e.kind){case`maestroRunFlowWhen`:return{...e,selector:w(e.selector,t,n)};case`retry`:return e}return e}function D(e,t,n){return e&&O(e,t,n)}function O(e,t,n){return typeof e==`string`?w(e,t,n):Array.isArray(e)?e.map(e=>O(e,t,n)):e&&typeof e==`object`?Object.fromEntries(Object.entries(e).map(([e,r])=>[e,O(r,t,n)])):e}const k=new Set(o.filter(e=>e!==`web`)),A=new Set([`mobile`,`tv`,`desktop`]);function j(t){let n=[],r=[],i=t.split(/\r?\n/),a=!1;for(let[t,o]of i.entries()){let i=o.trim();if(i.length===0||i.startsWith(`#`))continue;if(N(i)){if(a)throw new e(`INVALID_ARGS`,`env directives must precede all actions (line ${t+1}).`);continue}let s=R(o);s&&(n.push(s),r.push(t+1),a=!0)}return{actions:n,actionLines:r}}function M(e){let t=e.split(/\r?\n/),n={};for(let[e,r]of t.entries()){let t=r.trim();if(t.length===0||t.startsWith(`#`))continue;if(N(t)){I(n,t,e+1);continue}if(!t.startsWith(`context `))break;let i=t.match(/(?:^|\s)platform=([^\s]+)/);if(i){let e=i[1];e&&k.has(e)&&L(n,`platform`,e)}let a=t.match(/(?:^|\s)target=([^\s]+)/);if(a){let e=a[1];e&&A.has(e)&&L(n,`target`,e)}let o=t.match(/(?:^|\s)timeout=(\d+)/);if(o){let e=Number(o[1]);Number.isFinite(e)&&e>=1&&L(n,`timeoutMs`,Math.floor(e))}let s=t.match(/(?:^|\s)retries=(\d+)/);if(s){let e=Number(s[1]);Number.isFinite(e)&&e>=0&&L(n,`retries`,Math.floor(e))}}return n}function N(e){return e===`env`||e.startsWith(`env `)||e.startsWith(`env `)}function P(t,n){let r=t.slice(3).replace(/^[\s]+/,``),i=r.indexOf(`=`);if(i<=0)throw new e(`INVALID_ARGS`,`Invalid env directive on line ${n}: expected "env KEY=VALUE".`);let a=r.slice(0,i);if(!g.test(a))throw new e(`INVALID_ARGS`,`Invalid env key "${a}" on line ${n}: keys must be uppercase letters, digits, and underscores (e.g. APP_ID).`);if(a.startsWith(`AD_`))throw new e(`INVALID_ARGS`,`Invalid env key "${a}" on line ${n}: the AD_* namespace is reserved for built-in variables. Rename ${a} to avoid the AD_ prefix.`);return{key:a,value:F(r.slice(i+1),n)}}function F(t,n){if(t.length===0)return``;if(t.startsWith(`"`))try{let e=JSON.parse(t);if(typeof e!=`string`)throw Error(`not a string literal`);return e}catch{throw new e(`INVALID_ARGS`,`Invalid quoted env value on line ${n}.`)}return t}function I(t,n,r){let{key:i,value:a}=P(n,r),o=t.env??{};if(Object.prototype.hasOwnProperty.call(o,i))throw new e(`INVALID_ARGS`,`Duplicate env directive "${i}" on line ${r}.`);o[i]=a,t.env=o}function L(t,n,r){let i=t[n];if(i!==void 0)throw new e(`INVALID_ARGS`,i===r?`Duplicate replay test metadata "${n}" in context header.`:`Conflicting replay test metadata "${n}" in context header: ${String(i)} vs ${String(r)}.`);t[n]=r}function R(e){let t=e.trim();if(t.length===0||t.startsWith(`#`))return null;let[r,...a]=V(t);if(r===void 0||r===`context`)return null;let o={ts:Date.now(),command:r,positionals:[],flags:{}};if(r===`snapshot`){o.positionals=[];for(let e=0;e<a.length;e+=1){let t=a[e];if(t===`-i`){o.flags.snapshotInteractiveOnly=!0;continue}if(t!==`-c`){if(t===`--raw`){o.flags.snapshotRaw=!0;continue}if(t===`--force-full`){o.flags.snapshotForceFull=!0;continue}if((t===`-d`||t===`--depth`)&&e+1<a.length){let t=Number(a[e+1]);Number.isFinite(t)&&t>=0&&(o.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if((t===`-s`||t===`--scope`)&&e+1<a.length){o.flags.snapshotScope=a[e+1],e+=1;continue}if(t===`--backend`&&e+1<a.length){e+=1;continue}}}return o}if(r===`open`){let e=s(a);return o.positionals=e.positionals,Object.assign(o.flags,e.flags),o.runtime=e.runtime,o}if(r===`runtime`){let e=c(a);return o.positionals=e.positionals,Object.assign(o.flags,e.flags),o}if(f(r)){let e=d(r,a);Object.assign(o.flags,e.flags);let t=e.positionals[0];if(t===void 0)return o;if(t.startsWith(`@`))return o.positionals=[u(t)],e.positionals[1]&&(o.result={refLabel:e.positionals[1]}),o;let n=e.positionals[0],i=e.positionals[1];return B(n)&&B(i)&&e.positionals.length>=2?(o.positionals=[n,i],o):(o.positionals=[e.positionals.join(` `)],o)}if(r===`fill`){let e=d(r,a);if(Object.assign(o.flags,e.flags),!z(e.positionals))return o.positionals=e.positionals,o;let[t,n,...i]=e.positionals;if(t.startsWith(`@`)){let e=u(t);return i.length>0?(o.positionals=[e,i.join(` `)],o.result={refLabel:n},o):(o.positionals=[e,n],o)}return o.positionals=[t,[n,...i].join(` `)],o}if(r===`get`){let e=a[0],t=a[1];return e===void 0||t===void 0?(o.positionals=a,o):t.startsWith(`@`)?(o.positionals=[e,u(t)],a[2]&&(o.result={refLabel:a[2]}),o):(o.positionals=[e,a.slice(1).join(` `)],o)}if(r===`swipe`||r===`type`){let e=d(r,a);return Object.assign(o.flags,e.flags),o.positionals=e.positionals,o}if(r===`record`){let e=[];for(let t=0;t<a.length;t+=1){let r=a[t];if(r===`--hide-touches`){o.flags.hideTouches=!0;continue}if(r===`--fps`&&t+1<a.length){let e=Number(a[t+1]);Number.isFinite(e)&&(o.flags.fps=Math.floor(e)),t+=1;continue}if(r===`--quality`&&t+1<a.length){let e=a[t+1],r=n(e);r!==void 0&&(o.flags.quality=r),t+=1;continue}if(r===`--max-size`&&t+1<a.length){let e=Number(a[t+1]);Number.isFinite(e)&&(o.flags.screenshotMaxSize=Math.floor(e)),t+=1;continue}e.push(r)}return o.positionals=e,o}if(r===`screenshot`){let e=[];for(let t=0;t<a.length;t+=1){let n=a[t],r=i({args:a,index:t,flags:o.flags});if(r.handled){t=r.nextIndex;continue}e.push(n)}return o.positionals=e,o}return o.positionals=r===`wait`||r===`longpress`?a.map(e=>u(e)):a,o}function z(e){return e.length>=2}function B(e){return e?!Number.isNaN(Number(e)):!1}function V(e){let t=[],n=0;for(;n<e.length&&(n=H(e,n),!(n>=e.length));){let r=e[n]===`"`?U(e,n):W(e,n);t.push(r.value),n=r.nextCursor}return t}function H(e,t){let n=t;for(;n<e.length&&/\s/.test(e.charAt(n));)n+=1;return n}function U(t,n){let r=n+1,i=!1,a=r;for(;a<t.length;a+=1){let e=t.charAt(a);if(e===`"`&&!i)break;if(i){i=!1;continue}i=e===`\\`}if(a>=t.length)throw new e(`INVALID_ARGS`,`Invalid replay script line: ${t}`);return{value:JSON.parse(t.slice(n,a+1)),nextCursor:a+1}}function W(e,t){let n=t;for(;n<e.length&&!/\s/.test(e.charAt(n));)n+=1;return{value:e.slice(t,n),nextCursor:n}}function G(e,t,n){let r=[];if(n){let e=n.device.kind?` kind=${n.device.kind}`:``,t=n.device.target?` target=${n.device.target}`:``;r.push(`context platform=${a(n.device)}${t} device=${l(n.device.name)}${e} theme=unknown`)}for(let e of t)r.push(K(e));let i=`${r.join(`
2
+ `)}\n`,o=`${e}.tmp-${process.pid}-${Date.now()}`;p.writeFileSync(o,i),p.renameSync(o,e)}function K(e){return ee(e,{runtimeIncludeAllPositionals:!0})}function q(t){let n=m(t);for(let t of n)if(t.errors.length>0)throw new e(`INVALID_ARGS`,`Invalid Maestro YAML flow: ${t.errors[0]?.message??`Invalid Maestro YAML flow.`}`);return n.map(e=>e.toJSON()).filter(e=>e!==null)}function J(e){return`${e.map(e=>h(e).trimEnd()).join(`
3
3
  ---
4
- `)}\n`}function Y(e,t=[],n){return{ts:Date.now(),command:e,positionals:t,flags:n??{}}}function X(e,t,n){let r=new Set(n),i=Object.keys(e).filter(e=>!r.has(e));if(i.length>0)throw $(`Maestro ${t} field "${i[0]}" is not supported yet.`)}function Z(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function re(t){return t.map((t,n)=>{if(typeof t==`string`||Z(t))return t;throw new e(`INVALID_ARGS`,`Unsupported Maestro command at index ${n+1}: expected a scalar or one-key map.`)})}function ie(e){if(e)return ue(e)}function ae(t,n){if(t==null)return{};if(!Z(t))throw new e(`INVALID_ARGS`,`${n} expects a map.`);let r={};for(let[e,n]of Object.entries(t))(typeof n==`string`||typeof n==`number`||typeof n==`boolean`)&&(r[e]=String(n));return r}function oe(e,t){return Z(e)&&typeof e.timeout==`number`&&Number.isFinite(e.timeout)?Math.max(0,Math.floor(e.timeout)):t}function se(t,n){if(t.appId)return t.appId;throw new e(`INVALID_ARGS`,`${n} requires appId in the Maestro flow config.`)}function Q(t,n){if(typeof n==`string`)return n;throw new e(`INVALID_ARGS`,`${t} expects a string value.`)}function ce(e,t){return e.replace(/\$\{([A-Za-z_][A-Za-z0-9_.]*)\}/g,(e,n)=>Object.prototype.hasOwnProperty.call(t.env,n)?String(t.env[n]):e)}function le(e){throw $(`Maestro command "${e}" is not supported yet.`)}function $(t){throw new e(`INVALID_ARGS`,`${t} See supported/unsupported Maestro compatibility at ${r}. If this syntax matters for your flows, comment there or open a focused issue at ${i}.`)}function ue(e){let t=e.trim().toLowerCase();if(t===`android`)return`android`;if(t===`ios`)return`ios`}function de(e,t){return`${e},${t}`}function fe(e){let t=e.match(/^(\d+),(\d+)$/);if(!t)throw $(`Only absolute Maestro point selectors like "100,200" are supported.`);return{x:Number(t[1]),y:Number(t[2])}}function pe(e){let t=e.match(/^\s*(\d+)\s*,\s*(\d+)\s*$/);if(t)return{kind:`absolute`,x:Number(t[1]),y:Number(t[2])};let n=e.match(/^\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*$/);if(n)return{kind:`percent`,x:Number(n[1]),y:Number(n[2])};throw $(`Only Maestro swipe coordinates like "100,200" or "50%,75%" are supported.`)}export{ne as C,T as D,C as E,b as S,S as T,J as _,X as a,G as b,ie as c,se as d,Q as f,q as g,$ as h,Y as i,ae as l,le as m,fe as n,Z as o,ce as p,pe as r,re as s,de as t,oe as u,j as v,x as w,te as x,M as y};
4
+ `)}\n`}function Y(e,t=[],n){return{ts:Date.now(),command:e,positionals:t,flags:n??{}}}function X(e,t,n){let r=new Set(n),i=Object.keys(e).filter(e=>!r.has(e));if(i.length>0)throw $(`Maestro ${t} field "${i[0]}" is not supported yet.`)}function Z(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function re(t){return t.map((t,n)=>{if(typeof t==`string`||Z(t))return t;throw new e(`INVALID_ARGS`,`Unsupported Maestro command at index ${n+1}: expected a scalar or one-key map.`)})}function ie(e){if(e)return ue(e)}function ae(t,n){if(t==null)return{};if(!Z(t))throw new e(`INVALID_ARGS`,`${n} expects a map.`);let r={};for(let[e,n]of Object.entries(t))(typeof n==`string`||typeof n==`number`||typeof n==`boolean`)&&(r[e]=String(n));return r}function oe(e,t){return Z(e)&&typeof e.timeout==`number`&&Number.isFinite(e.timeout)?Math.max(0,Math.floor(e.timeout)):t}function se(t,n){if(t.appId)return t.appId;throw new e(`INVALID_ARGS`,`${n} requires appId in the Maestro flow config.`)}function Q(t,n){if(typeof n==`string`)return n;throw new e(`INVALID_ARGS`,`${t} expects a string value.`)}function ce(e,t){return e.replace(/\$\{([A-Za-z_][A-Za-z0-9_.]*)\}/g,(e,n)=>Object.prototype.hasOwnProperty.call(t.env,n)?String(t.env[n]):e)}function le(e){throw $(`Maestro command "${e}" is not supported yet.`)}function $(n){throw new e(`INVALID_ARGS`,`${n} See supported/unsupported Maestro compatibility at ${r}. If this syntax matters for your flows, comment there or open a focused issue at ${t}.`)}function ue(e){let t=e.trim().toLowerCase();if(t===`android`)return`android`;if(t===`ios`)return`ios`}function de(e,t){return`${e},${t}`}function fe(e){let t=e.match(/^(\d+),(\d+)$/);if(!t)throw $(`Only absolute Maestro point selectors like "100,200" are supported.`);return{x:Number(t[1]),y:Number(t[2])}}function pe(e){let t=e.match(/^\s*(\d+)\s*,\s*(\d+)\s*$/);if(t)return{kind:`absolute`,x:Number(t[1]),y:Number(t[2])};let n=e.match(/^\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*$/);if(n)return{kind:`percent`,x:Number(n[1]),y:Number(n[2])};throw $(`Only Maestro swipe coordinates like "100,200" or "50%,75%" are supported.`)}export{ne as C,T as D,C as E,b as S,S as T,J as _,X as a,G as b,ie as c,se as d,Q as f,q as g,$ as h,Y as i,ae as l,le as m,fe as n,Z as o,ce as p,pe as r,re as s,de as t,oe as u,j as v,x as w,te as x,M as y};
@@ -1 +1 @@
1
- import{N as e}from"./sdk-contracts.js";import{yn as t}from"./tv-remote.js";import n from"node:crypto";function r(t){return t.startsWith(`@`)?e(t)?.base??t:t}const i=/^-?\d+(\.\d+)?$/,a=/^[^\s"\\]+$/,o=new Map([[`--count`,`count`],[`--interval-ms`,`intervalMs`],[`--hold-ms`,`holdMs`],[`--jitter-px`,`jitterPx`]]),s=new Map([[`--count`,`count`],[`--pause-ms`,`pauseMs`]]),c=new Map([[`--delay-ms`,`delayMs`]]);function l(e){return e===`click`||e===`press`}function u(e){return l(e)||e===`longpress`}function d(e){return e===`type`||e===`fill`}function f(e){return h(e,g)}function p(e){return JSON.stringify(e)}function m(e){return h(e,_)}function h(e,t){return t(e)?e:p(e)}function g(e){return _(e)&&e.startsWith(`@`)||i.test(e)}function _(e){return a.test(e)}function v(e){let t=(e.positionals??[]).map(e=>f(e));return[e.command,...t].join(` `)}function y(e,t){let n=t.flags??{};if(l(t.command)){typeof n.count==`number`&&e.push(`--count`,String(n.count)),typeof n.intervalMs==`number`&&e.push(`--interval-ms`,String(n.intervalMs)),typeof n.holdMs==`number`&&e.push(`--hold-ms`,String(n.holdMs)),typeof n.jitterPx==`number`&&e.push(`--jitter-px`,String(n.jitterPx)),n.doubleTap===!0&&e.push(`--double-tap`);let t=n.clickButton;t&&t!==`primary`&&e.push(`--button`,t);return}if(t.command===`swipe`){typeof n.count==`number`&&e.push(`--count`,String(n.count)),typeof n.pauseMs==`number`&&e.push(`--pause-ms`,String(n.pauseMs)),(n.pattern===`one-way`||n.pattern===`ping-pong`)&&e.push(`--pattern`,n.pattern);return}d(t.command)&&typeof n.delayMs==`number`&&e.push(`--delay-ms`,String(n.delayMs))}function b(e,t){t&&((t.platform===`ios`||t.platform===`android`)&&e.push(`--platform`,t.platform),typeof t.metroHost==`string`&&t.metroHost.length>0&&e.push(`--metro-host`,m(t.metroHost)),typeof t.metroPort==`number`&&e.push(`--metro-port`,String(t.metroPort)),typeof t.bundleUrl==`string`&&t.bundleUrl.length>0&&e.push(`--bundle-url`,m(t.bundleUrl)),typeof t.launchUrl==`string`&&t.launchUrl.length>0&&e.push(`--launch-url`,m(t.launchUrl)))}function x(e,t){let[n,...r]=t.positionals??[];n&&e.push(m(n));for(let t of r)e.push(f(t));typeof t.flags?.fps==`number`&&e.push(`--fps`,String(t.flags.fps)),typeof t.flags?.screenshotMaxSize==`number`&&e.push(`--max-size`,String(t.flags.screenshotMaxSize)),(typeof t.flags?.quality==`number`||typeof t.flags?.quality==`string`)&&e.push(`--quality`,String(t.flags.quality)),t.flags?.hideTouches&&e.push(`--hide-touches`)}function S(e,t){t.flags?.snapshotInteractiveOnly&&e.push(`-i`),typeof t.flags?.snapshotDepth==`number`&&e.push(`-d`,String(t.flags.snapshotDepth)),t.flags?.snapshotScope&&e.push(`-s`,f(t.flags.snapshotScope)),t.flags?.snapshotRaw&&e.push(`--raw`)}function C(e,n){for(let t of n.positionals??[])e.push(f(t));t(e,n.flags)}function w(e,t,n={}){let r=t.positionals??[],i=n.includeAllPositionals?r:r.slice(0,1);for(let t of i)e.push(m(t));b(e,t.flags)}function T(e,t){for(let n of t.positionals??[])e.push(f(t.command===`wait`?r(n):n));y(e,t)}function E(e,t){let n=[],r={},i=l(e)?o:e===`swipe`?s:d(e)?c:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(l(e)&&o===`--double-tap`){r.doubleTap=!0;continue}let s=t[a+1];if(l(e)&&o===`--button`&&s!==void 0){let e=s;(e===`primary`||e===`secondary`||e===`middle`)&&(r.clickButton=e),a+=1;continue}let c=i?.get(o);if(c&&s!==void 0){let e=O(s);if(e!==null){r[c]=e,a+=1;continue}}if(e===`swipe`&&o===`--pattern`&&s!==void 0){let e=s;(e===`one-way`||e===`ping-pong`)&&(r.pattern=e),a+=1;continue}n.push(o)}return{positionals:n,flags:r}}function D(e){let t=[],n={};for(let r=0;r<e.length;r+=1){let i=e[r],a=e[r+1];if(i===`--platform`&&a!==void 0){let e=a;(e===`ios`||e===`android`)&&(n.platform=e),r+=1;continue}if(i===`--metro-host`&&a!==void 0){n.metroHost=a,r+=1;continue}if(i===`--metro-port`&&a!==void 0){let e=O(a);e!==null&&(n.metroPort=e),r+=1;continue}if(i===`--bundle-url`&&a!==void 0){n.bundleUrl=a,r+=1;continue}if(i===`--launch-url`&&a!==void 0){n.launchUrl=a,r+=1;continue}t.push(i)}return{positionals:t,flags:n}}function O(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}function k(e,t){for(let n of t.positionals??[])e.push(f(n));t.flags?.relaunch&&e.push(`--relaunch`),b(e,t.runtime)}function A(e){let t=[],n={};for(let r of e){if(r===`--relaunch`){n.relaunch=!0;continue}t.push(r)}let r=D(t);return{positionals:r.positionals,flags:n,runtime:j(r.flags)?r.flags:void 0}}function j(e){return!!(e.platform||e.metroHost||e.metroPort!==void 0||e.bundleUrl||e.launchUrl)}function M(e,t={}){let n=[e.command];return e.command===`snapshot`?S(n,e):e.command===`open`?k(n,e):e.command===`runtime`?w(n,e,{includeAllPositionals:t.runtimeIncludeAllPositionals}):e.command===`record`?x(n,e):e.command===`screenshot`?C(n,e):T(n,e),n.join(` `)}function N(e,t){let r=n.createHash(`sha256`).update(e).digest(),i=n.createHash(`sha256`).update(t).digest();return n.timingSafeEqual(r,i)}const P={browserStack:`browserstack`,awsDeviceFarm:`aws-device-farm`},F=new Set(Object.values(P));function I(e){return e!==void 0&&F.has(e)}export{A as a,f as c,u as d,D as f,M as i,p as l,r as m,I as n,y as o,E as p,N as r,v as s,P as t,l as u};
1
+ import{h as e}from"./sdk-contracts.js";import{_n as t}from"./tv-remote.js";import n from"node:crypto";function r(t){return t.startsWith(`@`)?e(t)?.base??t:t}const i=/^-?\d+(\.\d+)?$/,a=/^[^\s"\\]+$/,o=new Map([[`--count`,`count`],[`--interval-ms`,`intervalMs`],[`--hold-ms`,`holdMs`],[`--jitter-px`,`jitterPx`]]),s=new Map([[`--count`,`count`],[`--pause-ms`,`pauseMs`]]),c=new Map([[`--delay-ms`,`delayMs`]]);function l(e){return e===`click`||e===`press`}function u(e){return l(e)||e===`longpress`}function d(e){return e===`type`||e===`fill`}function f(e){return h(e,g)}function p(e){return JSON.stringify(e)}function m(e){return h(e,_)}function h(e,t){return t(e)?e:p(e)}function g(e){return _(e)&&e.startsWith(`@`)||i.test(e)}function _(e){return a.test(e)}function v(e){let t=(e.positionals??[]).map(e=>f(e));return[e.command,...t].join(` `)}function y(e,t){let n=t.flags??{};if(l(t.command)){typeof n.count==`number`&&e.push(`--count`,String(n.count)),typeof n.intervalMs==`number`&&e.push(`--interval-ms`,String(n.intervalMs)),typeof n.holdMs==`number`&&e.push(`--hold-ms`,String(n.holdMs)),typeof n.jitterPx==`number`&&e.push(`--jitter-px`,String(n.jitterPx)),n.doubleTap===!0&&e.push(`--double-tap`);let t=n.clickButton;t&&t!==`primary`&&e.push(`--button`,t);return}if(t.command===`swipe`){typeof n.count==`number`&&e.push(`--count`,String(n.count)),typeof n.pauseMs==`number`&&e.push(`--pause-ms`,String(n.pauseMs)),(n.pattern===`one-way`||n.pattern===`ping-pong`)&&e.push(`--pattern`,n.pattern);return}d(t.command)&&typeof n.delayMs==`number`&&e.push(`--delay-ms`,String(n.delayMs))}function b(e,t){t&&((t.platform===`ios`||t.platform===`android`)&&e.push(`--platform`,t.platform),typeof t.metroHost==`string`&&t.metroHost.length>0&&e.push(`--metro-host`,m(t.metroHost)),typeof t.metroPort==`number`&&e.push(`--metro-port`,String(t.metroPort)),typeof t.bundleUrl==`string`&&t.bundleUrl.length>0&&e.push(`--bundle-url`,m(t.bundleUrl)),typeof t.launchUrl==`string`&&t.launchUrl.length>0&&e.push(`--launch-url`,m(t.launchUrl)))}function x(e,t){let[n,...r]=t.positionals??[];n&&e.push(m(n));for(let t of r)e.push(f(t));typeof t.flags?.fps==`number`&&e.push(`--fps`,String(t.flags.fps)),typeof t.flags?.screenshotMaxSize==`number`&&e.push(`--max-size`,String(t.flags.screenshotMaxSize)),(typeof t.flags?.quality==`number`||typeof t.flags?.quality==`string`)&&e.push(`--quality`,String(t.flags.quality)),t.flags?.hideTouches&&e.push(`--hide-touches`)}function S(e,t){t.flags?.snapshotInteractiveOnly&&e.push(`-i`),typeof t.flags?.snapshotDepth==`number`&&e.push(`-d`,String(t.flags.snapshotDepth)),t.flags?.snapshotScope&&e.push(`-s`,f(t.flags.snapshotScope)),t.flags?.snapshotRaw&&e.push(`--raw`)}function C(e,n){for(let t of n.positionals??[])e.push(f(t));t(e,n.flags)}function w(e,t,n={}){let r=t.positionals??[],i=n.includeAllPositionals?r:r.slice(0,1);for(let t of i)e.push(m(t));b(e,t.flags)}function T(e,t){for(let n of t.positionals??[])e.push(f(t.command===`wait`?r(n):n));y(e,t)}function E(e,t){let n=[],r={},i=l(e)?o:e===`swipe`?s:d(e)?c:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(l(e)&&o===`--double-tap`){r.doubleTap=!0;continue}let s=t[a+1];if(l(e)&&o===`--button`&&s!==void 0){let e=s;(e===`primary`||e===`secondary`||e===`middle`)&&(r.clickButton=e),a+=1;continue}let c=i?.get(o);if(c&&s!==void 0){let e=O(s);if(e!==null){r[c]=e,a+=1;continue}}if(e===`swipe`&&o===`--pattern`&&s!==void 0){let e=s;(e===`one-way`||e===`ping-pong`)&&(r.pattern=e),a+=1;continue}n.push(o)}return{positionals:n,flags:r}}function D(e){let t=[],n={};for(let r=0;r<e.length;r+=1){let i=e[r],a=e[r+1];if(i===`--platform`&&a!==void 0){let e=a;(e===`ios`||e===`android`)&&(n.platform=e),r+=1;continue}if(i===`--metro-host`&&a!==void 0){n.metroHost=a,r+=1;continue}if(i===`--metro-port`&&a!==void 0){let e=O(a);e!==null&&(n.metroPort=e),r+=1;continue}if(i===`--bundle-url`&&a!==void 0){n.bundleUrl=a,r+=1;continue}if(i===`--launch-url`&&a!==void 0){n.launchUrl=a,r+=1;continue}t.push(i)}return{positionals:t,flags:n}}function O(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}function k(e,t){for(let n of t.positionals??[])e.push(f(n));t.flags?.relaunch&&e.push(`--relaunch`),b(e,t.runtime)}function A(e){let t=[],n={};for(let r of e){if(r===`--relaunch`){n.relaunch=!0;continue}t.push(r)}let r=D(t);return{positionals:r.positionals,flags:n,runtime:j(r.flags)?r.flags:void 0}}function j(e){return!!(e.platform||e.metroHost||e.metroPort!==void 0||e.bundleUrl||e.launchUrl)}function M(e,t={}){let n=[e.command];return e.command===`snapshot`?S(n,e):e.command===`open`?k(n,e):e.command===`runtime`?w(n,e,{includeAllPositionals:t.runtimeIncludeAllPositionals}):e.command===`record`?x(n,e):e.command===`screenshot`?C(n,e):T(n,e),n.join(` `)}function N(e,t){let r=n.createHash(`sha256`).update(e).digest(),i=n.createHash(`sha256`).update(t).digest();return n.timingSafeEqual(r,i)}const P={browserStack:`browserstack`,awsDeviceFarm:`aws-device-farm`},F=new Set(Object.values(P));function I(e){return e!==void 0&&F.has(e)}export{A as a,f as c,u as d,D as f,M as i,p as l,r as m,I as n,y as o,E as p,N as r,v as s,P as t,l as u};
@@ -1 +1 @@
1
- import{B as e}from"./sdk-contracts.js";import{Qn as t,wn as n}from"./tv-remote.js";import{b as r}from"./sdk-batch-runner.js";import{t as i}from"./snapshot-quality.js";import{d as a}from"./runtime.js";import{$t as o,Gt as s,en as c,tn as l}from"./internal/daemon.js";import{i as u,n as d,t as f}from"./interaction-snapshot.js";async function p(n){let{req:r,sessionName:o,sessionStore:s}=n;if(r.command!==t.reactNative)return null;let u=m(r.positionals??[]);if(!u.ok)return u.response;let d=s.get(o);if(!d)return c();let p=l(t.reactNative,d.device,{message:`react-native dismiss-overlay is not supported on this device`});if(p)return p;try{let e=await f(d,r.flags,s,n.contextFromFlags,{interactiveOnly:!0});if(i(e.snapshotQuality))return g(e.snapshotQuality);let t=a(e.nodes),o=t.primaryAction;return o?await _(n,d,e,o):h(t.detected)}catch(t){return{ok:!1,error:e(t)}}}function m(e){return e.length===1&&e[0]===`dismiss-overlay`?{ok:!0}:{ok:!1,response:o(`INVALID_ARGS`,`react-native supports only: dismiss-overlay`)}}function h(e){return e?o(`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`)}}}function g(e){return o(`COMMAND_FAILED`,`React Native overlay state could not be determined because the accessibility tree is unreadable`,{reason:e.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.`})}async function _(e,t,i,a){let{req:o,sessionStore:c}=e,l=Date.now(),f=await s(t.device,`press`,[String(a.point.x),String(a.point.y)],o.flags?.out,e.contextFromFlags(o.flags,t.appBundleId,t.trace?.outPath))??{},p=Date.now(),m=await v(e,t),h=r({...d(i.nodes),...f,action:`dismiss-overlay`,overlayAction:a.action,x:a.point.x,y:a.point.y,ref:a.ref,label:a.label,warning:a.warning,dismissed:!0,verified:m.verified,verificationRequired:!m.verified,verificationWarning:m.verificationWarning,nextCommand:m.nextCommand,...n(y(m))});return u({session:t,sessionStore:c,command:o.command,positionals:o.positionals??[],flags:o.flags,result:h,responseData:h,actionStartedAt:l,actionFinishedAt:p})}async function v(e,t){let{req:n,sessionStore:r}=e,o=await f(t,n.flags,r,e.contextFromFlags,{interactiveOnly:!0});return i(o.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`}:a(o.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}}function y(e){return e.verified?`React Native overlay dismiss action sent and verified gone`:`React Native overlay dismiss action sent, but verification still detects an overlay`}export{p as handleReactNativeCommands};
1
+ import{S as e}from"./sdk-contracts.js";import{Sn as t,Xn as n}from"./tv-remote.js";import{b as r}from"./sdk-batch-runner.js";import{t as i}from"./snapshot-quality.js";import{d as a}from"./runtime.js";import{Xt as o,an as s,in as c,on as l}from"./internal/daemon.js";import{i as u,n as d,t as f}from"./interaction-snapshot.js";async function p(t){let{req:r,sessionName:o,sessionStore:c}=t;if(r.command!==n.reactNative)return null;let u=m(r.positionals??[]);if(!u.ok)return u.response;let d=c.get(o);if(!d)return s();let p=l(n.reactNative,d.device,{message:`react-native dismiss-overlay is not supported on this device`});if(p)return p;try{let e=await f(d,r.flags,c,t.contextFromFlags,{interactiveOnly:!0});if(i(e.snapshotQuality))return g(e.snapshotQuality);let n=a(e.nodes),o=n.primaryAction;return o?await _(t,d,e,o):h(n.detected)}catch(t){return{ok:!1,error:e(t)}}}function m(e){return e.length===1&&e[0]===`dismiss-overlay`?{ok:!0}:{ok:!1,response:c(`INVALID_ARGS`,`react-native supports only: dismiss-overlay`)}}function h(e){return e?c(`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,...t(`No React Native overlay detected`)}}}function g(e){return c(`COMMAND_FAILED`,`React Native overlay state could not be determined because the accessibility tree is unreadable`,{reason:e.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.`})}async function _(e,n,i,a){let{req:s,sessionStore:c}=e,l=Date.now(),f=await o(n.device,`press`,[String(a.point.x),String(a.point.y)],s.flags?.out,e.contextFromFlags(s.flags,n.appBundleId,n.trace?.outPath))??{},p=Date.now(),m=await v(e,n),h=r({...d(i.nodes),...f,action:`dismiss-overlay`,overlayAction:a.action,x:a.point.x,y:a.point.y,ref:a.ref,label:a.label,warning:a.warning,dismissed:!0,verified:m.verified,verificationRequired:!m.verified,verificationWarning:m.verificationWarning,nextCommand:m.nextCommand,...t(y(m))});return u({session:n,sessionStore:c,command:s.command,positionals:s.positionals??[],flags:s.flags,result:h,responseData:h,actionStartedAt:l,actionFinishedAt:p})}async function v(e,t){let{req:n,sessionStore:r}=e,o=await f(t,n.flags,r,e.contextFromFlags,{interactiveOnly:!0});return i(o.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`}:a(o.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}}function y(e){return e.verified?`React Native overlay dismiss action sent and verified gone`:`React Native overlay dismiss action sent, but verification still detects an overlay`}export{p as handleReactNativeCommands};
@@ -1,4 +1,4 @@
1
- import{F as e,p as t}from"./sdk-contracts.js";import{F as n,j as r,s as i,v as a}from"./sdk-android-adb.js";import{Xt as o,Zt as s,d as c,l,u}from"./tv-remote.js";import{n as d,r as f,t as p}from"./output-path.js";import{g as m}from"./snapshot-diagnostics.js";import{t as h}from"./version.js";import{t as g}from"./timeouts.js";import{l as ee,o as te,s as ne}from"./host-process.js";import{d as _,p as re}from"./android-input-ownership.js";import{d as ie,i as ae}from"./runner-client.js";import{o as oe}from"./tool-provider.js";import{c as se}from"./agent-browser-tool.js";import{$t as v,ft as ce,in as le,ln as ue,mt as de,on as fe,tn as pe,xn as me}from"./internal/daemon.js";import{n as y}from"./provider.js";import{a as he,t as ge}from"./apple-runner-options.js";import{t as _e}from"./handler-utils.js";import{n as ve}from"./recording-provider.js";import{createHash as ye,randomUUID as be}from"node:crypto";import b from"node:fs";import xe from"node:os";import x from"node:path";import{fileURLToPath as Se}from"node:url";function S(e=process.env){let t=C(),n=x.join(t,`home`),r=x.join(t,`module-cache`);return b.mkdirSync(n,{recursive:!0}),b.mkdirSync(r,{recursive:!0}),{...e,HOME:n,CLANG_MODULE_CACHE_PATH:r}}async function Ce(e){let t=b.statSync(e.sourcePath),n=b.readFileSync(e.sourcePath),r=Oe(e.cacheName??x.basename(e.sourcePath,x.extname(e.sourcePath))),i=ke([`2`,process.platform,process.arch,x.resolve(e.sourcePath),t.size,n]),a=x.join(C(),`bin`,`${r}-${i}`);return await Te({sourcePath:e.sourcePath,executablePath:a,timeoutMs:e.timeoutMs}),a}async function we(e){let t=Oe(e.cacheName),n=ke([`2`,process.platform,process.arch,e.source]),r=x.join(C(),`sources`,`${t}-${n}.swift`),i=x.join(C(),`bin`,`${t}-${n}`);return await Te({sourcePath:r,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function C(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?x.resolve(e):x.join(xe.tmpdir(),`agent-device-swift-cache`)}async function Te(e){if(De(e.executablePath))return;let t=x.dirname(e.executablePath);b.mkdirSync(t,{recursive:!0});let n=await Ee(`${e.executablePath}.lock`,e.executablePath,e.timeoutMs??12e4);if(!n)return;let r=b.mkdtempSync(x.join(t,`.${x.basename(e.executablePath)}.${process.pid}.`)),i=x.join(r,x.basename(e.executablePath));try{if(De(e.executablePath))return;e.sourceText!==void 0&&!b.existsSync(e.sourcePath)&&(b.mkdirSync(x.dirname(e.sourcePath),{recursive:!0}),b.writeFileSync(e.sourcePath,e.sourceText)),await a(`xcrun`,[`swiftc`,e.sourcePath,`-o`,i],{timeoutMs:e.timeoutMs??12e4,env:S()}),b.renameSync(i,e.executablePath)}finally{b.rmSync(r,{recursive:!0,force:!0}),await n()}}async function Ee(t,n,r){if(De(n))return null;try{return await se({lockDirPath:t,owner:{pid:process.pid,startTime:te(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${t} (${r}ms)`})}catch(n){throw n instanceof e&&n.message.startsWith(`Timed out waiting for Swift cache lock:`)?new e(`COMMAND_FAILED`,n.message,{...n.details,lockDir:t,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${t}" and retry.`}):n}}function De(e){try{return b.accessSync(e,b.constants.X_OK),b.statSync(e).isFile()}catch{return!1}}function Oe(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,`-`).replaceAll(/^-+|-+$/g,``)||`swift-helper`}function ke(e){let t=ye(`sha256`);for(let n of e)t.update(Buffer.isBuffer(n)?n:String(n)),t.update(`\0`);return t.digest(`hex`).slice(0,16)}let Ae;async function je(e,t={}){let n=t.pollMs??150,r=t.attempts??12,i,a=0;for(let t=0;t<r;t+=1){let t=0;try{t=b.statSync(e).size}catch{t=0}if(t>0&&t===i){if(a+=1,a>=2)return}else a=0;i=t,await g(n)}}async function Me(e){try{let t=await a(await Ne(),[e],{allowFailure:!0,timeoutMs:1e4,env:S()});return t.exitCode===0?!0:Ie(t.stderr,t.stdout)?Le(e):!1}catch(t){if(Pe(t))return Le(e);throw t}}async function Ne(){Ae??=we({source:`import Foundation
1
+ import{_ as e}from"./sdk-contracts.js";import{F as t,j as n,s as r,v as i}from"./sdk-android-adb.js";import{Jt as a,Yt as o,d as s,l as c,u as l}from"./tv-remote.js";import{n as u,r as d,t as f}from"./output-path.js";import{g as p}from"./snapshot-diagnostics.js";import{t as m}from"./version.js";import{t as h}from"./timeouts.js";import{l as g,o as ee,s as te}from"./host-process.js";import{s as ne}from"./sdk-device.js";import{d as _,p as re}from"./android-input-ownership.js";import{d as ie,i as ae}from"./runner-client.js";import{a as oe}from"./tool-provider.js";import{c as se}from"./agent-browser-tool.js";import{En as ce,dn as le,ft as ue,in as v,ln as de,mn as fe,mt as pe,on as me}from"./internal/daemon.js";import{n as y}from"./provider.js";import{a as he,t as ge}from"./apple-runner-options.js";import{t as _e}from"./handler-utils.js";import{n as ve}from"./recording-provider.js";import{createHash as ye,randomUUID as be}from"node:crypto";import b from"node:fs";import xe from"node:os";import x from"node:path";import{fileURLToPath as Se}from"node:url";function S(e=process.env){let t=C(),n=x.join(t,`home`),r=x.join(t,`module-cache`);return b.mkdirSync(n,{recursive:!0}),b.mkdirSync(r,{recursive:!0}),{...e,HOME:n,CLANG_MODULE_CACHE_PATH:r}}async function Ce(e){let t=b.statSync(e.sourcePath),n=b.readFileSync(e.sourcePath),r=De(e.cacheName??x.basename(e.sourcePath,x.extname(e.sourcePath))),i=Oe([`2`,process.platform,process.arch,x.resolve(e.sourcePath),t.size,n]),a=x.join(C(),`bin`,`${r}-${i}`);return await Te({sourcePath:e.sourcePath,executablePath:a,timeoutMs:e.timeoutMs}),a}async function we(e){let t=De(e.cacheName),n=Oe([`2`,process.platform,process.arch,e.source]),r=x.join(C(),`sources`,`${t}-${n}.swift`),i=x.join(C(),`bin`,`${t}-${n}`);return await Te({sourcePath:r,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function C(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?x.resolve(e):x.join(xe.tmpdir(),`agent-device-swift-cache`)}async function Te(e){if(w(e.executablePath))return;let t=x.dirname(e.executablePath);b.mkdirSync(t,{recursive:!0});let n=await Ee(`${e.executablePath}.lock`,e.executablePath,e.timeoutMs??12e4);if(!n)return;let r=b.mkdtempSync(x.join(t,`.${x.basename(e.executablePath)}.${process.pid}.`)),a=x.join(r,x.basename(e.executablePath));try{if(w(e.executablePath))return;e.sourceText!==void 0&&!b.existsSync(e.sourcePath)&&(b.mkdirSync(x.dirname(e.sourcePath),{recursive:!0}),b.writeFileSync(e.sourcePath,e.sourceText)),await i(`xcrun`,[`swiftc`,e.sourcePath,`-o`,a],{timeoutMs:e.timeoutMs??12e4,env:S()}),b.renameSync(a,e.executablePath)}finally{b.rmSync(r,{recursive:!0,force:!0}),await n()}}async function Ee(t,n,r){if(w(n))return null;try{return await se({lockDirPath:t,owner:{pid:process.pid,startTime:ee(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${t} (${r}ms)`})}catch(n){throw n instanceof e&&n.message.startsWith(`Timed out waiting for Swift cache lock:`)?new e(`COMMAND_FAILED`,n.message,{...n.details,lockDir:t,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${t}" and retry.`}):n}}function w(e){try{return b.accessSync(e,b.constants.X_OK),b.statSync(e).isFile()}catch{return!1}}function De(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,`-`).replaceAll(/^-+|-+$/g,``)||`swift-helper`}function Oe(e){let t=ye(`sha256`);for(let n of e)t.update(Buffer.isBuffer(n)?n:String(n)),t.update(`\0`);return t.digest(`hex`).slice(0,16)}let ke;async function Ae(e,t={}){let n=t.pollMs??150,r=t.attempts??12,i,a=0;for(let t=0;t<r;t+=1){let t=0;try{t=b.statSync(e).size}catch{t=0}if(t>0&&t===i){if(a+=1,a>=2)return}else a=0;i=t,await h(n)}}async function je(e){try{let t=await i(await Me(),[e],{allowFailure:!0,timeoutMs:1e4,env:S()});return t.exitCode===0?!0:Fe(t.stderr,t.stdout)?Ie(e):!1}catch(t){if(Ne(t))return Ie(e);throw t}}async function Me(){ke??=we({source:`import Foundation
2
2
  import AVFoundation
3
3
 
4
4
  let url = URL(fileURLWithPath: CommandLine.arguments[1])
@@ -20,4 +20,4 @@ Task {
20
20
  }
21
21
 
22
22
  semaphore.wait()
23
- exit(exitCode)`,cacheName:`video-validator`,timeoutMs:3e4});try{return await Ae}catch(e){throw Ae=void 0,e}}function Pe(t){return t instanceof e?t.code===`TOOL_MISSING`?!0:Ie(String(t.details?.stderr??``),String(t.details?.stdout??``)):!1}async function Fe(e,t={}){let n=t.pollMs??150,r=t.attempts??12;for(let t=0;t<r;t+=1){if(await Me(e))return;await g(n)}}function Ie(e,t){let n=`${e}\n${t}`;return/\b(no such module ['"]AVFoundation['"]|unable to find utility ["']swiftc?["']|xcrun: error: unable to find utility ["']swiftc?["'])\b/i.test(n)}function Le(e){try{let t=b.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=Re(e);return t.includes(`ftyp`)&&t.includes(`moov`)}function Re(e){try{let t=b.openSync(e,`r`);try{let e=b.fstatSync(t).size,n=0,r=[];for(;n+8<=e&&r.length<16;){let e=Buffer.alloc(8);if(b.readSync(t,e,0,8,n)<8)break;let i=e.readUInt32BE(0),a=e.toString(`latin1`,4,8);if(r.push(a),i===1){let e=Buffer.alloc(8);if(b.readSync(t,e,0,8,n+8)<8)break;i=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(i)||i<=0)break;n+=i}return r}finally{b.closeSync(t)}}catch{return[]}}function ze(e){let t=x.parse(e);return x.join(t.dir,`${t.name}.gesture-telemetry.json`)}function Be(e,t){return Ve(t>0?e.flatMap(e=>{let n=e.tMs-t,r=`durationMs`in e?e.durationMs:void 0;return(typeof r==`number`?n+r:n)<=0?[]:[{...e,tMs:Math.max(0,n)}]}):e)}function Ve(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function He(e){let t=ze(e.videoPath),n={version:1,generatedAt:new Date().toISOString(),events:Be(e.events,e.trimStartMs??0)};return b.writeFileSync(t,JSON.stringify(n,null,2)),t}function Ue(e){let{recording:t,trimStartMs:n}=e,r=He({videoPath:t.outPath,events:t.gestureEvents,trimStartMs:n});return t.telemetryPath=r,r}function We(e,t,n,r){let i=`apple-runner/AgentDeviceRunner/RecordingScripts/${e}`,a=`dist/${i}`;return[x.resolve(t,e),x.resolve(n,i),x.resolve(t,`../${i}`),x.resolve(t,`../../${i}`),x.resolve(t,`../../../${i}`),x.resolve(n,a),x.resolve(r,i)]}function w(t){let n=We(t,x.dirname(Se(import.meta.url)),h(),process.cwd());for(let e of n)if(b.existsSync(e))return e;throw new e(`COMMAND_FAILED`,`Missing recording helper script: ${t}`,{hint:`Ensure apple-runner/AgentDeviceRunner/RecordingScripts is present in this checkout or bundled under dist/apple-runner in the package.`,scriptName:t,searchedPaths:n})}let Ge,Ke,qe;function Je(e=process.platform){if(e!==`darwin`)return`touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry`}function Ye(){return Ge??=w(`recording-overlay.swift`),Ge}function Xe(){return Ke??=w(`recording-trim.swift`),Ke}function Ze(){return qe??=w(`recording-resize.swift`),qe}async function T(t){let{videoPath:n,scriptPath:r,scriptArgs:i,commandDescription:o}=t;await je(n),await Fe(n);let s=Qe(n);try{await a(await Ce({sourcePath:r}),[`--input`,n,`--output`,s,...i],{timeoutMs:12e4,env:S()}),await Fe(s),b.renameSync(s,n)}catch(t){let i=t instanceof e?t:new e(`COMMAND_FAILED`,String(t),void 0,t instanceof Error?t:void 0);throw new e(`COMMAND_FAILED`,o,{...i.details,videoPath:n,script:r},i)}finally{b.rmSync(s,{force:!0})}}function Qe(e){let t=x.parse(e),n=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;return x.join(t.dir,`.${t.name}.agent-device-${n}${t.ext||`.mp4`}`)}async function $e(e){let{videoPath:t,trimStartMs:n}=e;n>0&&await T({videoPath:t,scriptPath:Xe(),scriptArgs:[`--trim-start-ms`,String(n)],commandDescription:`Failed to trim the start of the iOS recording`})}async function et(e){let{videoPath:t,telemetryPath:n,exportQuality:r=l,targetLabel:i=`recording`}=e;await T({videoPath:t,scriptPath:Ye(),scriptArgs:[`--events`,n,`--quality`,r],commandDescription:`Failed to add touch overlays to the ${i}`})}async function tt(e){let{videoPath:t,maxSize:n,exportQuality:r=l,targetLabel:i=`recording`}=e;await T({videoPath:t,scriptPath:Ze(),scriptArgs:[`--max-size`,String(n),`--quality`,r],commandDescription:`Failed to resize the ${i}`})}function E(e){return e instanceof Error?e.message:String(e)}const nt=1e3;function D(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function rt(e,t,n=Date.now()){let r=Math.max(0,n-t.startedAt);return r>=nt?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(r)}ms; wait at least ${nt}ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function O(e){let{recording:t,deps:i,trimStartMs:a,targetLabel:o}=e,s=Ue({recording:t,trimStartMs:a});if(!t.showTouches){r({level:`debug`,phase:`record_stop_overlay_skipped`,data:{reason:`hide_touches`}});return}if(t.gestureEvents.length===0){r({level:`debug`,phase:`record_stop_overlay_skipped`,data:{reason:`no_gesture_events`}});return}let c=Je();if(c){t.overlayWarning??=c;return}try{await n(`record_stop_overlay_export`,()=>i.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:s,exportQuality:t.exportQuality,targetLabel:o}),{targetLabel:o,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${E(e)}`}}function k(e,t){if(t===1)return e;let n=x.parse(e),r=n.ext||`.mp4`;return x.join(n.dir,`${n.name}.part-${String(t).padStart(3,`0`)}${r}`)}function A(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}function it(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.`}function at(e){let{recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}=e,o=setTimeout(()=>{t.rotationPromise=ot({recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}).catch(e=>{t.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{t.rotationPromise=void 0,!t.stopping&&!t.rotationFailedReason&&at({recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a})})},17e4);o.unref?.(),t.rotationTimer=o}async function ot(e){let{recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}=e;if(t.stopping)return;let o=A(t),s=o.length+1,c={remotePath:t.remotePath,remotePid:t.remotePid,startedAt:t.remoteStartedAt??t.startedAt},l=await st({recording:t,nextIndex:s,previousChunk:c,startNextChunk:n,finishCurrentChunk:r});if(!l)return;let{nextChunk:u,previousChunkFinished:d}=l;await lt({recording:t,chunks:o,nextChunk:u,nextIndex:s,previousState:ct({recording:t,nextChunk:u}),finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}),!d&&await dt(r,c)}async function st(e){let{recording:t,nextIndex:n,previousChunk:r,startNextChunk:i,finishCurrentChunk:a}=e,o=x.posix.dirname(t.remotePath);try{return{nextChunk:await i(o,n),previousChunkFinished:!1}}catch(e){let s=await a(r);if(s)throw Error(s);if(t.stopping)return;try{return{nextChunk:await i(o,n),previousChunkFinished:!0}}catch(t){throw t instanceof Error?t:e}}}function ct(e){let{recording:t,nextChunk:n}=e,r={remotePath:t.remotePath,remotePid:t.remotePid,remoteStartedAt:t.remoteStartedAt};return t.remotePath=n.remotePath,t.remotePid=n.remotePid,t.remoteStartedAt=n.startedAt,r}async function lt(e){let{recording:t,chunks:n,nextChunk:r,nextIndex:i,previousState:a,finishCurrentChunk:o,cleanupStartedChunk:s,persistRecordingState:c}=e;n.push({index:i,path:k(t.outPath,i),remotePath:r.remotePath}),t.warning??=`Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks.`;try{await c?.(t)}catch(e){throw ut({recording:t,chunks:n,previousState:a}),await ft({nextChunk:r,finishCurrentChunk:o,cleanupStartedChunk:s})||e}}function ut(e){let{recording:t,chunks:n,previousState:r}=e;n.pop(),t.remotePath=r.remotePath,t.remotePid=r.remotePid,t.remoteStartedAt=r.remoteStartedAt}async function dt(e,t){let n=await e(t);if(n)throw Error(n)}async function ft(e){let{nextChunk:t,finishCurrentChunk:n,cleanupStartedChunk:r}=e,i;try{await dt(n,t)}catch(e){i=e}try{await r?.(t)}catch(e){i??=e}return i}async function pt(e){let{recording:t,deps:n}=e;if(A(t).length<=1){await O({recording:t,deps:n,targetLabel:`Android recording`});return}Ue({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 mt(e){for(let t of e.chunks){let n=await ht({deps:e.deps,deviceId:e.deviceId,remotePath:t.remotePath,outPath:t.path});if(n)return`failed to copy recording chunk ${t.index}: ${n}`}}async function ht(e){let{deps:t,deviceId:n,remotePath:a,outPath:o}=e,s;for(let e=0;e<2;e+=1){_t(o);let c=await i(a,o,{allowFailure:!0,device:_(n)});if(c.exitCode!==0)s=D(c,`adb pull`);else{await t.waitForStableFile(o,{pollMs:250,attempts:20});let i=await t.isPlayableVideo(o);if(r({level:`debug`,phase:`record_stop_android_pull_validation`,data:{deviceId:n,remotePath:a,outPath:o,attempt:e+1,fileSize:gt(o),playable:i}}),i)return;r({level:`warn`,phase:`record_stop_android_invalid_video_retry`,data:{deviceId:n,remotePath:a,outPath:o,attempt:e+1}})}e<1&&await g(750)}return s?`failed to copy recording from device: ${s}`:(_t(o),`failed to copy recording from device: pulled file is not a playable MP4`)}function gt(e){try{return b.statSync(e).size}catch{return 0}}function _t(e){try{b.rmSync(e,{force:!0})}catch{}}const vt=`agent-device-recording-active.json`,yt=[`/sdcard`,`/data/local/tmp`];function bt(e){let t=e.trim().match(/^(\d+)\s+.*\bscreenrecord\b.*(\/(?:sdcard|data\/local\/tmp)\/agent-device-recording-(\d+)\.mp4)(?:\s|$)/);if(!t)return;let[,n,r,i]=t;if(!n||!r)return;let a=Number(i);return{remotePid:n,remotePath:r,startedAt:Number.isFinite(a)?a:Date.now()}}function xt(e){let t=Dt(e);if(!t)return{kind:`delete`};let n=kt(t);if(!n)return{kind:`blocked`,reason:`unsupported_or_malformed_manifest`};let r=jt(t.current),i=Mt(t.pending),a=Nt(t.chunks);return a?!r&&!i?{kind:`blocked`,reason:`invalid_recording_state`}:{kind:`manifest`,manifest:{...n,sessionScope:Ft(t.sessionScope),current:r,pending:i,chunks:a}}:{kind:`blocked`,reason:`invalid_recording_chunks`}}function St(e){return`${x.posix.dirname(e)}/${vt}`}function j(){return yt.map(e=>`${e}/${vt}`)}function Ct(e){let{deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}=e;return{version:1,sessionName:n,sessionScope:r,recordingId:i,deviceId:t,startedAt:a,showTouches:o,pending:{remotePath:s},chunks:[{index:1,remotePath:s}]}}function wt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i}=e;return{version:1,sessionName:n,sessionScope:r,recordingId:i.recordingId??`android-${i.remotePid}-${i.remoteStartedAt??i.startedAt}`,deviceId:t,startedAt:i.startedAt,showTouches:i.showTouches,current:{remotePath:i.remotePath,remotePid:i.remotePid,startedAt:i.remoteStartedAt??i.startedAt},chunks:Et(i)}}function Tt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return{...wt({deviceId:t,sessionName:n,sessionScope:r,recording:i}),pending:{remotePath:a},chunks:Et(i,{index:o,remotePath:a})}}function Et(e,t){return[...e.chunks??[{index:1,remotePath:e.remotePath}],...t?[t]:[]].map(e=>({index:e.index,remotePath:e.remotePath}))}function Dt(e){try{let t=JSON.parse(e);return Ot(t)?t:void 0}catch{return}}function Ot(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function kt(e){if(e.version!==1)return;let t=At(e);if(!t)return;let n=It(e.startedAt);if(n===void 0)return;let r=Lt(e.showTouches);if(r!==void 0)return{version:1,...t,startedAt:n,showTouches:r}}function At(e){let t=M(e.sessionName),n=M(e.recordingId),r=M(e.deviceId);if(!(!t||!n||!r))return{sessionName:t,recordingId:n,deviceId:r}}function jt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.remotePid!=`string`||!/^\d+$/.test(t.remotePid)||typeof t.remotePath!=`string`||!N(t.remotePath)))return{remotePid:t.remotePid,remotePath:t.remotePath,startedAt:typeof t.startedAt==`number`&&Number.isFinite(t.startedAt)?t.startedAt:Date.now()}}function Mt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.remotePath!=`string`||!N(t.remotePath)))return{remotePath:t.remotePath}}function Nt(e){if(!Array.isArray(e))return;let t=e.map(Pt).filter(e=>e!==void 0);return t.length>0&&t.length===e.length?t:void 0}function Pt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.index!=`number`||!Number.isInteger(t.index)||t.index<1||typeof t.remotePath!=`string`||!N(t.remotePath)))return{index:t.index,remotePath:t.remotePath}}function Ft(e){if(!e||typeof e!=`object`)return;let t=e;if(!(t.kind!==`cwd`||typeof t.id!=`string`))return{kind:`cwd`,id:t.id}}function M(e){return typeof e==`string`?e:void 0}function It(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function Lt(e){return typeof e==`boolean`?e:void 0}function N(e){return/^\/(?:sdcard|data\/local\/tmp)\/agent-device-recording-\d+\.mp4$/.test(e)}const Rt=`Recovered Android recording after daemon restart from durable device manifest.`,zt=`touch overlay burn-in is unavailable after daemon restart because gesture telemetry is stored in daemon memory`,P=`Recovered Android recording after daemon restart from durable device manifest; the screenrecord process was no longer running, so the MP4 may be truncated.`,F=`Recovered Android recording from an interrupted chunk rotation; returning chunks known to be safely owned by the durable manifest.`,I=5e3;async function L(e,t,n){return await re(_(e),t,n)}async function Bt(e){let t={live:[],uncertain:[],blocked:[]};for(let n of j()){let r=await L(e,[`shell`,`cat`,n],{allowFailure:!0,timeoutMs:I});if(r.exitCode!==0)continue;let i=xt(r.stdout);if(i.kind===`delete`){await H({deviceId:e,metadataPath:n,phase:`record_stop_android_recovery_metadata_invalid_cleanup_failed`});continue}if(i.kind===`blocked`){t.blocked.push({metadataPath:n,reason:i.reason});continue}let a=i.manifest;if(a.deviceId!==e){t.blocked.push({metadataPath:n,reason:`device_mismatch`});continue}let o=await Vt(e,a);if(o.kind===`live`){t.live.push(o.manifest);continue}if(o.kind===`uncertain`){t.uncertain.push(a);continue}await H({deviceId:e,metadataPath:n,phase:`record_stop_android_recovery_metadata_stale_cleanup_failed`})}return t}async function Vt(e,t){return t.pending?await Ht(e,t,t.pending):await Kt(e,t)}async function Ht(e,t,n){let r=await Jt(e,n.remotePath);return Wt(t,r)||(t.current?await Ut(e,t,t.current,r):await Gt(e,t,n.remotePath,r))}async function Ut(e,t,n,r){let i=await qt(e,n);return i===`uncertain`||r===`uncertain`?{kind:`uncertain`}:i===`stale`?{kind:`stale`}:R({manifest:t,current:n,chunks:Xt(t.chunks,n.remotePath),recoveryWarning:i===`finished`?`${F} ${P}`:F})}function Wt(e,t){if(!(!t||t===`uncertain`))return R({manifest:e,current:t,recoveryWarning:e.current?F:Rt})}async function Gt(e,t,n,r){return r===`uncertain`?{kind:`uncertain`}:await Yt(e,n)?R({manifest:t,current:{remotePath:n,remotePid:``,startedAt:t.startedAt},recoveryWarning:P}):{kind:`stale`}}async function Kt(e,t){if(!t.current)return{kind:`stale`};let n=await qt(e,t.current);return n===`live`?R({manifest:t,current:t.current}):n===`finished`?R({manifest:t,current:t.current,recoveryWarning:P}):{kind:n}}function R(e){let{manifest:t,current:n,chunks:r,recoveryWarning:i}=e;return{kind:`live`,manifest:{...t,current:n,chunks:r??t.chunks,...i?{recoveryWarning:i}:{}}}}async function qt(e,t){let n=await L(e,[`shell`,`ps`,`-o`,`pid=,args=`,`-p`,t.remotePid],{allowFailure:!0,timeoutMs:I});if(n.exitCode!==0)return r({level:`debug`,phase:`record_stop_android_recovery_metadata_probe_uncertain`,data:{deviceId:e,remotePid:t.remotePid,remotePath:t.remotePath,exitCode:n.exitCode,stdout:n.stdout.trim(),stderr:n.stderr.trim()}}),`uncertain`;let i=n.stdout.split(/\r?\n/),a=i.map(e=>e.trim()).find(e=>e.startsWith(t.remotePid));return i.map(bt).some(e=>e?.remotePid===t.remotePid&&e.remotePath===t.remotePath)?`live`:a?.includes(`screenrecord`)?`uncertain`:a?`stale`:await Yt(e,t.remotePath)?`finished`:`stale`}async function Jt(e,t){let n=await L(e,[`shell`,`ps`,`-A`,`-o`,`pid=,args=`],{allowFailure:!0,timeoutMs:I});return n.exitCode===0?n.stdout.split(/\r?\n/).map(bt).find(e=>e?.remotePath===t):(r({level:`debug`,phase:`record_stop_android_recovery_ps_failed`,data:{deviceId:e,remotePath:t,exitCode:n.exitCode,stdout:n.stdout.trim(),stderr:n.stderr.trim()}}),`uncertain`)}async function Yt(e,t){let n=await L(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:I}),r=n.exitCode===0?Number(n.stdout.trim()):NaN;return Number.isFinite(r)&&r>=1}function Xt(e,t){let n=e.findIndex(e=>e.remotePath===t);return n>=0?e.slice(0,n+1):e}async function Zt(e){let{deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}=e;return await B({deviceId:t,manifest:Ct({deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}),phase:`record_start_android_recovery_metadata_failed`})}async function Qt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return await B({deviceId:t,manifest:Tt({deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}),phase:`record_rotate_android_recovery_metadata_failed`})}async function z(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i}=e;return await B({deviceId:t,manifest:wt({deviceId:t,sessionName:n,sessionScope:r,recording:i}),phase:`record_start_android_recovery_metadata_failed`})}async function B(e){let{deviceId:t,manifest:n,phase:r}=e,i=n.current?.remotePath??n.pending?.remotePath;if(!i)return`failed to write Android recording recovery manifest: missing path`;let a=St(i),o=`${a}.tmp`,s=await L(t,[`shell`,`printf %s ${m(JSON.stringify(n))} > ${m(o)} && mv -f ${m(o)} ${m(a)}`],{allowFailure:!0,timeoutMs:I});if(s.exitCode!==0)return $t({phase:r,deviceId:t,metadataPath:a,result:s}),await H({deviceId:t,metadataPath:o,phase:`${r}_tmp_cleanup_failed`}),`failed to write Android recording recovery manifest: ${D(s,`adb shell write recovery manifest`)}`;for(let e of j())e!==a&&await H({deviceId:t,metadataPath:e,phase:`record_start_android_recovery_metadata_stale_cleanup_failed`})}async function V(e){for(let t of j())await H({deviceId:e,metadataPath:t,phase:`record_stop_android_recovery_metadata_cleanup_failed`})}async function H(e){let{deviceId:t,metadataPath:n,phase:r}=e,i=await L(t,[`shell`,`rm`,`-f`,n],{allowFailure:!0,timeoutMs:I});i.exitCode!==0&&$t({phase:r,deviceId:t,metadataPath:n,result:i})}function $t(e){let{phase:t,deviceId:n,metadataPath:i,result:a}=e;r({level:`warn`,phase:t,data:{deviceId:n,metadataPath:i,exitCode:a.exitCode,stdout:a.stdout.trim(),stderr:a.stderr.trim()}})}async function en(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a=await Bt(r.id);return a.live.length>0?rn({sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a.live}):a.uncertain.length>0?tn({sessionName:t,activeSession:n,manifests:a.uncertain}):a.blocked.length>0?nn(a.blocked):null}function tn(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=on({sessionName:t,activeSession:n,manifests:r}),a={activeRecordings:i.activeRecordings,recoveryBlocked:`manifest_liveness_uncertain`,hint:`Retry record stop after the device responds. Android recording recovery requires a verified durable manifest.`};return i.kind===`owner-mismatch`?v(`INVALID_ARGS`,fn(r),a):i.kind===`ambiguous`?v(`INVALID_ARGS`,`multiple active Android recording manifests could not be verified; cannot safely recover missing recording state`,a):v(`INVALID_ARGS`,`active Android recording manifest could not be verified; retry record stop after the device responds`,a)}function nn(e){return v(`INVALID_ARGS`,`active Android recording manifest could not be validated`,{recoveryBlocked:`manifest_invalid_or_unsupported`,manifests:e,hint:`Retry with the same agent-device version that started the recording, or inspect and remove stale device recovery metadata after confirming no recording is active.`})}function rn(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a}=e,o=an({sessionName:t,activeSession:n,manifests:a});return`ok`in o?o:(cn(r,o),ln(o,i))}function an(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=on({sessionName:t,activeSession:n,manifests:r});return i.kind===`selected`?i.manifest:i.kind===`owner-mismatch`?v(`INVALID_ARGS`,fn(r),{activeRecordings:i.activeRecordings}):v(`INVALID_ARGS`,`multiple active Android recording manifests exist; cannot safely recover missing recording state`,{activeRecordings:i.activeRecordings})}function on(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=r.filter(e=>un(e,t,n)),a=sn(r);return i.length===0?{kind:`owner-mismatch`,activeRecordings:a}:i.length>1||r.length>1?{kind:`ambiguous`,activeRecordings:a}:{kind:`selected`,manifest:i[0],activeRecordings:a}}function sn(e){return e.map(e=>({sessionName:e.sessionName,sessionScope:e.sessionScope,recordingId:e.recordingId,remotePid:e.current?.remotePid,remotePath:e.current?.remotePath??e.pending?.remotePath}))}function cn(e,t){r({level:`warn`,phase:`record_stop_android_recovered_missing_state`,data:{deviceId:e.id,sessionName:t.sessionName,recordingId:t.recordingId,remotePath:t.current.remotePath,remotePid:t.current.remotePid,chunks:t.chunks.length}})}function ln(e,t){let n=e.recoveryWarning??Rt;return{platform:`android`,recordingId:e.recordingId,remotePath:e.current.remotePath,remotePid:e.current.remotePid,remoteStartedAt:e.current.startedAt,chunks:e.chunks.map(e=>({index:e.index,path:k(t.outPath,e.index),remotePath:e.remotePath})),outPath:t.outPath,clientOutPath:t.clientOutPath,telemetryPath:t.telemetryPath,startedAt:e.startedAt,maxSize:t.maxSize,exportQuality:t.exportQuality,showTouches:!1,gestureEvents:[],warning:e.showTouches?`${n} ${zt}.`:n,overlayWarning:e.showTouches?zt:void 0}}function un(e,t,n){return e.sessionName===t&&dn(e.sessionScope,n.sessionScope)}function dn(e,t){return!e&&!t?!0:!e||!t?!1:e.kind===t.kind&&e.id===t.id}function fn(e){if(e.length===1){let t=e[0];return t.sessionScope?`active Android recording belongs to session "${t.sessionName}" in ${t.sessionScope.kind} scope; retry record stop from the original working directory without --session to recover it`:`active Android recording belongs to session "${t.sessionName}"; run record stop --session ${t.sessionName} to recover it`}return`active Android recordings belong to other sessions; cannot safely recover missing recording state`}const pn={medium:8e6,high:2e7},U=5e3;async function W(e,t,n){return await re(_(e),t,n)}function mn(e){return e.split(/\r?\n/).map(e=>e.trim()).filter(e=>/^\d+$/.test(e)).at(-1)}async function G(e,t){let n=await W(e,[`shell`,`ps`,`-o`,`pid=`,`-p`,t],{allowFailure:!0,timeoutMs:U});return n.exitCode===0?n.stdout.split(/\s+/).map(e=>e.trim()).includes(t):!1}async function hn(e,t){for(let n=0;n<40;n+=1){if(!await G(e,t))return!0;await g(250)}return!await G(e,t)}async function gn(e,t){let n,r=0;for(let i=0;i<20;i+=1){let i=await W(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:U}),a=i.exitCode===0?i.stdout.trim():``;if(a.length>0&&a===n){if(r+=1,r>=4)return}else r=0;n=a,await g(250)}}async function _n(e,t,n){for(let r=0;r<8;r+=1){let i=await W(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:U}),a=i.exitCode===0?Number(i.stdout.trim()):NaN;if(Number.isFinite(a)&&a>0)return!0;if(!await G(e,n))return!1;if(r+1>=2)return!0;await g(250)}return!1}function vn(e,t){let n=`agent-device-recording-${e}.mp4`,r=[`/sdcard`,`/data/local/tmp`];return(t&&r.includes(t)?[t,...r.filter(e=>e!==t)]:r).map(e=>`${e}/${n}`)}async function yn(e){let{deviceId:t,maxSize:n}=e;if(n===void 0)return;let r=await W(t,[`shell`,`wm`,`size`],{allowFailure:!0,timeoutMs:U}),i=r.stdout.match(/Override size:\s*(\d+)x(\d+)/)??r.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(r.exitCode!==0||!i)throw Error(`failed to resolve Android screen size for recording max-size: ${D(r,`adb shell wm size`)}`);return bn({width:Number(i[1]),height:Number(i[2]),maxSize:n})}function bn(e){let t=Math.max(e.width,e.height);if(t<=e.maxSize)return{width:e.width,height:e.height};let n=e.maxSize/t;return{width:xn(e.width,n),height:xn(e.height,n)}}function xn(e,t){return Math.max(2,Math.round(e*t/2)*2)}function Sn(e,t,n){let r=[`screenrecord`];return t&&r.push(`--size`,`${t.width}x${t.height}`),r.push(`--bit-rate`,String(pn[n])),r.push(e),`${r.join(` `)} >/dev/null 2>&1 & echo $!`}async function K(e,t){await W(e,[`shell`,`rm`,`-f`,t],{allowFailure:!0,timeoutMs:U})}async function q(e,t){let n=await W(e,[`shell`,`kill`,`-9`,t],{allowFailure:!0,timeoutMs:U});return r({level:`warn`,phase:`record_stop_android_force_signal`,data:{deviceId:e,remotePid:t,exitCode:n.exitCode,stdout:n.stdout.trim(),stderr:n.stderr.trim()}}),n.exitCode!==0&&await G(e,t)?!1:await hn(e,t)}async function Cn(e){let{device:t,recordingSize:n,quality:r,preferredRemoteDir:i,hooks:a}=e,o=`failed to start recording: Android screenrecord did not begin producing frames`;for(let e of vn(Date.now(),i)){let i=await wn({device:t,recordingSize:n,quality:r,remotePath:e,hooks:a});if(i.kind===`started`)return i.chunk;o=i.message}return{error:v(`COMMAND_FAILED`,o)}}async function wn(e){let{device:t,recordingSize:n,quality:i,remotePath:a,hooks:o}=e,s=await o?.prepareRemotePath?.(a);if(s)return{kind:`failed`,message:s};let c=await W(t.id,[`shell`,Sn(a,n,i)],{allowFailure:!0,timeoutMs:U});if(c.exitCode!==0)return await o?.cleanupPreparedRemotePath?.(a),{kind:`failed`,message:`failed to start recording: ${D(c,`adb shell screenrecord`)}`};let l=mn(c.stdout);return l?(r({level:`debug`,phase:`record_start_android_started`,data:{deviceId:t.id,remotePath:a,remotePid:l}}),await _n(t.id,a,l)?{kind:`started`,chunk:{remotePath:a,remotePid:l,startedAt:Date.now()}}:(await q(t.id,l),await o?.cleanupPreparedRemotePath?.(a),await K(t.id,a),{kind:`failed`,message:`failed to start recording: Android screenrecord did not begin producing frames`})):(await o?.cleanupPreparedRemotePath?.(a),await K(t.id,a),{kind:`failed`,message:`failed to start recording: adb did not return a valid Android screenrecord pid`})}async function Tn(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a;try{a=await yn({deviceId:r.id,maxSize:i.maxSize})}catch(e){return v(`COMMAND_FAILED`,e instanceof Error?e.message:String(e))}let o=i.exportQuality??`medium`,s=be(),c=await Cn({device:r,recordingSize:a,quality:o,hooks:{prepareRemotePath:async e=>await Zt({deviceId:r.id,sessionName:t,sessionScope:n.sessionScope,recordingId:s,startedAt:i.startedAt,showTouches:i.showTouches,remotePath:e}),cleanupPreparedRemotePath:async()=>{await V(r.id)}}});if(`error`in c)return c.error;let l=En({recordingBase:i,chunk:c,recordingId:s}),u=await z({deviceId:r.id,sessionName:t,sessionScope:n.sessionScope,recording:l});return u?(await q(r.id,l.remotePid),await K(r.id,l.remotePath),await V(r.id),v(`COMMAND_FAILED`,`failed to start recording: ${u}`)):(Dn({activeSession:n,sessionName:t,device:r,recording:l,recordingSize:a,quality:o}),l)}function En(e){let{recordingBase:t,chunk:n,recordingId:r}=e;return{platform:`android`,recordingId:r,remotePath:n.remotePath,remotePid:n.remotePid,remoteStartedAt:n.startedAt,chunks:[{index:1,path:t.outPath,remotePath:n.remotePath}],...t,startedAt:n.startedAt}}function Dn(e){let{activeSession:t,sessionName:n,device:r,recording:i,recordingSize:a,quality:o}=e;at({recording:i,finishCurrentChunk:async e=>await On({device:r,recording:i,remotePath:e.remotePath,remotePid:e.remotePid,waitForRemoteFileStability:!1}),cleanupStartedChunk:async e=>{await K(r.id,e.remotePath)},startNextChunk:async(e,s)=>{let c=await Cn({device:r,recordingSize:a,quality:o,preferredRemoteDir:e,hooks:{prepareRemotePath:async e=>await Qt({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:i,nextRemotePath:e,nextIndex:s}),cleanupPreparedRemotePath:async()=>{await z({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:i})}}});if(`error`in c)throw Error(c.error.ok?`failed to start next Android recording chunk`:c.error.error.message);return c},persistRecordingState:async e=>{let i=await z({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:e});if(i)throw Error(i)}})}async function On(e){let{device:t,recording:n,remotePath:i=n.remotePath,remotePid:a=n.remotePid,waitForRemoteFileStability:o=!0}=e;if(!a){Ln(n,it(n)),o&&await gn(t.id,i);return}await G(t.id,a)||Ln(n,it(n));let s=await W(t.id,[`shell`,`kill`,`-2`,a],{allowFailure:!0,timeoutMs:U});if(r({level:`debug`,phase:`record_stop_android_signal`,data:{deviceId:t.id,remotePath:i,remotePid:a,exitCode:s.exitCode,stdout:s.stdout.trim(),stderr:s.stderr.trim()}}),s.exitCode!==0)return await kn(t.id,a,s);let c=await An(t.id,a);if(c)return c;o&&await gn(t.id,i)}async function kn(e,t,n){if(await G(e,t)&&!await q(e,t))return`failed to stop recording: ${D(n,`adb shell kill`)}`}async function An(e,t){if(!await hn(e,t)&&!await q(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function jn(e){let{deps:t,device:n,recording:i,stopRequestedAt:a}=e;r({level:`debug`,phase:`record_stop_android_enter`,data:{deviceId:n.id,remotePath:i.remotePath,remotePid:i.remotePid}}),i.stopping=!0,await Mn(i);let o=await On({device:n,recording:i});i.rotationFailedReason&&!o&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`);let s=o===void 0?await Nn({deps:t,device:n,recording:i}):void 0,c=await Pn({deviceId:n.id,recording:i,recordCleanupError:o===void 0});return s?v(`COMMAND_FAILED`,In(s,i,a)):o?v(`COMMAND_FAILED`,In(o,i,a)):c?v(`COMMAND_FAILED`,c):null}async function Mn(e){e.rotationTimer&&=(clearTimeout(e.rotationTimer),void 0),await e.rotationPromise}async function Nn(e){let{deps:t,device:n,recording:r}=e,i=await mt({deps:t,deviceId:n.id,chunks:A(r)});if(i)return i;await pt({recording:r,deps:t})}async function Pn(e){let{deviceId:t,recording:n,recordCleanupError:r}=e,i;for(let e of A(n)){let n=await Fn(t,e.remotePath);n&&r&&(i=n)}return await V(t),i}async function Fn(e,t){let n=await W(e,[`shell`,`rm`,`-f`,t],{allowFailure:!0,timeoutMs:U});if(r({level:`debug`,phase:`record_stop_android_cleanup`,data:{deviceId:e,remotePath:t,exitCode:n.exitCode,stdout:n.stdout.trim(),stderr:n.stderr.trim()}}),n.exitCode!==0)return`failed to clean up remote recording: ${D(n,`adb shell rm`)}`}function In(e,t,n){return rt(e,t,n).message}function Ln(e,t){!t||e.warning?.includes(t)||(e.warning=e.warning?`${e.warning} ${t}`:t)}function J(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function Rn(e){return E(e).toLowerCase().includes(`recording already in progress`)}function zn(e,n,r){return e.toArray().find(e=>e.name!==r&&t(e.device)&&e.device.kind===`device`&&e.device.id===n&&e.recording?.platform===`ios-device-runner`)}function Y(e,t,n){return ge({req:e,logPath:t,traceLogPath:n.trace?.outPath})}function Bn(e){return typeof e.runnerStartedAtUptimeMs!=`number`||typeof e.targetAppReadyUptimeMs!=`number`?0:Math.max(0,e.targetAppReadyUptimeMs-e.runnerStartedAtUptimeMs)}async function Vn(e){let{req:t,activeSession:n,device:i,logPath:a,deps:o}=e,s=J(n);try{await o.runAppleRunnerCommand(i,{command:`recordStop`,appBundleId:s},Y(t,a,n))}catch(e){r({level:`warn`,phase:`record_stop_runner_failed`,data:{platform:i.platform,kind:i.kind,deviceId:i.id,session:n.name,error:E(e)}})}}async function Hn(e){let{req:t,activeSession:n,device:i,logPath:a,deps:o}=e,s=J(n);if(s)try{let e=await o.runAppleRunnerCommand(i,{command:`snapshot`,appBundleId:s,interactiveOnly:!0,depth:1},Y(t,a,n)),c=Date.now();return typeof e.currentUptimeMs==`number`&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0?(r({level:`debug`,phase:`record_start_gesture_clock_anchor`,data:{source:`warm_snapshot`}}),{gestureClockOriginAtMs:c,gestureClockOriginUptimeMs:e.currentUptimeMs}):void 0}catch(e){r({level:`warn`,phase:`record_start_simulator_runner_warm_failed`,data:{deviceId:i.id,session:n.name,appBundleId:s,error:E(e)}});return}}async function Un(e){let{req:t,activeSession:n,sessionStore:i,device:a,logPath:o,deps:s,fpsFlag:c,recordingBase:l,appBundleId:u}=e,d=`agent-device-recording-${Date.now()}.mp4`,f=`tmp/${d}`,p=Y(t,o,n),m,h,g=async()=>s.runAppleRunnerCommand(a,{command:`recordStart`,outPath:d,fps:c,maxSize:l.maxSize,appBundleId:u},p);try{let e=await g();m=typeof e.recorderStartUptimeMs==`number`?e.recorderStartUptimeMs:void 0,h=typeof e.targetAppReadyUptimeMs==`number`?e.targetAppReadyUptimeMs:void 0}catch(e){if(!Rn(e))return v(`COMMAND_FAILED`,`failed to start recording: ${E(e)}`);r({level:`warn`,phase:`record_start_runner_desynced`,data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:n.name,error:E(e)}});let t=zn(i,a.id,n.name);if(t)return v(`COMMAND_FAILED`,`failed to start recording: recording already in progress in session '${t.name}'`);try{await s.runAppleRunnerCommand(a,{command:`recordStop`,appBundleId:u},p)}catch{}try{let e=await g();m=typeof e.recorderStartUptimeMs==`number`?e.recorderStartUptimeMs:void 0,h=typeof e.targetAppReadyUptimeMs==`number`?e.targetAppReadyUptimeMs:void 0}catch(e){return v(`COMMAND_FAILED`,`failed to start recording: ${E(e)}`)}}return{platform:`ios-device-runner`,remotePath:f,runnerStartedAtUptimeMs:m,targetAppReadyUptimeMs:h,...l}}async function Wn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s,appBundleId:c}=e;try{await a.runAppleRunnerCommand(r,{command:`recordStart`,outPath:s.outPath,fps:o,maxSize:s.maxSize,appBundleId:c},Y(t,i,n))}catch(e){return v(`COMMAND_FAILED`,`failed to start recording: ${E(e)}`)}return{platform:`macos-runner`,...s}}async function Gn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;await Vn({req:t,activeSession:n,device:r,logPath:i,deps:a});let s={stdout:``,stderr:``,exitCode:1};for(let e of ie)if(s=await a.runCmd(`xcrun`,[`devicectl`,`device`,`copy`,`from`,`--device`,r.id,`--source`,o.remotePath,`--destination`,o.outPath,`--domain-type`,`appDataContainer`,`--domain-identifier`,e],{allowFailure:!0}),s.exitCode===0)break;if(s.exitCode!==0)return v(`COMMAND_FAILED`,`failed to copy recording from device: ${s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`}`);let c=Bn(o);return c>0&&await a.trimRecordingStart({videoPath:o.outPath,trimStartMs:c}),await O({recording:o,deps:a,trimStartMs:c,targetLabel:`iOS recording`}),null}async function Kn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;return await Vn({req:t,activeSession:n,device:r,logPath:i,deps:a}),await O({recording:o,deps:a,targetLabel:`macOS recording`}),null}const qn=5e3,Jn=2e3;async function Yn(e){let{deps:t,recording:n}=e;n.child.kill(`SIGINT`);let r=await X(n.wait,qn);return r||(await Z(t,n,`SIGINT`),r=await X(n.wait,Jn),r)||(n.child.kill(`SIGTERM`),await Z(t,n,`SIGTERM`),r=await X(n.wait,Jn),r)?r:(n.child.kill(`SIGKILL`),await Z(t,n,`SIGKILL`),await X(n.wait,Jn))}async function X(e,t){return await Promise.race([e,g(t).then(()=>null)])}async function Z(e,t,n){await Zn(e,t,n)||await Xn(e,t.outPath,n)}async function Xn(e,t,n){let i=`simctl.*recordVideo.*${er(t)}`,a;try{a=await e.runCmd(`pgrep`,[`-f`,i],{allowFailure:!0})}catch(e){r({level:`warn`,phase:`record_stop_ios_simulator_pgrep_failed`,data:{outPath:t,signal:n,error:E(e)}});return}let o=ee($n(a.stdout),{excludePid:process.pid}),s=ne(o,n);r({level:s>0?`warn`:`debug`,phase:`record_stop_ios_simulator_signal_recorders`,data:{outPath:t,signal:n,matchedPidCount:o.length,signaled:s,pgrepExitCode:a.exitCode}})}async function Zn(e,t,n){let i=t.recorderPid??t.child.pid;if(typeof i!=`number`||!Number.isInteger(i)||i<=0)return r({level:`debug`,phase:`record_stop_ios_simulator_owned_recorder_unavailable`,data:{outPath:t.outPath,signal:n,reason:`missing_recorder_pid`}}),!1;let a=await Qn(e,i,t.outPath,n),o=ee([i,...a.pids],{excludePid:process.pid}),s=ne(o,n);return r({level:s>0?`warn`:`debug`,phase:`record_stop_ios_simulator_signal_owned_recorder`,data:{outPath:t.outPath,signal:n,recorderPid:i,childPidCount:a.pids.length,matchedPidCount:o.length,signaled:s,pgrepExitCode:a.exitCode}}),s>0}async function Qn(e,t,n,i){let a;try{a=await e.runCmd(`pgrep`,[`-P`,String(t)],{allowFailure:!0})}catch(e){return r({level:`warn`,phase:`record_stop_ios_simulator_owned_pgrep_failed`,data:{outPath:n,signal:i,parentPid:t,error:E(e)}}),{pids:[]}}return{pids:$n(a.stdout),exitCode:a.exitCode}}function $n(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}function er(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async function tr(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recordingBase:o,resolvedOut:s}=e,c=o.showTouches?await Hn({req:t,activeSession:n,device:r,logPath:i,deps:a}):void 0,{child:l,wait:u}=a.startIosSimulatorRecording({device:r,outPath:s}),d=await rr(s),f,p;if(c)f=c.gestureClockOriginAtMs,p=c.gestureClockOriginUptimeMs;else if(o.showTouches)try{let e=Date.now(),o=await a.runAppleRunnerCommand(r,{command:`uptime`,appBundleId:J(n)},Y(t,i,n));f=Math.round((e+Date.now())/2),p=typeof o.currentUptimeMs==`number`?o.currentUptimeMs:void 0}catch{}return{platform:`ios`,child:l,wait:u,...o,recorderPid:l.pid,startedAt:d,gestureClockOriginAtMs:p===void 0?void 0:f,gestureClockOriginUptimeMs:p}}async function nr(e){let{deps:t,recording:r,stopRequestedAt:i}=e;await n(`record_stop_tail_settle`,()=>t.waitForRecordingTail(r),{platform:r.platform,gestureEventCount:r.gestureEvents.length});let a=await n(`record_stop_ios_simulator_process`,()=>Yn({deps:t,recording:r}),{outPath:r.outPath});if(!a)return ir(`failed to stop recording: simctl recordVideo did not exit after ${qn}ms and forced cleanup`,r,i);if(a.exitCode!==0)return ir(`failed to stop recording: ${D(a,`simctl recordVideo`)}`,r,i);if(await n(`record_stop_video_stable`,()=>t.waitForStableFile(r.outPath,{pollMs:150,attempts:12}),{outPath:r.outPath}),!await n(`record_stop_video_playable_check`,()=>t.isPlayableVideo(r.outPath),{outPath:r.outPath}))return ir(`failed to stop recording: ${r.outPath} was not finalized into a playable video`,r,i);if(r.maxSize!==void 0)try{await n(`record_stop_resize`,()=>t.resizeRecording({videoPath:r.outPath,maxSize:r.maxSize,exportQuality:r.exportQuality,targetLabel:`iOS recording`}),{outPath:r.outPath,maxSize:r.maxSize})}catch(e){r.overlayWarning=`failed to resize recording: ${E(e)}`}return await n(`record_stop_finalize_overlay`,()=>O({recording:r,deps:t,targetLabel:`iOS recording`}),{outPath:r.outPath,showTouches:r.showTouches,gestureEventCount:r.gestureEvents.length}),null}async function rr(e){for(let t=0;t<2;t+=1){try{if(b.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)return Date.now();await g(250)}return Date.now()}function ir(e,t,n){let r=rt(e,t,n);return ar(t.outPath),v(`COMMAND_FAILED`,r.message)}function ar(e){try{b.rmSync(e,{force:!0})}catch{}}le();function or(e){let t=fe(e.platform)?.recording?.resolveBackendTag(e)??`unsupported`;return mr[t]}function sr(e){let{recording:t}=e;switch(t.platform){case`android`:return pr.stop({...e,recording:t});case`ios`:return fr.stop({...e,recording:t});case`ios-device-runner`:return ur.stop({...e,recording:t});case`macos-runner`:return dr.stop({...e,recording:t});case`web`:return lr.stop({...e,recording:t})}return t}function Q({req:e}){return e.positionals?.[1]??f(void 0)}function cr({req:e}){let t=e.positionals?.[1];return t===void 0?f(`web`):d(t,p)}const lr={recordingBackend:`agent-browser recording`,validateStart:e=>_r(e),resolveOutputPath:cr,start:async({activeSession:e,recordingBase:t,resolvedOut:n})=>{let r=vr(n);if(r)return r;if(e.recordOnlySession)return v(`INVALID_ARGS`,`record on web requires an active browser session; run open <url> --platform web first`);let i=y();return i.startRecording?(await i.startRecording(n),{...t,outPath:n,startedAt:Date.now(),platform:`web`,showTouches:!1}):v(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)},stop:async({recording:e})=>await xr({recording:e}),cleanupRecordOnlySession:async()=>{try{await y().close()}catch{}}},ur={recordingBackend:`runner AVAssetWriter`,resolveOutputPath:Q,start:async({req:e,activeSession:t,sessionStore:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s})=>{let c=J(t);return c?await Un({req:e,activeSession:t,sessionStore:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s,appBundleId:c}):v(`INVALID_ARGS`,`record on physical iOS devices requires an active app session; run open <app> first`)},stop:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})=>await Gn({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},dr={recordingBackend:`runner AVAssetWriter`,resolveOutputPath:Q,start:async({req:e,activeSession:t,device:n,logPath:r,deps:i,fpsFlag:a,recordingBase:o})=>{let s=J(t);return s?await Wn({req:e,activeSession:t,device:n,logPath:r,deps:i,fpsFlag:a,recordingBase:o,appBundleId:s}):v(`INVALID_ARGS`,`record on macOS requires an active app session; run open <app> first`)},stop:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})=>await Kn({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},fr={recordingBackend:`simctl recordVideo`,resolveOutputPath:Q,start:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:o})=>{let c=J(t),l=!s(a.recordingScope??`app`);return l&&!c?v(`INVALID_ARGS`,`record on iOS Simulator with app scope requires an active app session; run open <app> first, or use --scope device to record the full simulator screen`):l&&c&&yr(c)?v(`INVALID_ARGS`,`record on iOS Simulator cannot use Agent Device Runner as the active app session; run open <app> first`):await tr({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:o})},stop:async({deps:e,recording:t,stopRequestedAt:n})=>await nr({deps:e,recording:t,stopRequestedAt:n})},pr={recordingBackend:`adb screenrecord`,resolveOutputPath:Q,start:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await Tn({sessionName:e,activeSession:t,device:n,recordingBase:r}),recoverMissingStop:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await en({sessionName:e,activeSession:t,device:n,recordingBase:r}),stop:async({deps:e,device:t,recording:n,stopRequestedAt:r})=>await jn({deps:e,device:t,recording:n,stopRequestedAt:r})},mr={web:lr,android:pr,macos:dr,"ios-device":ur,"ios-simulator":fr,unsupported:{recordingBackend:`unsupported`,resolveOutputPath:Q,start:async()=>v(`UNSUPPORTED_OPERATION`,`record is not supported on this device`),stop:async()=>v(`UNSUPPORTED_OPERATION`,`record is not supported on this device`)}},hr=[[`fps`,`--fps`],[`quality`,`--quality`],[`screenshotMaxSize`,`--max-size`],[`hideTouches`,`--hide-touches`]];function gr(e){let t=e.flags??{},n=hr.flatMap(([e,n])=>t[e]===void 0?[]:[n]);return s(t.recordingScope??`app`)?[...n,`--scope`]:n}function _r(e){let t=gr(e);return t.length>0?v(`INVALID_ARGS`,`web recordings do not support ${t.join(`, `)}; agent-browser records WebM directly`):null}function vr(e){return x.extname(e).toLowerCase()===`.webm`?null:v(`INVALID_ARGS`,`web recordings must use a ${p} output path`)}function yr(e){return ie.includes(e)}function br(e){try{b.rmSync(e,{force:!0})}catch{}}async function xr(e){let{recording:t}=e,n=y();return n.stopRecording?(await n.stopRecording(),Sr(t.outPath)?null:(br(t.outPath),v(`COMMAND_FAILED`,`failed to stop recording: ${t.outPath} was not finalized into a WebM video`))):v(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)}function Sr(e){try{return b.statSync(e).size>0}catch{return!1}}function Cr(){return{runCmd:async(e,t,n)=>e===`xcrun`?await oe(t,n):await a(e,t,n),startIosSimulatorRecording:e=>ve().startIosSimulatorRecording(e),runAppleRunnerCommand:ae,waitForRecordingTail:wr,waitForStableFile:je,isPlayableVideo:Me,trimRecordingStart:$e,resizeRecording:tt,overlayRecordingTouches:et}}async function wr(e){e.platform===`ios`&&e.gestureEvents.length!==0&&await g(350)}function Tr(e){let{req:t,outPath:n,activeSession:r,recordingBackend:i,recordingScope:a}=e,o=c(t.flags?.quality);return{outPath:n,clientOutPath:t.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),recordingScope:a,recordingBackend:i,recordOnlySession:r.recordOnlySession===!0,activeSessionApp:r.appBundleId?{bundleId:r.appBundleId,...r.appName?{name:r.appName}:{}}:void 0,maxSize:t.flags?.screenshotMaxSize,exportQuality:o??`medium`,showTouches:t.flags?.hideTouches!==!0,gestureEvents:[]}}async function Er(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e,c=Dr(e);return`backend`in c?kr({req:t,sessionName:n,sessionStore:r,activeSession:i,recording:await c.backend.start({req:t,sessionName:n,activeSession:i,sessionStore:r,device:a,logPath:o,deps:s,fpsFlag:c.fpsFlag,recordingBase:c.recordingBase,resolvedOut:c.resolvedOut}),outPath:c.outPath}):c}function Dr(e){let{req:t,activeSession:n,device:r,recordingScope:i}=e,a=or(r);return Or({req:t,activeSession:n,device:r,backend:a})||{...Fr(t,a,n,i),backend:a,fpsFlag:t.flags?.fps}}function Or(e){let{req:t,activeSession:n,device:r,backend:i}=e,a=[()=>Ar(n),()=>i.validateStart?.(t)??null,()=>jr({fpsFlag:t.flags?.fps,qualityFlag:t.flags?.quality,maxSizeFlag:t.flags?.screenshotMaxSize}),()=>pe(`record`,r)];for(let e of a){let t=e();if(t)return t}return null}function kr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,recording:a,outPath:o}=e;if(`ok`in a)return a;i.recording=a,r.set(n,i);let s=r.ensureSessionDir(n);return _e(r,i,t,t.command,{action:`start`,showTouches:a.showTouches}),{ok:!0,data:{recording:`started`,outPath:a.clientOutPath??o,sessionStateDir:s,recordingBackend:a.recordingBackend,recordingScope:a.recordingScope,recordOnlySession:a.recordOnlySession,activeSessionApp:a.activeSessionApp,showTouches:a.showTouches}}}function Ar(e){return e.recording?v(`INVALID_ARGS`,`recording already in progress`):null}function jr(e){let{fpsFlag:t,qualityFlag:n,maxSizeFlag:r}=e;return Mr(t)??Nr(n)??Pr(r)}function Mr(e){return e!==void 0&&(!Number.isInteger(e)||e<1||e>120)?v(`INVALID_ARGS`,`fps must be an integer between 1 and 120`):null}function Nr(e){return e!==void 0&&c(e)===void 0?v(`INVALID_ARGS`,`quality must be one of: ${u.join(`, `)} (legacy numeric values 5-10 are accepted)`):null}function Pr(e){return e!==void 0&&(!Number.isInteger(e)||e<1)?v(`INVALID_ARGS`,`max-size must be a positive integer`):null}function Fr(e,t,n,r){let i=t.resolveOutputPath({req:e}),a=me.expandHome(i,e.meta?.cwd),o=Tr({req:e,outPath:a,activeSession:n,recordingBackend:t.recordingBackend,recordingScope:r});return b.mkdirSync(x.dirname(a),{recursive:!0}),b.rmSync(a,{force:!0}),{outPath:i,resolvedOut:a,recordingBase:o}}async function Ir(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a}=e,o=await Lr(e);if(o&&`ok`in o)return o;if(!o)return v(`INVALID_ARGS`,`no active recording`);let s=Date.now(),c=o.invalidatedReason;return n.recording=void 0,await sr({req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o,stopRequestedAt:s})||Vr(o,c)||Ur(o)}async function Lr(e){return e.activeSession.recording?e.activeSession.recording:await Rr(e)}async function Rr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e;if(Hr(r,a.id))return null;let c=or(a);if(!c.recoverMissingStop)return null;let{resolvedOut:l,recordingBase:u}=zr(t,c,i),d=await c.recoverMissingStop({req:t,sessionName:n,activeSession:i,sessionStore:r,device:a,logPath:o,deps:s,recordingBase:u,resolvedOut:l});return d?(`ok`in d||Br(l),d):null}function zr(e,t,n){let r=t.resolveOutputPath({req:e}),i=me.expandHome(r,e.meta?.cwd);return{resolvedOut:i,recordingBase:Tr({req:e,outPath:i,activeSession:n,recordingBackend:t.recordingBackend,recordingScope:n.recording?.recordingScope??`app`})}}function Br(e){b.mkdirSync(x.dirname(e),{recursive:!0}),b.rmSync(e,{force:!0})}function Vr(e,t){return t?e.platform===`ios`&&e.showTouches?(e.overlayWarning??=`overlay unavailable: ${t}`,null):v(`COMMAND_FAILED`,t):null}function Hr(e,t){for(let n of e.values())if(n.recording&&n.device.id===t)return!0;return!1}function Ur(e){let t=e.platform===`android`?e.chunks:void 0,n=[{field:`outPath`,artifactType:`screen-recording`,path:e.outPath,localPath:e.clientOutPath,fileName:x.basename(e.clientOutPath??e.outPath)}];return t&&t.length>1&&n.push(...t.slice(1).map(t=>({field:`chunkPath`,artifactType:`screen-recording-chunk`,path:t.path,localPath:$(e,t.index),fileName:x.basename($(e,t.index)??t.path)}))),e.telemetryPath&&n.push({field:`telemetryPath`,artifactType:`screen-recording-telemetry`,path:e.telemetryPath,localPath:Wr(e),fileName:x.basename(e.telemetryPath)}),{ok:!0,data:{recording:`stopped`,outPath:e.outPath,telemetryPath:e.telemetryPath,artifacts:n,recordingBackend:e.recordingBackend,recordingScope:e.recordingScope,recordOnlySession:e.recordOnlySession,activeSessionApp:e.activeSessionApp,durationMs:Date.now()-e.startedAt,showTouches:e.showTouches,warning:e.warning,overlayWarning:e.overlayWarning,chunks:t?.map(t=>({index:t.index,path:$(e,t.index)??t.path}))}}}function $(e,t){if(!(e.platform!==`android`||!e.clientOutPath))return k(e.clientOutPath,t)}function Wr(e){if(e.clientOutPath)return ze(e.clientOutPath)}async function Gr(e,t,n,r={}){n.recordOnlySession&&(await or(n.device).cleanupRecordOnlySession?.(n),r.writeLog&&e.writeSessionLog(n),e.delete(t))}async function Kr(e){let{req:t,sessionName:n,sessionStore:r,logPath:i}=e,a=Cr(),o=r.get(n),c=(t.positionals?.[0]??``).toLowerCase();if(![`start`,`stop`].includes(c))return v(`INVALID_ARGS`,`record requires start|stop`);let l=qr(t);if(typeof l==`object`)return l;if(c===`start`&&!o&&!s(l))return v(`INVALID_ARGS`,ce(t)?`record start with app scope and an explicit session requires an active app session; run open <app> first, or use --scope device to record the full screen`:`record start defaults to app scope and requires an active app session; run open <app> first, or use --scope device to record the full screen`);let u=o?.device??await ue(t.flags??{});o||await he(u);let d=o??{name:n,sessionScope:de(t),device:u,createdAt:Date.now(),recordOnlySession:!0,actions:[]};if(c===`start`)return Er({req:t,sessionName:n,sessionStore:r,activeSession:d,device:u,recordingScope:l,logPath:i,deps:a});let f=await Ir({req:t,sessionName:n,sessionStore:r,activeSession:d,device:u,logPath:i,deps:a});return f.ok?(_e(r,d,t,t.command,{action:`stop`,outPath:f.data?.outPath,showTouches:f.data?.showTouches}),await Gr(r,n,d,{writeLog:!0}),f):(await Gr(r,n,d),f)}function qr(e){let t=e.flags?.recordingScope;return t===void 0?`app`:Jr(t)?t:v(`INVALID_ARGS`,`record scope must be one of: ${o.join(`, `)}`)}function Jr(e){return typeof e==`string`&&o.includes(e)}export{Kr as t};
23
+ exit(exitCode)`,cacheName:`video-validator`,timeoutMs:3e4});try{return await ke}catch(e){throw ke=void 0,e}}function Ne(t){return t instanceof e?t.code===`TOOL_MISSING`?!0:Fe(String(t.details?.stderr??``),String(t.details?.stdout??``)):!1}async function Pe(e,t={}){let n=t.pollMs??150,r=t.attempts??12;for(let t=0;t<r;t+=1){if(await je(e))return;await h(n)}}function Fe(e,t){let n=`${e}\n${t}`;return/\b(no such module ['"]AVFoundation['"]|unable to find utility ["']swiftc?["']|xcrun: error: unable to find utility ["']swiftc?["'])\b/i.test(n)}function Ie(e){try{let t=b.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=Le(e);return t.includes(`ftyp`)&&t.includes(`moov`)}function Le(e){try{let t=b.openSync(e,`r`);try{let e=b.fstatSync(t).size,n=0,r=[];for(;n+8<=e&&r.length<16;){let e=Buffer.alloc(8);if(b.readSync(t,e,0,8,n)<8)break;let i=e.readUInt32BE(0),a=e.toString(`latin1`,4,8);if(r.push(a),i===1){let e=Buffer.alloc(8);if(b.readSync(t,e,0,8,n+8)<8)break;i=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(i)||i<=0)break;n+=i}return r}finally{b.closeSync(t)}}catch{return[]}}function Re(e){let t=x.parse(e);return x.join(t.dir,`${t.name}.gesture-telemetry.json`)}function ze(e,t){return Be(t>0?e.flatMap(e=>{let n=e.tMs-t,r=`durationMs`in e?e.durationMs:void 0;return(typeof r==`number`?n+r:n)<=0?[]:[{...e,tMs:Math.max(0,n)}]}):e)}function Be(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function Ve(e){let t=Re(e.videoPath),n={version:1,generatedAt:new Date().toISOString(),events:ze(e.events,e.trimStartMs??0)};return b.writeFileSync(t,JSON.stringify(n,null,2)),t}function He(e){let{recording:t,trimStartMs:n}=e,r=Ve({videoPath:t.outPath,events:t.gestureEvents,trimStartMs:n});return t.telemetryPath=r,r}function Ue(e,t,n,r){let i=`apple-runner/AgentDeviceRunner/RecordingScripts/${e}`,a=`dist/${i}`;return[x.resolve(t,e),x.resolve(n,i),x.resolve(t,`../${i}`),x.resolve(t,`../../${i}`),x.resolve(t,`../../../${i}`),x.resolve(n,a),x.resolve(r,i)]}function T(t){let n=Ue(t,x.dirname(Se(import.meta.url)),m(),process.cwd());for(let e of n)if(b.existsSync(e))return e;throw new e(`COMMAND_FAILED`,`Missing recording helper script: ${t}`,{hint:`Ensure apple-runner/AgentDeviceRunner/RecordingScripts is present in this checkout or bundled under dist/apple-runner in the package.`,scriptName:t,searchedPaths:n})}let We,Ge,Ke;function qe(e=process.platform){if(e!==`darwin`)return`touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry`}function Je(){return We??=T(`recording-overlay.swift`),We}function Ye(){return Ge??=T(`recording-trim.swift`),Ge}function Xe(){return Ke??=T(`recording-resize.swift`),Ke}async function E(t){let{videoPath:n,scriptPath:r,scriptArgs:a,commandDescription:o}=t;await Ae(n),await Pe(n);let s=Ze(n);try{await i(await Ce({sourcePath:r}),[`--input`,n,`--output`,s,...a],{timeoutMs:12e4,env:S()}),await Pe(s),b.renameSync(s,n)}catch(t){let i=t instanceof e?t:new e(`COMMAND_FAILED`,String(t),void 0,t instanceof Error?t:void 0);throw new e(`COMMAND_FAILED`,o,{...i.details,videoPath:n,script:r},i)}finally{b.rmSync(s,{force:!0})}}function Ze(e){let t=x.parse(e),n=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;return x.join(t.dir,`.${t.name}.agent-device-${n}${t.ext||`.mp4`}`)}async function Qe(e){let{videoPath:t,trimStartMs:n}=e;n>0&&await E({videoPath:t,scriptPath:Ye(),scriptArgs:[`--trim-start-ms`,String(n)],commandDescription:`Failed to trim the start of the iOS recording`})}async function $e(e){let{videoPath:t,telemetryPath:n,exportQuality:r=c,targetLabel:i=`recording`}=e;await E({videoPath:t,scriptPath:Je(),scriptArgs:[`--events`,n,`--quality`,r],commandDescription:`Failed to add touch overlays to the ${i}`})}async function et(e){let{videoPath:t,maxSize:n,exportQuality:r=c,targetLabel:i=`recording`}=e;await E({videoPath:t,scriptPath:Xe(),scriptArgs:[`--max-size`,String(n),`--quality`,r],commandDescription:`Failed to resize the ${i}`})}function D(e){return e instanceof Error?e.message:String(e)}const tt=1e3;function O(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function nt(e,t,n=Date.now()){let r=Math.max(0,n-t.startedAt);return r>=tt?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(r)}ms; wait at least ${tt}ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function k(e){let{recording:r,deps:i,trimStartMs:a,targetLabel:o}=e,s=He({recording:r,trimStartMs:a});if(!r.showTouches){n({level:`debug`,phase:`record_stop_overlay_skipped`,data:{reason:`hide_touches`}});return}if(r.gestureEvents.length===0){n({level:`debug`,phase:`record_stop_overlay_skipped`,data:{reason:`no_gesture_events`}});return}let c=qe();if(c){r.overlayWarning??=c;return}try{await t(`record_stop_overlay_export`,()=>i.overlayRecordingTouches({videoPath:r.outPath,telemetryPath:s,exportQuality:r.exportQuality,targetLabel:o}),{targetLabel:o,gestureEventCount:r.gestureEvents.length})}catch(e){r.overlayWarning??=`failed to overlay recording touches: ${D(e)}`}}function A(e,t){if(t===1)return e;let n=x.parse(e),r=n.ext||`.mp4`;return x.join(n.dir,`${n.name}.part-${String(t).padStart(3,`0`)}${r}`)}function j(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}function rt(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.`}function it(e){let{recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}=e,o=setTimeout(()=>{t.rotationPromise=at({recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}).catch(e=>{t.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{t.rotationPromise=void 0,!t.stopping&&!t.rotationFailedReason&&it({recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a})})},17e4);o.unref?.(),t.rotationTimer=o}async function at(e){let{recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}=e;if(t.stopping)return;let o=j(t),s=o.length+1,c={remotePath:t.remotePath,remotePid:t.remotePid,startedAt:t.remoteStartedAt??t.startedAt},l=await ot({recording:t,nextIndex:s,previousChunk:c,startNextChunk:n,finishCurrentChunk:r});if(!l)return;let{nextChunk:u,previousChunkFinished:d}=l;await ct({recording:t,chunks:o,nextChunk:u,nextIndex:s,previousState:st({recording:t,nextChunk:u}),finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}),!d&&await ut(r,c)}async function ot(e){let{recording:t,nextIndex:n,previousChunk:r,startNextChunk:i,finishCurrentChunk:a}=e,o=x.posix.dirname(t.remotePath);try{return{nextChunk:await i(o,n),previousChunkFinished:!1}}catch(e){let s=await a(r);if(s)throw Error(s);if(t.stopping)return;try{return{nextChunk:await i(o,n),previousChunkFinished:!0}}catch(t){throw t instanceof Error?t:e}}}function st(e){let{recording:t,nextChunk:n}=e,r={remotePath:t.remotePath,remotePid:t.remotePid,remoteStartedAt:t.remoteStartedAt};return t.remotePath=n.remotePath,t.remotePid=n.remotePid,t.remoteStartedAt=n.startedAt,r}async function ct(e){let{recording:t,chunks:n,nextChunk:r,nextIndex:i,previousState:a,finishCurrentChunk:o,cleanupStartedChunk:s,persistRecordingState:c}=e;n.push({index:i,path:A(t.outPath,i),remotePath:r.remotePath}),t.warning??=`Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks.`;try{await c?.(t)}catch(e){throw lt({recording:t,chunks:n,previousState:a}),await dt({nextChunk:r,finishCurrentChunk:o,cleanupStartedChunk:s})||e}}function lt(e){let{recording:t,chunks:n,previousState:r}=e;n.pop(),t.remotePath=r.remotePath,t.remotePid=r.remotePid,t.remoteStartedAt=r.remoteStartedAt}async function ut(e,t){let n=await e(t);if(n)throw Error(n)}async function dt(e){let{nextChunk:t,finishCurrentChunk:n,cleanupStartedChunk:r}=e,i;try{await ut(n,t)}catch(e){i=e}try{await r?.(t)}catch(e){i??=e}return i}async function ft(e){let{recording:t,deps:n}=e;if(j(t).length<=1){await k({recording:t,deps:n,targetLabel:`Android recording`});return}He({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 pt(e){for(let t of e.chunks){let n=await mt({deps:e.deps,deviceId:e.deviceId,remotePath:t.remotePath,outPath:t.path});if(n)return`failed to copy recording chunk ${t.index}: ${n}`}}async function mt(e){let{deps:t,deviceId:i,remotePath:a,outPath:o}=e,s;for(let e=0;e<2;e+=1){gt(o);let c=await r(a,o,{allowFailure:!0,device:_(i)});if(c.exitCode!==0)s=O(c,`adb pull`);else{await t.waitForStableFile(o,{pollMs:250,attempts:20});let r=await t.isPlayableVideo(o);if(n({level:`debug`,phase:`record_stop_android_pull_validation`,data:{deviceId:i,remotePath:a,outPath:o,attempt:e+1,fileSize:ht(o),playable:r}}),r)return;n({level:`warn`,phase:`record_stop_android_invalid_video_retry`,data:{deviceId:i,remotePath:a,outPath:o,attempt:e+1}})}e<1&&await h(750)}return s?`failed to copy recording from device: ${s}`:(gt(o),`failed to copy recording from device: pulled file is not a playable MP4`)}function ht(e){try{return b.statSync(e).size}catch{return 0}}function gt(e){try{b.rmSync(e,{force:!0})}catch{}}const _t=`agent-device-recording-active.json`,vt=[`/sdcard`,`/data/local/tmp`];function yt(e){let t=e.trim().match(/^(\d+)\s+.*\bscreenrecord\b.*(\/(?:sdcard|data\/local\/tmp)\/agent-device-recording-(\d+)\.mp4)(?:\s|$)/);if(!t)return;let[,n,r,i]=t;if(!n||!r)return;let a=Number(i);return{remotePid:n,remotePath:r,startedAt:Number.isFinite(a)?a:Date.now()}}function bt(e){let t=Et(e);if(!t)return{kind:`delete`};let n=Ot(t);if(!n)return{kind:`blocked`,reason:`unsupported_or_malformed_manifest`};let r=At(t.current),i=jt(t.pending),a=Mt(t.chunks);return a?!r&&!i?{kind:`blocked`,reason:`invalid_recording_state`}:{kind:`manifest`,manifest:{...n,sessionScope:Pt(t.sessionScope),current:r,pending:i,chunks:a}}:{kind:`blocked`,reason:`invalid_recording_chunks`}}function xt(e){return`${x.posix.dirname(e)}/${_t}`}function M(){return vt.map(e=>`${e}/${_t}`)}function St(e){let{deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}=e;return{version:1,sessionName:n,sessionScope:r,recordingId:i,deviceId:t,startedAt:a,showTouches:o,pending:{remotePath:s},chunks:[{index:1,remotePath:s}]}}function Ct(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i}=e;return{version:1,sessionName:n,sessionScope:r,recordingId:i.recordingId??`android-${i.remotePid}-${i.remoteStartedAt??i.startedAt}`,deviceId:t,startedAt:i.startedAt,showTouches:i.showTouches,current:{remotePath:i.remotePath,remotePid:i.remotePid,startedAt:i.remoteStartedAt??i.startedAt},chunks:Tt(i)}}function wt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return{...Ct({deviceId:t,sessionName:n,sessionScope:r,recording:i}),pending:{remotePath:a},chunks:Tt(i,{index:o,remotePath:a})}}function Tt(e,t){return[...e.chunks??[{index:1,remotePath:e.remotePath}],...t?[t]:[]].map(e=>({index:e.index,remotePath:e.remotePath}))}function Et(e){try{let t=JSON.parse(e);return Dt(t)?t:void 0}catch{return}}function Dt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Ot(e){if(e.version!==1)return;let t=kt(e);if(!t)return;let n=Ft(e.startedAt);if(n===void 0)return;let r=It(e.showTouches);if(r!==void 0)return{version:1,...t,startedAt:n,showTouches:r}}function kt(e){let t=N(e.sessionName),n=N(e.recordingId),r=N(e.deviceId);if(!(!t||!n||!r))return{sessionName:t,recordingId:n,deviceId:r}}function At(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.remotePid!=`string`||!/^\d+$/.test(t.remotePid)||typeof t.remotePath!=`string`||!P(t.remotePath)))return{remotePid:t.remotePid,remotePath:t.remotePath,startedAt:typeof t.startedAt==`number`&&Number.isFinite(t.startedAt)?t.startedAt:Date.now()}}function jt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.remotePath!=`string`||!P(t.remotePath)))return{remotePath:t.remotePath}}function Mt(e){if(!Array.isArray(e))return;let t=e.map(Nt).filter(e=>e!==void 0);return t.length>0&&t.length===e.length?t:void 0}function Nt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.index!=`number`||!Number.isInteger(t.index)||t.index<1||typeof t.remotePath!=`string`||!P(t.remotePath)))return{index:t.index,remotePath:t.remotePath}}function Pt(e){if(!e||typeof e!=`object`)return;let t=e;if(!(t.kind!==`cwd`||typeof t.id!=`string`))return{kind:`cwd`,id:t.id}}function N(e){return typeof e==`string`?e:void 0}function Ft(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function It(e){return typeof e==`boolean`?e:void 0}function P(e){return/^\/(?:sdcard|data\/local\/tmp)\/agent-device-recording-\d+\.mp4$/.test(e)}const Lt=`Recovered Android recording after daemon restart from durable device manifest.`,Rt=`touch overlay burn-in is unavailable after daemon restart because gesture telemetry is stored in daemon memory`,F=`Recovered Android recording after daemon restart from durable device manifest; the screenrecord process was no longer running, so the MP4 may be truncated.`,I=`Recovered Android recording from an interrupted chunk rotation; returning chunks known to be safely owned by the durable manifest.`,L=5e3;async function R(e,t,n){return await re(_(e),t,n)}async function zt(e){let t={live:[],uncertain:[],blocked:[]};for(let n of M()){let r=await R(e,[`shell`,`cat`,n],{allowFailure:!0,timeoutMs:L});if(r.exitCode!==0)continue;let i=bt(r.stdout);if(i.kind===`delete`){await U({deviceId:e,metadataPath:n,phase:`record_stop_android_recovery_metadata_invalid_cleanup_failed`});continue}if(i.kind===`blocked`){t.blocked.push({metadataPath:n,reason:i.reason});continue}let a=i.manifest;if(a.deviceId!==e){t.blocked.push({metadataPath:n,reason:`device_mismatch`});continue}let o=await Bt(e,a);if(o.kind===`live`){t.live.push(o.manifest);continue}if(o.kind===`uncertain`){t.uncertain.push(a);continue}await U({deviceId:e,metadataPath:n,phase:`record_stop_android_recovery_metadata_stale_cleanup_failed`})}return t}async function Bt(e,t){return t.pending?await Vt(e,t,t.pending):await Gt(e,t)}async function Vt(e,t,n){let r=await qt(e,n.remotePath);return Ut(t,r)||(t.current?await Ht(e,t,t.current,r):await Wt(e,t,n.remotePath,r))}async function Ht(e,t,n,r){let i=await Kt(e,n);return i===`uncertain`||r===`uncertain`?{kind:`uncertain`}:i===`stale`?{kind:`stale`}:z({manifest:t,current:n,chunks:Yt(t.chunks,n.remotePath),recoveryWarning:i===`finished`?`${I} ${F}`:I})}function Ut(e,t){if(!(!t||t===`uncertain`))return z({manifest:e,current:t,recoveryWarning:e.current?I:Lt})}async function Wt(e,t,n,r){return r===`uncertain`?{kind:`uncertain`}:await Jt(e,n)?z({manifest:t,current:{remotePath:n,remotePid:``,startedAt:t.startedAt},recoveryWarning:F}):{kind:`stale`}}async function Gt(e,t){if(!t.current)return{kind:`stale`};let n=await Kt(e,t.current);return n===`live`?z({manifest:t,current:t.current}):n===`finished`?z({manifest:t,current:t.current,recoveryWarning:F}):{kind:n}}function z(e){let{manifest:t,current:n,chunks:r,recoveryWarning:i}=e;return{kind:`live`,manifest:{...t,current:n,chunks:r??t.chunks,...i?{recoveryWarning:i}:{}}}}async function Kt(e,t){let r=await R(e,[`shell`,`ps`,`-o`,`pid=,args=`,`-p`,t.remotePid],{allowFailure:!0,timeoutMs:L});if(r.exitCode!==0)return n({level:`debug`,phase:`record_stop_android_recovery_metadata_probe_uncertain`,data:{deviceId:e,remotePid:t.remotePid,remotePath:t.remotePath,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),`uncertain`;let i=r.stdout.split(/\r?\n/),a=i.map(e=>e.trim()).find(e=>e.startsWith(t.remotePid));return i.map(yt).some(e=>e?.remotePid===t.remotePid&&e.remotePath===t.remotePath)?`live`:a?.includes(`screenrecord`)?`uncertain`:a?`stale`:await Jt(e,t.remotePath)?`finished`:`stale`}async function qt(e,t){let r=await R(e,[`shell`,`ps`,`-A`,`-o`,`pid=,args=`],{allowFailure:!0,timeoutMs:L});return r.exitCode===0?r.stdout.split(/\r?\n/).map(yt).find(e=>e?.remotePath===t):(n({level:`debug`,phase:`record_stop_android_recovery_ps_failed`,data:{deviceId:e,remotePath:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),`uncertain`)}async function Jt(e,t){let n=await R(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:L}),r=n.exitCode===0?Number(n.stdout.trim()):NaN;return Number.isFinite(r)&&r>=1}function Yt(e,t){let n=e.findIndex(e=>e.remotePath===t);return n>=0?e.slice(0,n+1):e}async function Xt(e){let{deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}=e;return await V({deviceId:t,manifest:St({deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}),phase:`record_start_android_recovery_metadata_failed`})}async function Zt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return await V({deviceId:t,manifest:wt({deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}),phase:`record_rotate_android_recovery_metadata_failed`})}async function B(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i}=e;return await V({deviceId:t,manifest:Ct({deviceId:t,sessionName:n,sessionScope:r,recording:i}),phase:`record_start_android_recovery_metadata_failed`})}async function V(e){let{deviceId:t,manifest:n,phase:r}=e,i=n.current?.remotePath??n.pending?.remotePath;if(!i)return`failed to write Android recording recovery manifest: missing path`;let a=xt(i),o=`${a}.tmp`,s=await R(t,[`shell`,`printf %s ${p(JSON.stringify(n))} > ${p(o)} && mv -f ${p(o)} ${p(a)}`],{allowFailure:!0,timeoutMs:L});if(s.exitCode!==0)return Qt({phase:r,deviceId:t,metadataPath:a,result:s}),await U({deviceId:t,metadataPath:o,phase:`${r}_tmp_cleanup_failed`}),`failed to write Android recording recovery manifest: ${O(s,`adb shell write recovery manifest`)}`;for(let e of M())e!==a&&await U({deviceId:t,metadataPath:e,phase:`record_start_android_recovery_metadata_stale_cleanup_failed`})}async function H(e){for(let t of M())await U({deviceId:e,metadataPath:t,phase:`record_stop_android_recovery_metadata_cleanup_failed`})}async function U(e){let{deviceId:t,metadataPath:n,phase:r}=e,i=await R(t,[`shell`,`rm`,`-f`,n],{allowFailure:!0,timeoutMs:L});i.exitCode!==0&&Qt({phase:r,deviceId:t,metadataPath:n,result:i})}function Qt(e){let{phase:t,deviceId:r,metadataPath:i,result:a}=e;n({level:`warn`,phase:t,data:{deviceId:r,metadataPath:i,exitCode:a.exitCode,stdout:a.stdout.trim(),stderr:a.stderr.trim()}})}async function $t(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a=await zt(r.id);return a.live.length>0?nn({sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a.live}):a.uncertain.length>0?en({sessionName:t,activeSession:n,manifests:a.uncertain}):a.blocked.length>0?tn(a.blocked):null}function en(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=an({sessionName:t,activeSession:n,manifests:r}),a={activeRecordings:i.activeRecordings,recoveryBlocked:`manifest_liveness_uncertain`,hint:`Retry record stop after the device responds. Android recording recovery requires a verified durable manifest.`};return i.kind===`owner-mismatch`?v(`INVALID_ARGS`,dn(r),a):i.kind===`ambiguous`?v(`INVALID_ARGS`,`multiple active Android recording manifests could not be verified; cannot safely recover missing recording state`,a):v(`INVALID_ARGS`,`active Android recording manifest could not be verified; retry record stop after the device responds`,a)}function tn(e){return v(`INVALID_ARGS`,`active Android recording manifest could not be validated`,{recoveryBlocked:`manifest_invalid_or_unsupported`,manifests:e,hint:`Retry with the same agent-device version that started the recording, or inspect and remove stale device recovery metadata after confirming no recording is active.`})}function nn(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a}=e,o=rn({sessionName:t,activeSession:n,manifests:a});return`ok`in o?o:(sn(r,o),cn(o,i))}function rn(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=an({sessionName:t,activeSession:n,manifests:r});return i.kind===`selected`?i.manifest:i.kind===`owner-mismatch`?v(`INVALID_ARGS`,dn(r),{activeRecordings:i.activeRecordings}):v(`INVALID_ARGS`,`multiple active Android recording manifests exist; cannot safely recover missing recording state`,{activeRecordings:i.activeRecordings})}function an(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=r.filter(e=>ln(e,t,n)),a=on(r);return i.length===0?{kind:`owner-mismatch`,activeRecordings:a}:i.length>1||r.length>1?{kind:`ambiguous`,activeRecordings:a}:{kind:`selected`,manifest:i[0],activeRecordings:a}}function on(e){return e.map(e=>({sessionName:e.sessionName,sessionScope:e.sessionScope,recordingId:e.recordingId,remotePid:e.current?.remotePid,remotePath:e.current?.remotePath??e.pending?.remotePath}))}function sn(e,t){n({level:`warn`,phase:`record_stop_android_recovered_missing_state`,data:{deviceId:e.id,sessionName:t.sessionName,recordingId:t.recordingId,remotePath:t.current.remotePath,remotePid:t.current.remotePid,chunks:t.chunks.length}})}function cn(e,t){let n=e.recoveryWarning??Lt;return{platform:`android`,recordingId:e.recordingId,remotePath:e.current.remotePath,remotePid:e.current.remotePid,remoteStartedAt:e.current.startedAt,chunks:e.chunks.map(e=>({index:e.index,path:A(t.outPath,e.index),remotePath:e.remotePath})),outPath:t.outPath,clientOutPath:t.clientOutPath,telemetryPath:t.telemetryPath,startedAt:e.startedAt,maxSize:t.maxSize,exportQuality:t.exportQuality,showTouches:!1,gestureEvents:[],warning:e.showTouches?`${n} ${Rt}.`:n,overlayWarning:e.showTouches?Rt:void 0}}function ln(e,t,n){return e.sessionName===t&&un(e.sessionScope,n.sessionScope)}function un(e,t){return!e&&!t?!0:!e||!t?!1:e.kind===t.kind&&e.id===t.id}function dn(e){if(e.length===1){let t=e[0];return t.sessionScope?`active Android recording belongs to session "${t.sessionName}" in ${t.sessionScope.kind} scope; retry record stop from the original working directory without --session to recover it`:`active Android recording belongs to session "${t.sessionName}"; run record stop --session ${t.sessionName} to recover it`}return`active Android recordings belong to other sessions; cannot safely recover missing recording state`}const fn={medium:8e6,high:2e7},W=5e3;async function G(e,t,n){return await re(_(e),t,n)}function pn(e){return e.split(/\r?\n/).map(e=>e.trim()).filter(e=>/^\d+$/.test(e)).at(-1)}async function K(e,t){let n=await G(e,[`shell`,`ps`,`-o`,`pid=`,`-p`,t],{allowFailure:!0,timeoutMs:W});return n.exitCode===0?n.stdout.split(/\s+/).map(e=>e.trim()).includes(t):!1}async function mn(e,t){for(let n=0;n<40;n+=1){if(!await K(e,t))return!0;await h(250)}return!await K(e,t)}async function hn(e,t){let n,r=0;for(let i=0;i<20;i+=1){let i=await G(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:W}),a=i.exitCode===0?i.stdout.trim():``;if(a.length>0&&a===n){if(r+=1,r>=4)return}else r=0;n=a,await h(250)}}async function gn(e,t,n){for(let r=0;r<8;r+=1){let i=await G(e,[`shell`,`stat`,`-c`,`%s`,t],{allowFailure:!0,timeoutMs:W}),a=i.exitCode===0?Number(i.stdout.trim()):NaN;if(Number.isFinite(a)&&a>0)return!0;if(!await K(e,n))return!1;if(r+1>=2)return!0;await h(250)}return!1}function _n(e,t){let n=`agent-device-recording-${e}.mp4`,r=[`/sdcard`,`/data/local/tmp`];return(t&&r.includes(t)?[t,...r.filter(e=>e!==t)]:r).map(e=>`${e}/${n}`)}async function vn(e){let{deviceId:t,maxSize:n}=e;if(n===void 0)return;let r=await G(t,[`shell`,`wm`,`size`],{allowFailure:!0,timeoutMs:W}),i=r.stdout.match(/Override size:\s*(\d+)x(\d+)/)??r.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(r.exitCode!==0||!i)throw Error(`failed to resolve Android screen size for recording max-size: ${O(r,`adb shell wm size`)}`);return yn({width:Number(i[1]),height:Number(i[2]),maxSize:n})}function yn(e){let t=Math.max(e.width,e.height);if(t<=e.maxSize)return{width:e.width,height:e.height};let n=e.maxSize/t;return{width:bn(e.width,n),height:bn(e.height,n)}}function bn(e,t){return Math.max(2,Math.round(e*t/2)*2)}function xn(e,t,n){let r=[`screenrecord`];return t&&r.push(`--size`,`${t.width}x${t.height}`),r.push(`--bit-rate`,String(fn[n])),r.push(e),`${r.join(` `)} >/dev/null 2>&1 & echo $!`}async function q(e,t){await G(e,[`shell`,`rm`,`-f`,t],{allowFailure:!0,timeoutMs:W})}async function J(e,t){let r=await G(e,[`shell`,`kill`,`-9`,t],{allowFailure:!0,timeoutMs:W});return n({level:`warn`,phase:`record_stop_android_force_signal`,data:{deviceId:e,remotePid:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),r.exitCode!==0&&await K(e,t)?!1:await mn(e,t)}async function Sn(e){let{device:t,recordingSize:n,quality:r,preferredRemoteDir:i,hooks:a}=e,o=`failed to start recording: Android screenrecord did not begin producing frames`;for(let e of _n(Date.now(),i)){let i=await Cn({device:t,recordingSize:n,quality:r,remotePath:e,hooks:a});if(i.kind===`started`)return i.chunk;o=i.message}return{error:v(`COMMAND_FAILED`,o)}}async function Cn(e){let{device:t,recordingSize:r,quality:i,remotePath:a,hooks:o}=e,s=await o?.prepareRemotePath?.(a);if(s)return{kind:`failed`,message:s};let c=await G(t.id,[`shell`,xn(a,r,i)],{allowFailure:!0,timeoutMs:W});if(c.exitCode!==0)return await o?.cleanupPreparedRemotePath?.(a),{kind:`failed`,message:`failed to start recording: ${O(c,`adb shell screenrecord`)}`};let l=pn(c.stdout);return l?(n({level:`debug`,phase:`record_start_android_started`,data:{deviceId:t.id,remotePath:a,remotePid:l}}),await gn(t.id,a,l)?{kind:`started`,chunk:{remotePath:a,remotePid:l,startedAt:Date.now()}}:(await J(t.id,l),await o?.cleanupPreparedRemotePath?.(a),await q(t.id,a),{kind:`failed`,message:`failed to start recording: Android screenrecord did not begin producing frames`})):(await o?.cleanupPreparedRemotePath?.(a),await q(t.id,a),{kind:`failed`,message:`failed to start recording: adb did not return a valid Android screenrecord pid`})}async function wn(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a;try{a=await vn({deviceId:r.id,maxSize:i.maxSize})}catch(e){return v(`COMMAND_FAILED`,e instanceof Error?e.message:String(e))}let o=i.exportQuality??`medium`,s=be(),c=await Sn({device:r,recordingSize:a,quality:o,hooks:{prepareRemotePath:async e=>await Xt({deviceId:r.id,sessionName:t,sessionScope:n.sessionScope,recordingId:s,startedAt:i.startedAt,showTouches:i.showTouches,remotePath:e}),cleanupPreparedRemotePath:async()=>{await H(r.id)}}});if(`error`in c)return c.error;let l=Tn({recordingBase:i,chunk:c,recordingId:s}),u=await B({deviceId:r.id,sessionName:t,sessionScope:n.sessionScope,recording:l});return u?(await J(r.id,l.remotePid),await q(r.id,l.remotePath),await H(r.id),v(`COMMAND_FAILED`,`failed to start recording: ${u}`)):(En({activeSession:n,sessionName:t,device:r,recording:l,recordingSize:a,quality:o}),l)}function Tn(e){let{recordingBase:t,chunk:n,recordingId:r}=e;return{platform:`android`,recordingId:r,remotePath:n.remotePath,remotePid:n.remotePid,remoteStartedAt:n.startedAt,chunks:[{index:1,path:t.outPath,remotePath:n.remotePath}],...t,startedAt:n.startedAt}}function En(e){let{activeSession:t,sessionName:n,device:r,recording:i,recordingSize:a,quality:o}=e;it({recording:i,finishCurrentChunk:async e=>await Dn({device:r,recording:i,remotePath:e.remotePath,remotePid:e.remotePid,waitForRemoteFileStability:!1}),cleanupStartedChunk:async e=>{await q(r.id,e.remotePath)},startNextChunk:async(e,s)=>{let c=await Sn({device:r,recordingSize:a,quality:o,preferredRemoteDir:e,hooks:{prepareRemotePath:async e=>await Zt({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:i,nextRemotePath:e,nextIndex:s}),cleanupPreparedRemotePath:async()=>{await B({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:i})}}});if(`error`in c)throw Error(c.error.ok?`failed to start next Android recording chunk`:c.error.error.message);return c},persistRecordingState:async e=>{let i=await B({deviceId:r.id,sessionName:n,sessionScope:t.sessionScope,recording:e});if(i)throw Error(i)}})}async function Dn(e){let{device:t,recording:r,remotePath:i=r.remotePath,remotePid:a=r.remotePid,waitForRemoteFileStability:o=!0}=e;if(!a){In(r,rt(r)),o&&await hn(t.id,i);return}await K(t.id,a)||In(r,rt(r));let s=await G(t.id,[`shell`,`kill`,`-2`,a],{allowFailure:!0,timeoutMs:W});if(n({level:`debug`,phase:`record_stop_android_signal`,data:{deviceId:t.id,remotePath:i,remotePid:a,exitCode:s.exitCode,stdout:s.stdout.trim(),stderr:s.stderr.trim()}}),s.exitCode!==0)return await On(t.id,a,s);let c=await kn(t.id,a);if(c)return c;o&&await hn(t.id,i)}async function On(e,t,n){if(await K(e,t)&&!await J(e,t))return`failed to stop recording: ${O(n,`adb shell kill`)}`}async function kn(e,t){if(!await mn(e,t)&&!await J(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function An(e){let{deps:t,device:r,recording:i,stopRequestedAt:a}=e;n({level:`debug`,phase:`record_stop_android_enter`,data:{deviceId:r.id,remotePath:i.remotePath,remotePid:i.remotePid}}),i.stopping=!0,await jn(i);let o=await Dn({device:r,recording:i});i.rotationFailedReason&&!o&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`);let s=o===void 0?await Mn({deps:t,device:r,recording:i}):void 0,c=await Nn({deviceId:r.id,recording:i,recordCleanupError:o===void 0});return s?v(`COMMAND_FAILED`,Fn(s,i,a)):o?v(`COMMAND_FAILED`,Fn(o,i,a)):c?v(`COMMAND_FAILED`,c):null}async function jn(e){e.rotationTimer&&=(clearTimeout(e.rotationTimer),void 0),await e.rotationPromise}async function Mn(e){let{deps:t,device:n,recording:r}=e,i=await pt({deps:t,deviceId:n.id,chunks:j(r)});if(i)return i;await ft({recording:r,deps:t})}async function Nn(e){let{deviceId:t,recording:n,recordCleanupError:r}=e,i;for(let e of j(n)){let n=await Pn(t,e.remotePath);n&&r&&(i=n)}return await H(t),i}async function Pn(e,t){let r=await G(e,[`shell`,`rm`,`-f`,t],{allowFailure:!0,timeoutMs:W});if(n({level:`debug`,phase:`record_stop_android_cleanup`,data:{deviceId:e,remotePath:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),r.exitCode!==0)return`failed to clean up remote recording: ${O(r,`adb shell rm`)}`}function Fn(e,t,n){return nt(e,t,n).message}function In(e,t){!t||e.warning?.includes(t)||(e.warning=e.warning?`${e.warning} ${t}`:t)}function Y(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function Ln(e){return D(e).toLowerCase().includes(`recording already in progress`)}function Rn(e,t,n){return e.toArray().find(e=>e.name!==n&&ne(e.device)&&e.device.kind===`device`&&e.device.id===t&&e.recording?.platform===`ios-device-runner`)}function X(e,t,n){return ge({req:e,logPath:t,traceLogPath:n.trace?.outPath})}function zn(e){return typeof e.runnerStartedAtUptimeMs!=`number`||typeof e.targetAppReadyUptimeMs!=`number`?0:Math.max(0,e.targetAppReadyUptimeMs-e.runnerStartedAtUptimeMs)}async function Bn(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,s=Y(r);try{await o.runAppleRunnerCommand(i,{command:`recordStop`,appBundleId:s},X(t,a,r))}catch(e){n({level:`warn`,phase:`record_stop_runner_failed`,data:{platform:i.platform,kind:i.kind,deviceId:i.id,session:r.name,error:D(e)}})}}async function Vn(e){let{req:t,activeSession:r,device:i,logPath:a,deps:o}=e,s=Y(r);if(s)try{let e=await o.runAppleRunnerCommand(i,{command:`snapshot`,appBundleId:s,interactiveOnly:!0,depth:1},X(t,a,r)),c=Date.now();return typeof e.currentUptimeMs==`number`&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0?(n({level:`debug`,phase:`record_start_gesture_clock_anchor`,data:{source:`warm_snapshot`}}),{gestureClockOriginAtMs:c,gestureClockOriginUptimeMs:e.currentUptimeMs}):void 0}catch(e){n({level:`warn`,phase:`record_start_simulator_runner_warm_failed`,data:{deviceId:i.id,session:r.name,appBundleId:s,error:D(e)}});return}}async function Hn(e){let{req:t,activeSession:r,sessionStore:i,device:a,logPath:o,deps:s,fpsFlag:c,recordingBase:l,appBundleId:u}=e,d=`agent-device-recording-${Date.now()}.mp4`,f=`tmp/${d}`,p=X(t,o,r),m,h,g=async()=>s.runAppleRunnerCommand(a,{command:`recordStart`,outPath:d,fps:c,maxSize:l.maxSize,appBundleId:u},p);try{let e=await g();m=typeof e.recorderStartUptimeMs==`number`?e.recorderStartUptimeMs:void 0,h=typeof e.targetAppReadyUptimeMs==`number`?e.targetAppReadyUptimeMs:void 0}catch(e){if(!Ln(e))return v(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`);n({level:`warn`,phase:`record_start_runner_desynced`,data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:r.name,error:D(e)}});let t=Rn(i,a.id,r.name);if(t)return v(`COMMAND_FAILED`,`failed to start recording: recording already in progress in session '${t.name}'`);try{await s.runAppleRunnerCommand(a,{command:`recordStop`,appBundleId:u},p)}catch{}try{let e=await g();m=typeof e.recorderStartUptimeMs==`number`?e.recorderStartUptimeMs:void 0,h=typeof e.targetAppReadyUptimeMs==`number`?e.targetAppReadyUptimeMs:void 0}catch(e){return v(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`)}}return{platform:`ios-device-runner`,remotePath:f,runnerStartedAtUptimeMs:m,targetAppReadyUptimeMs:h,...l}}async function Un(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s,appBundleId:c}=e;try{await a.runAppleRunnerCommand(r,{command:`recordStart`,outPath:s.outPath,fps:o,maxSize:s.maxSize,appBundleId:c},X(t,i,n))}catch(e){return v(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`)}return{platform:`macos-runner`,...s}}async function Wn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;await Bn({req:t,activeSession:n,device:r,logPath:i,deps:a});let s={stdout:``,stderr:``,exitCode:1};for(let e of ie)if(s=await a.runCmd(`xcrun`,[`devicectl`,`device`,`copy`,`from`,`--device`,r.id,`--source`,o.remotePath,`--destination`,o.outPath,`--domain-type`,`appDataContainer`,`--domain-identifier`,e],{allowFailure:!0}),s.exitCode===0)break;if(s.exitCode!==0)return v(`COMMAND_FAILED`,`failed to copy recording from device: ${s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`}`);let c=zn(o);return c>0&&await a.trimRecordingStart({videoPath:o.outPath,trimStartMs:c}),await k({recording:o,deps:a,trimStartMs:c,targetLabel:`iOS recording`}),null}async function Gn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;return await Bn({req:t,activeSession:n,device:r,logPath:i,deps:a}),await k({recording:o,deps:a,targetLabel:`macOS recording`}),null}const Kn=5e3,Z=2e3;async function qn(e){let{deps:t,recording:n}=e;n.child.kill(`SIGINT`);let r=await Q(n.wait,Kn);return r||(await Jn(t,n,`SIGINT`),r=await Q(n.wait,Z),r)||(n.child.kill(`SIGTERM`),await Jn(t,n,`SIGTERM`),r=await Q(n.wait,Z),r)?r:(n.child.kill(`SIGKILL`),await Jn(t,n,`SIGKILL`),await Q(n.wait,Z))}async function Q(e,t){return await Promise.race([e,h(t).then(()=>null)])}async function Jn(e,t,n){await Xn(e,t,n)||await Yn(e,t.outPath,n)}async function Yn(e,t,r){let i=`simctl.*recordVideo.*${$n(t)}`,a;try{a=await e.runCmd(`pgrep`,[`-f`,i],{allowFailure:!0})}catch(e){n({level:`warn`,phase:`record_stop_ios_simulator_pgrep_failed`,data:{outPath:t,signal:r,error:D(e)}});return}let o=g(Qn(a.stdout),{excludePid:process.pid}),s=te(o,r);n({level:s>0?`warn`:`debug`,phase:`record_stop_ios_simulator_signal_recorders`,data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:s,pgrepExitCode:a.exitCode}})}async function Xn(e,t,r){let i=t.recorderPid??t.child.pid;if(typeof i!=`number`||!Number.isInteger(i)||i<=0)return n({level:`debug`,phase:`record_stop_ios_simulator_owned_recorder_unavailable`,data:{outPath:t.outPath,signal:r,reason:`missing_recorder_pid`}}),!1;let a=await Zn(e,i,t.outPath,r),o=g([i,...a.pids],{excludePid:process.pid}),s=te(o,r);return n({level:s>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:s,pgrepExitCode:a.exitCode}}),s>0}async function Zn(e,t,r,i){let a;try{a=await e.runCmd(`pgrep`,[`-P`,String(t)],{allowFailure:!0})}catch(e){return n({level:`warn`,phase:`record_stop_ios_simulator_owned_pgrep_failed`,data:{outPath:r,signal:i,parentPid:t,error:D(e)}}),{pids:[]}}return{pids:Qn(a.stdout),exitCode:a.exitCode}}function Qn(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}function $n(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async function er(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recordingBase:o,resolvedOut:s}=e,c=o.showTouches?await Vn({req:t,activeSession:n,device:r,logPath:i,deps:a}):void 0,{child:l,wait:u}=a.startIosSimulatorRecording({device:r,outPath:s}),d=await nr(s),f,p;if(c)f=c.gestureClockOriginAtMs,p=c.gestureClockOriginUptimeMs;else if(o.showTouches)try{let e=Date.now(),o=await a.runAppleRunnerCommand(r,{command:`uptime`,appBundleId:Y(n)},X(t,i,n));f=Math.round((e+Date.now())/2),p=typeof o.currentUptimeMs==`number`?o.currentUptimeMs:void 0}catch{}return{platform:`ios`,child:l,wait:u,...o,recorderPid:l.pid,startedAt:d,gestureClockOriginAtMs:p===void 0?void 0:f,gestureClockOriginUptimeMs:p}}async function tr(e){let{deps:n,recording:r,stopRequestedAt:i}=e;await t(`record_stop_tail_settle`,()=>n.waitForRecordingTail(r),{platform:r.platform,gestureEventCount:r.gestureEvents.length});let a=await t(`record_stop_ios_simulator_process`,()=>qn({deps:n,recording:r}),{outPath:r.outPath});if(!a)return rr(`failed to stop recording: simctl recordVideo did not exit after ${Kn}ms and forced cleanup`,r,i);if(a.exitCode!==0)return rr(`failed to stop recording: ${O(a,`simctl recordVideo`)}`,r,i);if(await t(`record_stop_video_stable`,()=>n.waitForStableFile(r.outPath,{pollMs:150,attempts:12}),{outPath:r.outPath}),!await t(`record_stop_video_playable_check`,()=>n.isPlayableVideo(r.outPath),{outPath:r.outPath}))return rr(`failed to stop recording: ${r.outPath} was not finalized into a playable video`,r,i);if(r.maxSize!==void 0)try{await t(`record_stop_resize`,()=>n.resizeRecording({videoPath:r.outPath,maxSize:r.maxSize,exportQuality:r.exportQuality,targetLabel:`iOS recording`}),{outPath:r.outPath,maxSize:r.maxSize})}catch(e){r.overlayWarning=`failed to resize recording: ${D(e)}`}return await t(`record_stop_finalize_overlay`,()=>k({recording:r,deps:n,targetLabel:`iOS recording`}),{outPath:r.outPath,showTouches:r.showTouches,gestureEventCount:r.gestureEvents.length}),null}async function nr(e){for(let t=0;t<2;t+=1){try{if(b.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)return Date.now();await h(250)}return Date.now()}function rr(e,t,n){let r=nt(e,t,n);return ir(t.outPath),v(`COMMAND_FAILED`,r.message)}function ir(e){try{b.rmSync(e,{force:!0})}catch{}}de();function ar(e){let t=le(e.platform)?.recording?.resolveBackendTag(e)??`unsupported`;return pr[t]}function or(e){let{recording:t}=e;switch(t.platform){case`android`:return fr.stop({...e,recording:t});case`ios`:return dr.stop({...e,recording:t});case`ios-device-runner`:return lr.stop({...e,recording:t});case`macos-runner`:return ur.stop({...e,recording:t});case`web`:return cr.stop({...e,recording:t})}return t}function $({req:e}){return e.positionals?.[1]??d(void 0)}function sr({req:e}){let t=e.positionals?.[1];return t===void 0?d(`web`):u(t,f)}const cr={recordingBackend:`agent-browser recording`,validateStart:e=>gr(e),resolveOutputPath:sr,start:async({activeSession:e,recordingBase:t,resolvedOut:n})=>{let r=_r(n);if(r)return r;if(e.recordOnlySession)return v(`INVALID_ARGS`,`record on web requires an active browser session; run open <url> --platform web first`);let i=y();return i.startRecording?(await i.startRecording(n),{...t,outPath:n,startedAt:Date.now(),platform:`web`,showTouches:!1}):v(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)},stop:async({recording:e})=>await br({recording:e}),cleanupRecordOnlySession:async()=>{try{await y().close()}catch{}}},lr={recordingBackend:`runner AVAssetWriter`,resolveOutputPath:$,start:async({req:e,activeSession:t,sessionStore:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s})=>{let c=Y(t);return c?await Hn({req:e,activeSession:t,sessionStore:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s,appBundleId:c}):v(`INVALID_ARGS`,`record on physical iOS devices requires an active app session; run open <app> first`)},stop:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})=>await Wn({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},ur={recordingBackend:`runner AVAssetWriter`,resolveOutputPath:$,start:async({req:e,activeSession:t,device:n,logPath:r,deps:i,fpsFlag:a,recordingBase:o})=>{let s=Y(t);return s?await Un({req:e,activeSession:t,device:n,logPath:r,deps:i,fpsFlag:a,recordingBase:o,appBundleId:s}):v(`INVALID_ARGS`,`record on macOS requires an active app session; run open <app> first`)},stop:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})=>await Gn({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},dr={recordingBackend:`simctl recordVideo`,resolveOutputPath:$,start:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:s})=>{let c=Y(t),l=!o(a.recordingScope??`app`);return l&&!c?v(`INVALID_ARGS`,`record on iOS Simulator with app scope requires an active app session; run open <app> first, or use --scope device to record the full simulator screen`):l&&c&&vr(c)?v(`INVALID_ARGS`,`record on iOS Simulator cannot use Agent Device Runner as the active app session; run open <app> first`):await er({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:s})},stop:async({deps:e,recording:t,stopRequestedAt:n})=>await tr({deps:e,recording:t,stopRequestedAt:n})},fr={recordingBackend:`adb screenrecord`,resolveOutputPath:$,start:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await wn({sessionName:e,activeSession:t,device:n,recordingBase:r}),recoverMissingStop:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await $t({sessionName:e,activeSession:t,device:n,recordingBase:r}),stop:async({deps:e,device:t,recording:n,stopRequestedAt:r})=>await An({deps:e,device:t,recording:n,stopRequestedAt:r})},pr={web:cr,android:fr,macos:ur,"ios-device":lr,"ios-simulator":dr,unsupported:{recordingBackend:`unsupported`,resolveOutputPath:$,start:async()=>v(`UNSUPPORTED_OPERATION`,`record is not supported on this device`),stop:async()=>v(`UNSUPPORTED_OPERATION`,`record is not supported on this device`)}},mr=[[`fps`,`--fps`],[`quality`,`--quality`],[`screenshotMaxSize`,`--max-size`],[`hideTouches`,`--hide-touches`]];function hr(e){let t=e.flags??{},n=mr.flatMap(([e,n])=>t[e]===void 0?[]:[n]);return o(t.recordingScope??`app`)?[...n,`--scope`]:n}function gr(e){let t=hr(e);return t.length>0?v(`INVALID_ARGS`,`web recordings do not support ${t.join(`, `)}; agent-browser records WebM directly`):null}function _r(e){return x.extname(e).toLowerCase()===`.webm`?null:v(`INVALID_ARGS`,`web recordings must use a ${f} output path`)}function vr(e){return ie.includes(e)}function yr(e){try{b.rmSync(e,{force:!0})}catch{}}async function br(e){let{recording:t}=e,n=y();return n.stopRecording?(await n.stopRecording(),xr(t.outPath)?null:(yr(t.outPath),v(`COMMAND_FAILED`,`failed to stop recording: ${t.outPath} was not finalized into a WebM video`))):v(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)}function xr(e){try{return b.statSync(e).size>0}catch{return!1}}function Sr(){return{runCmd:async(e,t,n)=>e===`xcrun`?await oe(t,n):await i(e,t,n),startIosSimulatorRecording:e=>ve().startIosSimulatorRecording(e),runAppleRunnerCommand:ae,waitForRecordingTail:Cr,waitForStableFile:Ae,isPlayableVideo:je,trimRecordingStart:Qe,resizeRecording:et,overlayRecordingTouches:$e}}async function Cr(e){e.platform===`ios`&&e.gestureEvents.length!==0&&await h(350)}function wr(e){let{req:t,outPath:n,activeSession:r,recordingBackend:i,recordingScope:a}=e,o=s(t.flags?.quality);return{outPath:n,clientOutPath:t.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),recordingScope:a,recordingBackend:i,recordOnlySession:r.recordOnlySession===!0,activeSessionApp:r.appBundleId?{bundleId:r.appBundleId,...r.appName?{name:r.appName}:{}}:void 0,maxSize:t.flags?.screenshotMaxSize,exportQuality:o??`medium`,showTouches:t.flags?.hideTouches!==!0,gestureEvents:[]}}async function Tr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e,c=Er(e);return`backend`in c?Or({req:t,sessionName:n,sessionStore:r,activeSession:i,recording:await c.backend.start({req:t,sessionName:n,activeSession:i,sessionStore:r,device:a,logPath:o,deps:s,fpsFlag:c.fpsFlag,recordingBase:c.recordingBase,resolvedOut:c.resolvedOut}),outPath:c.outPath}):c}function Er(e){let{req:t,activeSession:n,device:r,recordingScope:i}=e,a=ar(r);return Dr({req:t,activeSession:n,device:r,backend:a})||{...Pr(t,a,n,i),backend:a,fpsFlag:t.flags?.fps}}function Dr(e){let{req:t,activeSession:n,device:r,backend:i}=e,a=[()=>kr(n),()=>i.validateStart?.(t)??null,()=>Ar({fpsFlag:t.flags?.fps,qualityFlag:t.flags?.quality,maxSizeFlag:t.flags?.screenshotMaxSize}),()=>me(`record`,r)];for(let e of a){let t=e();if(t)return t}return null}function Or(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,recording:a,outPath:o}=e;if(`ok`in a)return a;i.recording=a,r.set(n,i);let s=r.ensureSessionDir(n);return _e(r,i,t,t.command,{action:`start`,showTouches:a.showTouches}),{ok:!0,data:{recording:`started`,outPath:a.clientOutPath??o,sessionStateDir:s,recordingBackend:a.recordingBackend,recordingScope:a.recordingScope,recordOnlySession:a.recordOnlySession,activeSessionApp:a.activeSessionApp,showTouches:a.showTouches}}}function kr(e){return e.recording?v(`INVALID_ARGS`,`recording already in progress`):null}function Ar(e){let{fpsFlag:t,qualityFlag:n,maxSizeFlag:r}=e;return jr(t)??Mr(n)??Nr(r)}function jr(e){return e!==void 0&&(!Number.isInteger(e)||e<1||e>120)?v(`INVALID_ARGS`,`fps must be an integer between 1 and 120`):null}function Mr(e){return e!==void 0&&s(e)===void 0?v(`INVALID_ARGS`,`quality must be one of: ${l.join(`, `)} (legacy numeric values 5-10 are accepted)`):null}function Nr(e){return e!==void 0&&(!Number.isInteger(e)||e<1)?v(`INVALID_ARGS`,`max-size must be a positive integer`):null}function Pr(e,t,n,r){let i=t.resolveOutputPath({req:e}),a=ce.expandHome(i,e.meta?.cwd),o=wr({req:e,outPath:a,activeSession:n,recordingBackend:t.recordingBackend,recordingScope:r});return b.mkdirSync(x.dirname(a),{recursive:!0}),b.rmSync(a,{force:!0}),{outPath:i,resolvedOut:a,recordingBase:o}}async function Fr(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a}=e,o=await Ir(e);if(o&&`ok`in o)return o;if(!o)return v(`INVALID_ARGS`,`no active recording`);let s=Date.now(),c=o.invalidatedReason;return n.recording=void 0,await or({req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o,stopRequestedAt:s})||Br(o,c)||Hr(o)}async function Ir(e){return e.activeSession.recording?e.activeSession.recording:await Lr(e)}async function Lr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e;if(Vr(r,a.id))return null;let c=ar(a);if(!c.recoverMissingStop)return null;let{resolvedOut:l,recordingBase:u}=Rr(t,c,i),d=await c.recoverMissingStop({req:t,sessionName:n,activeSession:i,sessionStore:r,device:a,logPath:o,deps:s,recordingBase:u,resolvedOut:l});return d?(`ok`in d||zr(l),d):null}function Rr(e,t,n){let r=t.resolveOutputPath({req:e}),i=ce.expandHome(r,e.meta?.cwd);return{resolvedOut:i,recordingBase:wr({req:e,outPath:i,activeSession:n,recordingBackend:t.recordingBackend,recordingScope:n.recording?.recordingScope??`app`})}}function zr(e){b.mkdirSync(x.dirname(e),{recursive:!0}),b.rmSync(e,{force:!0})}function Br(e,t){return t?e.platform===`ios`&&e.showTouches?(e.overlayWarning??=`overlay unavailable: ${t}`,null):v(`COMMAND_FAILED`,t):null}function Vr(e,t){for(let n of e.values())if(n.recording&&n.device.id===t)return!0;return!1}function Hr(e){let t=e.platform===`android`?e.chunks:void 0,n=[{field:`outPath`,artifactType:`screen-recording`,path:e.outPath,localPath:e.clientOutPath,fileName:x.basename(e.clientOutPath??e.outPath)}];return t&&t.length>1&&n.push(...t.slice(1).map(t=>({field:`chunkPath`,artifactType:`screen-recording-chunk`,path:t.path,localPath:Ur(e,t.index),fileName:x.basename(Ur(e,t.index)??t.path)}))),e.telemetryPath&&n.push({field:`telemetryPath`,artifactType:`screen-recording-telemetry`,path:e.telemetryPath,localPath:Wr(e),fileName:x.basename(e.telemetryPath)}),{ok:!0,data:{recording:`stopped`,outPath:e.outPath,telemetryPath:e.telemetryPath,artifacts:n,recordingBackend:e.recordingBackend,recordingScope:e.recordingScope,recordOnlySession:e.recordOnlySession,activeSessionApp:e.activeSessionApp,durationMs:Date.now()-e.startedAt,showTouches:e.showTouches,warning:e.warning,overlayWarning:e.overlayWarning,chunks:t?.map(t=>({index:t.index,path:Ur(e,t.index)??t.path}))}}}function Ur(e,t){if(!(e.platform!==`android`||!e.clientOutPath))return A(e.clientOutPath,t)}function Wr(e){if(e.clientOutPath)return Re(e.clientOutPath)}async function Gr(e,t,n,r={}){n.recordOnlySession&&(await ar(n.device).cleanupRecordOnlySession?.(n),r.writeLog&&e.writeSessionLog(n),e.delete(t))}async function Kr(e){let{req:t,sessionName:n,sessionStore:r,logPath:i}=e,a=Sr(),s=r.get(n),c=(t.positionals?.[0]??``).toLowerCase();if(![`start`,`stop`].includes(c))return v(`INVALID_ARGS`,`record requires start|stop`);let l=qr(t);if(typeof l==`object`)return l;if(c===`start`&&!s&&!o(l))return v(`INVALID_ARGS`,ue(t)?`record start with app scope and an explicit session requires an active app session; run open <app> first, or use --scope device to record the full screen`:`record start defaults to app scope and requires an active app session; run open <app> first, or use --scope device to record the full screen`);let u=s?.device??await fe(t.flags??{});s||await he(u);let d=s??{name:n,sessionScope:pe(t),device:u,createdAt:Date.now(),recordOnlySession:!0,actions:[]};if(c===`start`)return Tr({req:t,sessionName:n,sessionStore:r,activeSession:d,device:u,recordingScope:l,logPath:i,deps:a});let f=await Fr({req:t,sessionName:n,sessionStore:r,activeSession:d,device:u,logPath:i,deps:a});return f.ok?(_e(r,d,t,t.command,{action:`stop`,outPath:f.data?.outPath,showTouches:f.data?.showTouches}),await Gr(r,n,d,{writeLog:!0}),f):(await Gr(r,n,d),f)}function qr(e){let t=e.flags?.recordingScope;return t===void 0?`app`:Jr(t)?t:v(`INVALID_ARGS`,`record scope must be one of: ${a.join(`, `)}`)}function Jr(e){return typeof e==`string`&&a.includes(e)}export{Kr as t};
@@ -1 +1 @@
1
- import{$t as e,xn as t}from"./internal/daemon.js";import{t as n}from"./handler-utils.js";import{t as r}from"./record-trace-recording.js";import i from"node:fs";import a from"node:path";async function o(o){let{req:s,sessionName:c,sessionStore:l,logPath:u}=o,d=s.command;if(d===`record`)return r({req:s,sessionName:c,sessionStore:l,logPath:u});if(d===`trace`){let r=(s.positionals?.[0]??``).toLowerCase();if(![`start`,`stop`].includes(r))return e(`INVALID_ARGS`,`trace requires start|stop`);let o=l.get(c);if(!o)return e(`SESSION_NOT_FOUND`,`No active session`);if(r===`start`){if(o.trace)return e(`INVALID_ARGS`,`trace already in progress`);let r=s.positionals?.[1]??l.defaultTracePath(o),c=t.expandHome(r);return i.mkdirSync(a.dirname(c),{recursive:!0}),i.appendFileSync(c,``),o.trace={outPath:c,startedAt:Date.now()},n(l,o,s,d,{action:`start`,outPath:c}),{ok:!0,data:{trace:`started`,outPath:c}}}if(!o.trace)return e(`INVALID_ARGS`,`no active trace`);let u=o.trace.outPath;if(s.positionals?.[1]){let e=t.expandHome(s.positionals[1]);i.mkdirSync(a.dirname(e),{recursive:!0}),i.existsSync(u)?i.renameSync(u,e):i.appendFileSync(e,``),u=e}return o.trace=void 0,n(l,o,s,d,{action:`stop`,outPath:u}),{ok:!0,data:{trace:`stopped`,outPath:u}}}return null}export{o as handleRecordTraceCommands};
1
+ import{En as e,in as t}from"./internal/daemon.js";import{t as n}from"./handler-utils.js";import{t as r}from"./record-trace-recording.js";import i from"node:fs";import a from"node:path";async function o(o){let{req:s,sessionName:c,sessionStore:l,logPath:u}=o,d=s.command;if(d===`record`)return r({req:s,sessionName:c,sessionStore:l,logPath:u});if(d===`trace`){let r=(s.positionals?.[0]??``).toLowerCase();if(![`start`,`stop`].includes(r))return t(`INVALID_ARGS`,`trace requires start|stop`);let o=l.get(c);if(!o)return t(`SESSION_NOT_FOUND`,`No active session`);if(r===`start`){if(o.trace)return t(`INVALID_ARGS`,`trace already in progress`);let r=s.positionals?.[1]??l.defaultTracePath(o),c=e.expandHome(r);return i.mkdirSync(a.dirname(c),{recursive:!0}),i.appendFileSync(c,``),o.trace={outPath:c,startedAt:Date.now()},n(l,o,s,d,{action:`start`,outPath:c}),{ok:!0,data:{trace:`started`,outPath:c}}}if(!o.trace)return t(`INVALID_ARGS`,`no active trace`);let u=o.trace.outPath;if(s.positionals?.[1]){let t=e.expandHome(s.positionals[1]);i.mkdirSync(a.dirname(t),{recursive:!0}),i.existsSync(u)?i.renameSync(u,t):i.appendFileSync(t,``),u=t}return o.trace=void 0,n(l,o,s,d,{action:`stop`,outPath:u}),{ok:!0,data:{trace:`stopped`,outPath:u}}}return null}export{o as handleRecordTraceCommands};