agent-device 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.0.apk → agent-device-android-multitouch-helper-0.19.1.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.1.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.0.manifest.json → agent-device-android-multitouch-helper-0.19.1.manifest.json} +4 -4
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.0.apk → agent-device-android-snapshot-helper-0.19.1.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.1.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.0.manifest.json → agent-device-android-snapshot-helper-0.19.1.manifest.json} +6 -6
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +24 -7
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +506 -119
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +153 -48
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +172 -0
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +76 -5
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +60 -52
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +159 -56
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +142 -0
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -14
- package/dist/src/android-adb.d.ts +1 -2
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-ownership.js +6 -0
- package/dist/src/android.js +1 -1
- package/dist/src/app-lifecycle.js +3 -3
- package/dist/src/apple-runner-options.js +1 -1
- package/dist/src/apps.js +5 -5
- package/dist/src/cli-help.js +131 -34
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +11 -11
- package/dist/src/client.js +2 -2
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/device-input-state.js +2 -2
- package/dist/src/devices2.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/index.d.ts +199 -20
- package/dist/src/input-actions.js +3 -3
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +17 -15
- package/dist/src/lease.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/metro.d.ts +0 -1
- package/dist/src/notifications.js +1 -1
- package/dist/src/points.js +1 -1
- package/dist/src/project-runtime.js +1 -1
- package/dist/src/providers.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace-recording.js +2 -2
- package/dist/src/record-trace.js +1 -1
- package/dist/src/registry.js +24 -23
- package/dist/src/reporting.js +3 -3
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runtime.js +2 -2
- package/dist/src/sdk-android-adb.d.ts +2 -2
- package/dist/src/sdk-batch-runner.d.ts +0 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-finders.d.ts +1 -2
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-io.d.ts +0 -1
- package/dist/src/sdk-remote-config.d.ts +1 -2
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +0 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/selectors2.js +1 -1
- package/dist/src/server.js +3 -3
- package/dist/src/session.js +10 -10
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.js +2 -2
- package/dist/src/snapshot-helper.js +4 -4
- package/dist/src/snapshot-quality.js +1 -1
- package/dist/src/snapshot2.js +2 -2
- package/dist/src/tv-remote.js +14 -0
- package/dist/src/web.js +1 -1
- package/package.json +5 -4
- package/server.json +2 -2
- package/skills/agent-device/SKILL.md +8 -7
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.0.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.0.apk.sha256 +0 -1
- package/dist/src/device-rotation.js +0 -14
- package/dist/src/logcat.js +0 -6
package/dist/src/lease.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e}from"./sdk-contracts.js";import{
|
|
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};
|
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`)},readClipboard:()=>_(),writeClipboard:e=>v(e),setSetting:()=>{throw new e(`UNSUPPORTED_OPERATION`,`setSetting not supported on Linux`)}}}export{b as createLinuxInteractor};
|
|
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};
|
package/dist/src/metro.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { y as SessionRuntimeHints } from "./sdk-contracts.js";
|
|
2
2
|
import { s as MetroBridgeDescriptor } from "./sdk-remote-config.js";
|
|
3
|
-
|
|
4
3
|
//#region src/utils/url.d.ts
|
|
5
4
|
declare function normalizeBaseUrl(input: string): string;
|
|
6
5
|
declare function buildBundleUrl(baseUrl: string, platform: 'ios' | 'android'): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e}from"./sdk-contracts.js";import{
|
|
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};
|
package/dist/src/points.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{F as e,b as t,l as n}from"./sdk-contracts.js";import{
|
|
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
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(`
|
|
3
3
|
---
|
|
4
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:fs";import t from"node:path";function n(e){let t=i(e);return t?r(t):`auto`}function r(e){let t={...e.dependencies??{},...e.devDependencies??{}};return typeof t.expo==`string`?`expo`:typeof t[`react-native`]==`string`?`react-native`:`auto`}function i(n){if(!n)return;let r=t.join(n,`package.json`);try{return JSON.parse(e.readFileSync(r,`utf8`))}catch{return}}export{r as n,i as r,n as t};
|
|
1
|
+
import e from"node:fs";import t from"node:path";function n(e){let t=i(e);return t?r(t):`auto`}function r(e){let t={...e.dependencies??{},...e.devDependencies??{}};return typeof t[`@callstack/repack`]==`string`?`repack`:typeof t.expo==`string`?`expo`:typeof t[`react-native`]==`string`?`react-native`:`auto`}function i(n){if(!n)return;let r=t.join(n,`package.json`);try{return JSON.parse(e.readFileSync(r,`utf8`))}catch{return}}export{r as n,i as r,n as t};
|
package/dist/src/providers.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{N as e}from"./sdk-contracts.js";import{
|
|
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};
|
package/dist/src/react-native.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{B as e}from"./sdk-contracts.js";import{
|
|
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,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{
|
|
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
|
|
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 w}catch(e){throw w=void 0,e}}function Ae(t){return t instanceof e?t.code===`TOOL_MISSING`?!0:Me(String(t.details?.stderr??``),String(t.details?.stdout??``)):!1}async function je(e,t={}){let n=t.pollMs??150,r=t.attempts??12;for(let t=0;t<r;t+=1){if(await Oe(e))return;await d(n)}}function Me(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 Ne(e){try{let t=y.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=Pe(e);return t.includes(`ftyp`)&&t.includes(`moov`)}function Pe(e){try{let t=y.openSync(e,`r`);try{let e=y.fstatSync(t).size,n=0,r=[];for(;n+8<=e&&r.length<16;){let e=Buffer.alloc(8);if(y.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(y.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{y.closeSync(t)}}catch{return[]}}function Fe(e){let t=b.parse(e);return b.join(t.dir,`${t.name}.gesture-telemetry.json`)}function Ie(e,t){return Le(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 Le(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function Re(e){let t=Fe(e.videoPath),n={version:1,generatedAt:new Date().toISOString(),events:Ie(e.events,e.trimStartMs??0)};return y.writeFileSync(t,JSON.stringify(n,null,2)),t}function ze(e){let{recording:t,trimStartMs:n}=e,r=Re({videoPath:t.outPath,events:t.gestureEvents,trimStartMs:n});return t.telemetryPath=r,r}function Be(e,t,n,r){let i=`apple-runner/AgentDeviceRunner/RecordingScripts/${e}`,a=`dist/${i}`;return[b.resolve(t,e),b.resolve(n,i),b.resolve(t,`../${i}`),b.resolve(t,`../../${i}`),b.resolve(t,`../../../${i}`),b.resolve(n,a),b.resolve(r,i)]}function T(t){let n=Be(t,b.dirname(be(import.meta.url)),u(),process.cwd());for(let e of n)if(y.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 Ve,He,Ue;function We(e=process.platform){if(e!==`darwin`)return`touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry`}function Ge(){return Ve??=T(`recording-overlay.swift`),Ve}function Ke(){return He??=T(`recording-trim.swift`),He}function qe(){return Ue??=T(`recording-resize.swift`),Ue}async function E(t){let{videoPath:n,scriptPath:r,scriptArgs:i,commandDescription:o}=t;await De(n),await je(n);let s=Je(n);try{await a(await xe({sourcePath:r}),[`--input`,n,`--output`,s,...i],{timeoutMs:12e4,env:x()}),await je(s),y.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{y.rmSync(s,{force:!0})}}function Je(e){let t=b.parse(e),n=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;return b.join(t.dir,`.${t.name}.agent-device-${n}${t.ext||`.mp4`}`)}async function Ye(e){let{videoPath:t,trimStartMs:n}=e;n>0&&await E({videoPath:t,scriptPath:Ke(),scriptArgs:[`--trim-start-ms`,String(n)],commandDescription:`Failed to trim the start of the iOS recording`})}async function Xe(e){let{videoPath:t,telemetryPath:n,exportQuality:r=ee,targetLabel:i=`recording`}=e;await E({videoPath:t,scriptPath:Ge(),scriptArgs:[`--events`,n,`--quality`,r],commandDescription:`Failed to add touch overlays to the ${i}`})}async function Ze(e){let{videoPath:t,maxSize:n,exportQuality:r=ee,targetLabel:i=`recording`}=e;await E({videoPath:t,scriptPath:qe(),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 Qe=1e3;function O(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function $e(e,t,n=Date.now()){let r=Math.max(0,n-t.startedAt);return r>=Qe?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(r)}ms; wait at least ${Qe}ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function k(e){let{recording:t,deps:i,trimStartMs:a,targetLabel:o}=e,s=ze({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=We();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: ${D(e)}`}}function A(e,t){if(t===1)return e;let n=b.parse(e),r=n.ext||`.mp4`;return b.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 et(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 tt(e){let{recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}=e,o=setTimeout(()=>{t.rotationPromise=nt({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&&tt({recording:t,startNextChunk:n,finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a})})},17e4);o.unref?.(),t.rotationTimer=o}async function nt(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 rt({recording:t,nextIndex:s,previousChunk:c,startNextChunk:n,finishCurrentChunk:r});if(!l)return;let{nextChunk:u,previousChunkFinished:d}=l;await at({recording:t,chunks:o,nextChunk:u,nextIndex:s,previousState:it({recording:t,nextChunk:u}),finishCurrentChunk:r,cleanupStartedChunk:i,persistRecordingState:a}),!d&&await st(r,c)}async function rt(e){let{recording:t,nextIndex:n,previousChunk:r,startNextChunk:i,finishCurrentChunk:a}=e,o=b.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 it(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 at(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 ot({recording:t,chunks:n,previousState:a}),await ct({nextChunk:r,finishCurrentChunk:o,cleanupStartedChunk:s})||e}}function ot(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 st(e,t){let n=await e(t);if(n)throw Error(n)}async function ct(e){let{nextChunk:t,finishCurrentChunk:n,cleanupStartedChunk:r}=e,i;try{await st(n,t)}catch(e){i=e}try{await r?.(t)}catch(e){i??=e}return i}async function lt(e){let{recording:t,deps:n}=e;if(j(t).length<=1){await k({recording:t,deps:n,targetLabel:`Android recording`});return}ze({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 ut(e){for(let t of e.chunks){let n=await dt({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 dt(e){let{deps:t,deviceId:n,remotePath:a,outPath:o}=e,s;for(let e=0;e<2;e+=1){pt(o);let c=await i(a,o,{allowFailure:!0,device:te(n)});if(c.exitCode!==0)s=O(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:ft(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 d(750)}return s?`failed to copy recording from device: ${s}`:(pt(o),`failed to copy recording from device: pulled file is not a playable MP4`)}function ft(e){try{return y.statSync(e).size}catch{return 0}}function pt(e){try{y.rmSync(e,{force:!0})}catch{}}const mt=`agent-device-recording-active.json`,ht=[`/sdcard`,`/data/local/tmp`];function gt(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 _t(e){let t=Ct(e);if(!t)return{kind:`delete`};let n=Tt(t);if(!n)return{kind:`blocked`,reason:`unsupported_or_malformed_manifest`};let r=Dt(t.current),i=Ot(t.pending),a=kt(t.chunks);return a?!r&&!i?{kind:`blocked`,reason:`invalid_recording_state`}:{kind:`manifest`,manifest:{...n,sessionScope:jt(t.sessionScope),current:r,pending:i,chunks:a}}:{kind:`blocked`,reason:`invalid_recording_chunks`}}function vt(e){return`${b.posix.dirname(e)}/${mt}`}function M(){return ht.map(e=>`${e}/${mt}`)}function yt(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 bt(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:St(i)}}function xt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return{...bt({deviceId:t,sessionName:n,sessionScope:r,recording:i}),pending:{remotePath:a},chunks:St(i,{index:o,remotePath:a})}}function St(e,t){return[...e.chunks??[{index:1,remotePath:e.remotePath}],...t?[t]:[]].map(e=>({index:e.index,remotePath:e.remotePath}))}function Ct(e){try{let t=JSON.parse(e);return wt(t)?t:void 0}catch{return}}function wt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Tt(e){if(e.version!==1)return;let t=Et(e);if(!t)return;let n=Mt(e.startedAt);if(n===void 0)return;let r=Nt(e.showTouches);if(r!==void 0)return{version:1,...t,startedAt:n,showTouches:r}}function Et(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 Dt(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 Ot(e){if(!e||typeof e!=`object`)return;let t=e;if(!(typeof t.remotePath!=`string`||!P(t.remotePath)))return{remotePath:t.remotePath}}function kt(e){if(!Array.isArray(e))return;let t=e.map(At).filter(e=>e!==void 0);return t.length>0&&t.length===e.length?t:void 0}function At(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 jt(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 Mt(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function Nt(e){return typeof e==`boolean`?e:void 0}function P(e){return/^\/(?:sdcard|data\/local\/tmp)\/agent-device-recording-\d+\.mp4$/.test(e)}const Pt=`Recovered Android recording after daemon restart from durable device manifest.`,Ft=`touch overlay burn-in is unavailable after daemon restart because gesture telemetry is stored in daemon memory`,It=`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 ne(te(e),t,n)}async function Lt(e){let t={live:[],uncertain:[],blocked:[]};for(let n of M()){let r=await L(e,[`shell`,`cat`,n],{allowFailure:!0,timeoutMs:I});if(r.exitCode!==0)continue;let i=_t(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 Rt(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 Rt(e,t){return t.pending?await zt(e,t,t.pending):await Ut(e,t)}async function zt(e,t,n){let r=await Gt(e,n.remotePath);return Vt(t,r)||(t.current?await Bt(e,t,t.current,r):await Ht(e,t,n.remotePath,r))}async function Bt(e,t,n,r){let i=await Wt(e,n);return i===`uncertain`||r===`uncertain`?{kind:`uncertain`}:i===`stale`?{kind:`stale`}:R({manifest:t,current:n,chunks:qt(t.chunks,n.remotePath),recoveryWarning:i===`finished`?`${F} ${It}`:F})}function Vt(e,t){if(!(!t||t===`uncertain`))return R({manifest:e,current:t,recoveryWarning:e.current?F:Pt})}async function Ht(e,t,n,r){return r===`uncertain`?{kind:`uncertain`}:await Kt(e,n)?R({manifest:t,current:{remotePath:n,remotePid:``,startedAt:t.startedAt},recoveryWarning:It}):{kind:`stale`}}async function Ut(e,t){if(!t.current)return{kind:`stale`};let n=await Wt(e,t.current);return n===`live`?R({manifest:t,current:t.current}):n===`finished`?R({manifest:t,current:t.current,recoveryWarning:It}):{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 Wt(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(gt).some(e=>e?.remotePid===t.remotePid&&e.remotePath===t.remotePath)?`live`:a?.includes(`screenrecord`)?`uncertain`:a?`stale`:await Kt(e,t.remotePath)?`finished`:`stale`}async function Gt(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(gt).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 Kt(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 qt(e,t){let n=e.findIndex(e=>e.remotePath===t);return n>=0?e.slice(0,n+1):e}async function Jt(e){let{deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}=e;return await B({deviceId:t,manifest:yt({deviceId:t,sessionName:n,sessionScope:r,recordingId:i,startedAt:a,showTouches:o,remotePath:s}),phase:`record_start_android_recovery_metadata_failed`})}async function Yt(e){let{deviceId:t,sessionName:n,sessionScope:r,recording:i,nextRemotePath:a,nextIndex:o}=e;return await B({deviceId:t,manifest:xt({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:bt({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=vt(i),o=`${a}.tmp`,s=await L(t,[`shell`,`printf %s ${l(JSON.stringify(n))} > ${l(o)} && mv -f ${l(o)} ${l(a)}`],{allowFailure:!0,timeoutMs:I});if(s.exitCode!==0)return Xt({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: ${O(s,`adb shell write recovery manifest`)}`;for(let e of M())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 M())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&&Xt({phase:r,deviceId:t,metadataPath:n,result:i})}function Xt(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 Zt(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a=await Lt(r.id);return a.live.length>0?en({sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a.live}):a.uncertain.length>0?Qt({sessionName:t,activeSession:n,manifests:a.uncertain}):a.blocked.length>0?$t(a.blocked):null}function Qt(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=nn({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`?_(`INVALID_ARGS`,ln(r),a):i.kind===`ambiguous`?_(`INVALID_ARGS`,`multiple active Android recording manifests could not be verified; cannot safely recover missing recording state`,a):_(`INVALID_ARGS`,`active Android recording manifest could not be verified; retry record stop after the device responds`,a)}function $t(e){return _(`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 en(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i,manifests:a}=e,o=tn({sessionName:t,activeSession:n,manifests:a});return`ok`in o?o:(an(r,o),on(o,i))}function tn(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=nn({sessionName:t,activeSession:n,manifests:r});return i.kind===`selected`?i.manifest:i.kind===`owner-mismatch`?_(`INVALID_ARGS`,ln(r),{activeRecordings:i.activeRecordings}):_(`INVALID_ARGS`,`multiple active Android recording manifests exist; cannot safely recover missing recording state`,{activeRecordings:i.activeRecordings})}function nn(e){let{sessionName:t,activeSession:n,manifests:r}=e,i=r.filter(e=>sn(e,t,n)),a=rn(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 rn(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 an(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 on(e,t){let n=e.recoveryWarning??Pt;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} ${Ft}.`:n,overlayWarning:e.showTouches?Ft:void 0}}function sn(e,t,n){return e.sessionName===t&&cn(e.sessionScope,n.sessionScope)}function cn(e,t){return!e&&!t?!0:!e||!t?!1:e.kind===t.kind&&e.id===t.id}function ln(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 un={medium:8e6,high:2e7},U=5e3;async function W(e,t,n){return await ne(te(e),t,n)}function dn(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 fn(e,t){for(let n=0;n<40;n+=1){if(!await G(e,t))return!0;await d(250)}return!await G(e,t)}async function pn(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 d(250)}}async function mn(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 d(250)}return!1}function hn(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 gn(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: ${O(r,`adb shell wm size`)}`);return _n({width:Number(i[1]),height:Number(i[2]),maxSize:n})}function _n(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:vn(e.width,n),height:vn(e.height,n)}}function vn(e,t){return Math.max(2,Math.round(e*t/2)*2)}function yn(e,t,n){let r=[`screenrecord`];return t&&r.push(`--size`,`${t.width}x${t.height}`),r.push(`--bit-rate`,String(un[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 fn(e,t)}async function bn(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 hn(Date.now(),i)){let i=await xn({device:t,recordingSize:n,quality:r,remotePath:e,hooks:a});if(i.kind===`started`)return i.chunk;o=i.message}return{error:_(`COMMAND_FAILED`,o)}}async function xn(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`,yn(a,n,i)],{allowFailure:!0,timeoutMs:U});if(c.exitCode!==0)return await o?.cleanupPreparedRemotePath?.(a),{kind:`failed`,message:`failed to start recording: ${O(c,`adb shell screenrecord`)}`};let l=dn(c.stdout);return l?(r({level:`debug`,phase:`record_start_android_started`,data:{deviceId:t.id,remotePath:a,remotePid:l}}),await mn(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 Sn(e){let{sessionName:t,activeSession:n,device:r,recordingBase:i}=e,a;try{a=await gn({deviceId:r.id,maxSize:i.maxSize})}catch(e){return _(`COMMAND_FAILED`,e instanceof Error?e.message:String(e))}let o=i.exportQuality??`medium`,s=ve(),c=await bn({device:r,recordingSize:a,quality:o,hooks:{prepareRemotePath:async e=>await Jt({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=Cn({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),_(`COMMAND_FAILED`,`failed to start recording: ${u}`)):(wn({activeSession:n,sessionName:t,device:r,recording:l,recordingSize:a,quality:o}),l)}function Cn(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 wn(e){let{activeSession:t,sessionName:n,device:r,recording:i,recordingSize:a,quality:o}=e;tt({recording:i,finishCurrentChunk:async e=>await Tn({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 bn({device:r,recordingSize:a,quality:o,preferredRemoteDir:e,hooks:{prepareRemotePath:async e=>await Yt({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 Tn(e){let{device:t,recording:n,remotePath:i=n.remotePath,remotePid:a=n.remotePid,waitForRemoteFileStability:o=!0}=e;if(!a){Pn(n,et(n)),o&&await pn(t.id,i);return}await G(t.id,a)||Pn(n,et(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 En(t.id,a,s);let c=await Dn(t.id,a);if(c)return c;o&&await pn(t.id,i)}async function En(e,t,n){if(await G(e,t)&&!await q(e,t))return`failed to stop recording: ${O(n,`adb shell kill`)}`}async function Dn(e,t){if(!await fn(e,t)&&!await q(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function On(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 kn(i);let o=await Tn({device:n,recording:i});i.rotationFailedReason&&!o&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`);let s=o===void 0?await An({deps:t,device:n,recording:i}):void 0,c=await jn({deviceId:n.id,recording:i,recordCleanupError:o===void 0});return s?_(`COMMAND_FAILED`,Nn(s,i,a)):o?_(`COMMAND_FAILED`,Nn(o,i,a)):c?_(`COMMAND_FAILED`,c):null}async function kn(e){e.rotationTimer&&=(clearTimeout(e.rotationTimer),void 0),await e.rotationPromise}async function An(e){let{deps:t,device:n,recording:r}=e,i=await ut({deps:t,deviceId:n.id,chunks:j(r)});if(i)return i;await lt({recording:r,deps:t})}async function jn(e){let{deviceId:t,recording:n,recordCleanupError:r}=e,i;for(let e of j(n)){let n=await Mn(t,e.remotePath);n&&r&&(i=n)}return await V(t),i}async function Mn(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: ${O(n,`adb shell rm`)}`}function Nn(e,t,n){return $e(e,t,n).message}function Pn(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 Fn(e){return D(e).toLowerCase().includes(`recording already in progress`)}function In(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 me({req:e,logPath:t,traceLogPath:n.trace?.outPath})}function Ln(e){return typeof e.runnerStartedAtUptimeMs!=`number`||typeof e.targetAppReadyUptimeMs!=`number`?0:Math.max(0,e.targetAppReadyUptimeMs-e.runnerStartedAtUptimeMs)}async function Rn(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:D(e)}})}}async function zn(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:D(e)}});return}}async function Bn(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(!Fn(e))return _(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`);r({level:`warn`,phase:`record_start_runner_desynced`,data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:n.name,error:D(e)}});let t=In(i,a.id,n.name);if(t)return _(`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 _(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`)}}return{platform:`ios-device-runner`,remotePath:f,runnerStartedAtUptimeMs:m,targetAppReadyUptimeMs:h,...l}}async function Vn(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 _(`COMMAND_FAILED`,`failed to start recording: ${D(e)}`)}return{platform:`macos-runner`,...s}}async function Hn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;await Rn({req:t,activeSession:n,device:r,logPath:i,deps:a});let s={stdout:``,stderr:``,exitCode:1};for(let e of re)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 _(`COMMAND_FAILED`,`failed to copy recording from device: ${s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`}`);let c=Ln(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 Un(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o}=e;return await Rn({req:t,activeSession:n,device:r,logPath:i,deps:a}),await k({recording:o,deps:a,targetLabel:`macOS recording`}),null}const Wn=5e3,X=2e3;async function Gn(e){let{deps:t,recording:n}=e;n.child.kill(`SIGINT`);let r=await Z(n.wait,Wn);return r||(await Kn(t,n,`SIGINT`),r=await Z(n.wait,X),r)||(n.child.kill(`SIGTERM`),await Kn(t,n,`SIGTERM`),r=await Z(n.wait,X),r)?r:(n.child.kill(`SIGKILL`),await Kn(t,n,`SIGKILL`),await Z(n.wait,X))}async function Z(e,t){return await Promise.race([e,d(t).then(()=>null)])}async function Kn(e,t,n){await Jn(e,t,n)||await qn(e,t.outPath,n)}async function qn(e,t,n){let i=`simctl.*recordVideo.*${Zn(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:D(e)}});return}let o=f(Xn(a.stdout),{excludePid:process.pid}),s=m(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 Jn(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 Yn(e,i,t.outPath,n),o=f([i,...a.pids],{excludePid:process.pid}),s=m(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 Yn(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:D(e)}}),{pids:[]}}return{pids:Xn(a.stdout),exitCode:a.exitCode}}function Xn(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}function Zn(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async function Qn(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a,recordingBase:o,resolvedOut:s}=e,c=o.showTouches?await zn({req:t,activeSession:n,device:r,logPath:i,deps:a}):void 0,{child:l,wait:u}=a.startIosSimulatorRecording({device:r,outPath:s}),d=await er(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 $n(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`,()=>Gn({deps:t,recording:r}),{outPath:r.outPath});if(!a)return tr(`failed to stop recording: simctl recordVideo did not exit after ${Wn}ms and forced cleanup`,r,i);if(a.exitCode!==0)return tr(`failed to stop recording: ${O(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 tr(`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: ${D(e)}`}return await n(`record_stop_finalize_overlay`,()=>k({recording:r,deps:t,targetLabel:`iOS recording`}),{outPath:r.outPath,showTouches:r.showTouches,gestureEventCount:r.gestureEvents.length}),null}async function er(e){for(let t=0;t<2;t+=1){try{if(y.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)return Date.now();await d(250)}return Date.now()}function tr(e,t,n){let r=$e(e,t,n);return nr(t.outPath),_(`COMMAND_FAILED`,r.message)}function nr(e){try{y.rmSync(e,{force:!0})}catch{}}de();function rr(e){let t=ue(e.platform)?.recording?.resolveBackendTag(e)??`unsupported`;return dr[t]}function ir(e){let{recording:t}=e;switch(t.platform){case`android`:return ur.stop({...e,recording:t});case`ios`:return lr.stop({...e,recording:t});case`ios-device-runner`:return sr.stop({...e,recording:t});case`macos-runner`:return cr.stop({...e,recording:t});case`web`:return or.stop({...e,recording:t})}return t}function Q({req:e}){return e.positionals?.[1]??s(void 0)}function ar({req:e}){let t=e.positionals?.[1];return t===void 0?s(`web`):o(t,c)}const or={validateStart:e=>pr(e),resolveOutputPath:ar,start:async({activeSession:e,recordingBase:t,resolvedOut:n})=>{let r=mr(n);if(r)return r;if(e.recordOnlySession)return _(`INVALID_ARGS`,`record on web requires an active browser session; run open <url> --platform web first`);let i=v();return i.startRecording?(await i.startRecording(n),{...t,outPath:n,startedAt:Date.now(),platform:`web`,showTouches:!1}):_(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)},stop:async({recording:e})=>await gr({recording:e}),cleanupRecordOnlySession:async()=>{try{await v().close()}catch{}}},sr={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 Bn({req:e,activeSession:t,sessionStore:n,device:r,logPath:i,deps:a,fpsFlag:o,recordingBase:s,appBundleId:c}):_(`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 Hn({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},cr={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 Vn({req:e,activeSession:t,device:n,logPath:r,deps:i,fpsFlag:a,recordingBase:o,appBundleId:s}):_(`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 Un({req:e,activeSession:t,device:n,logPath:r,deps:i,recording:a})},lr={resolveOutputPath:Q,start:async({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:o})=>await Qn({req:e,activeSession:t,device:n,logPath:r,deps:i,recordingBase:a,resolvedOut:o}),stop:async({deps:e,recording:t,stopRequestedAt:n})=>await $n({deps:e,recording:t,stopRequestedAt:n})},ur={resolveOutputPath:Q,start:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await Sn({sessionName:e,activeSession:t,device:n,recordingBase:r}),recoverMissingStop:async({sessionName:e,activeSession:t,device:n,recordingBase:r})=>await Zt({sessionName:e,activeSession:t,device:n,recordingBase:r}),stop:async({deps:e,device:t,recording:n,stopRequestedAt:r})=>await On({deps:e,device:t,recording:n,stopRequestedAt:r})},dr={web:or,android:ur,macos:cr,"ios-device":sr,"ios-simulator":lr,unsupported:{resolveOutputPath:Q,start:async()=>_(`UNSUPPORTED_OPERATION`,`record is not supported on this device`),stop:async()=>_(`UNSUPPORTED_OPERATION`,`record is not supported on this device`)}};function fr(e){let t=[];return e.flags?.fps!==void 0&&t.push(`--fps`),e.flags?.quality!==void 0&&t.push(`--quality`),e.flags?.screenshotMaxSize!==void 0&&t.push(`--max-size`),e.flags?.hideTouches!==void 0&&t.push(`--hide-touches`),t}function pr(e){let t=fr(e);return t.length>0?_(`INVALID_ARGS`,`web recordings do not support ${t.join(`, `)}; agent-browser records WebM directly`):null}function mr(e){return b.extname(e).toLowerCase()===`.webm`?null:_(`INVALID_ARGS`,`web recordings must use a ${c} output path`)}function hr(e){try{y.rmSync(e,{force:!0})}catch{}}async function gr(e){let{recording:t}=e,n=v();return n.stopRecording?(await n.stopRecording(),_r(t.outPath)?null:(hr(t.outPath),_(`COMMAND_FAILED`,`failed to stop recording: ${t.outPath} was not finalized into a WebM video`))):_(`UNSUPPORTED_OPERATION`,`record is not supported by this web provider`)}function _r(e){try{return y.statSync(e).size>0}catch{return!1}}function vr(){return{runCmd:async(e,t,n)=>e===`xcrun`?await ae(t,n):await a(e,t,n),startIosSimulatorRecording:e=>ge().startIosSimulatorRecording(e),runAppleRunnerCommand:ie,waitForRecordingTail:yr,waitForStableFile:De,isPlayableVideo:Oe,trimRecordingStart:Ye,resizeRecording:Ze,overlayRecordingTouches:Xe}}async function yr(e){e.platform===`ios`&&e.gestureEvents.length!==0&&await d(350)}function br(e,t){let n=h(e.flags?.quality);return{outPath:t,clientOutPath:e.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),maxSize:e.flags?.screenshotMaxSize,exportQuality:n??`medium`,showTouches:e.flags?.hideTouches!==!0,gestureEvents:[]}}async function xr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e,c=Sr(e);return`backend`in c?wr({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 Sr(e){let{req:t,activeSession:n,device:r}=e,i=rr(r);return Cr({req:t,activeSession:n,device:r,backend:i})||{...Ar(t,i),backend:i,fpsFlag:t.flags?.fps}}function Cr(e){let{req:t,activeSession:n,device:r,backend:i}=e,a=[()=>Tr(n),()=>i.validateStart?.(t)??null,()=>Er({fpsFlag:t.flags?.fps,qualityFlag:t.flags?.quality,maxSizeFlag:t.flags?.screenshotMaxSize}),()=>se(`record`,r)];for(let e of a){let t=e();if(t)return t}return null}function wr(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 he(r,i,t,t.command,{action:`start`,showTouches:a.showTouches}),{ok:!0,data:{recording:`started`,outPath:a.clientOutPath??o,sessionStateDir:s,showTouches:a.showTouches}}}function Tr(e){return e.recording?_(`INVALID_ARGS`,`recording already in progress`):null}function Er(e){let{fpsFlag:t,qualityFlag:n,maxSizeFlag:r}=e;return Dr(t)??Or(n)??kr(r)}function Dr(e){return e!==void 0&&(!Number.isInteger(e)||e<1||e>120)?_(`INVALID_ARGS`,`fps must be an integer between 1 and 120`):null}function Or(e){return e!==void 0&&h(e)===void 0?_(`INVALID_ARGS`,`quality must be one of: ${g.join(`, `)} (legacy numeric values 5-10 are accepted)`):null}function kr(e){return e!==void 0&&(!Number.isInteger(e)||e<1)?_(`INVALID_ARGS`,`max-size must be a positive integer`):null}function Ar(e,t){let n=t.resolveOutputPath({req:e}),r=fe.expandHome(n,e.meta?.cwd),i=br(e,r);return y.mkdirSync(b.dirname(r),{recursive:!0}),y.rmSync(r,{force:!0}),{outPath:n,resolvedOut:r,recordingBase:i}}async function jr(e){let{req:t,activeSession:n,device:r,logPath:i,deps:a}=e,o=await Mr(e);if(o&&`ok`in o)return o;if(!o)return _(`INVALID_ARGS`,`no active recording`);let s=Date.now(),c=o.invalidatedReason;return n.recording=void 0,await ir({req:t,activeSession:n,device:r,logPath:i,deps:a,recording:o,stopRequestedAt:s})||Ir(o,c)||Rr(o)}async function Mr(e){return e.activeSession.recording?e.activeSession.recording:await Nr(e)}async function Nr(e){let{req:t,sessionName:n,sessionStore:r,activeSession:i,device:a,logPath:o,deps:s}=e;if(Lr(r,a.id))return null;let c=rr(a);if(!c.recoverMissingStop)return null;let{resolvedOut:l,recordingBase:u}=Pr(t,c),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||Fr(l),d):null}function Pr(e,t){let n=t.resolveOutputPath({req:e}),r=fe.expandHome(n,e.meta?.cwd);return{resolvedOut:r,recordingBase:br(e,r)}}function Fr(e){y.mkdirSync(b.dirname(e),{recursive:!0}),y.rmSync(e,{force:!0})}function Ir(e,t){return t?e.platform===`ios`&&e.showTouches?(e.overlayWarning??=`overlay unavailable: ${t}`,null):_(`COMMAND_FAILED`,t):null}function Lr(e,t){for(let n of e.values())if(n.recording&&n.device.id===t)return!0;return!1}function Rr(e){let t=e.platform===`android`?e.chunks:void 0,n=[{field:`outPath`,artifactType:`screen-recording`,path:e.outPath,localPath:e.clientOutPath,fileName:b.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:b.basename($(e,t.index)??t.path)}))),e.telemetryPath&&n.push({field:`telemetryPath`,artifactType:`screen-recording-telemetry`,path:e.telemetryPath,localPath:zr(e),fileName:b.basename(e.telemetryPath)}),{ok:!0,data:{recording:`stopped`,outPath:e.outPath,telemetryPath:e.telemetryPath,artifacts:n,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 A(e.clientOutPath,t)}function zr(e){if(e.clientOutPath)return Fe(e.clientOutPath)}async function Br(e,t,n,r={}){n.recordOnlySession&&(await rr(n.device).cleanupRecordOnlySession?.(n),r.writeLog&&e.writeSessionLog(n),e.delete(t))}async function Vr(e){let{req:t,sessionName:n,sessionStore:r,logPath:i}=e,a=vr(),o=r.get(n),s=o?.device??await ce(t.flags??{});o||await pe(s);let c=o??{name:n,sessionScope:le(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},l=(t.positionals?.[0]??``).toLowerCase();if(![`start`,`stop`].includes(l))return _(`INVALID_ARGS`,`record requires start|stop`);if(l===`start`)return xr({req:t,sessionName:n,sessionStore:r,activeSession:c,device:s,logPath:i,deps:a});let u=await jr({req:t,sessionName:n,sessionStore:r,activeSession:c,device:s,logPath:i,deps:a});return u.ok?(he(r,c,t,t.command,{action:`stop`,outPath:u.data?.outPath,showTouches:u.data?.showTouches}),await Br(r,n,c,{writeLog:!0}),u):(await Br(r,n,c),u)}export{Vr as t};
|
|
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};
|
package/dist/src/record-trace.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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};
|