agent-device 0.18.3 → 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.18.3.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.18.3.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.18.3.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.18.3.manifest.json → agent-device-android-snapshot-helper-0.19.1.manifest.json} +6 -6
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +28 -0
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +33 -127
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +630 -177
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +155 -0
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +67 -0
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +173 -122
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +172 -0
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +64 -0
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +76 -182
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +92 -51
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +213 -137
- package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +142 -0
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +208 -46
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +82 -11
- package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +74 -0
- package/dist/src/agent-browser-tool.js +1 -0
- package/dist/src/android-adb.d.ts +63 -234
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-ownership.js +6 -0
- package/dist/src/android.js +1 -5
- package/dist/src/app-lifecycle.js +7 -0
- package/dist/src/apple-runner-options.js +1 -0
- package/dist/src/apps.js +5 -11
- package/dist/src/artifacts.d.ts +4 -3
- package/dist/src/artifacts.js +1 -1
- package/dist/src/audio-probe.js +1 -1
- package/dist/src/batch.d.ts +2 -177
- package/dist/src/batch.js +1 -1
- package/dist/src/cli-help.js +178 -60
- package/dist/src/cli-output.js +1 -1
- package/dist/src/cli-runner.js +2 -0
- package/dist/src/cli.js +12 -41
- package/dist/src/client-metro-companion.js +1 -0
- package/dist/src/client.js +3 -0
- package/dist/src/command-metadata.js +1 -0
- package/dist/src/command-schema.js +22 -0
- package/dist/src/command-surface.js +1 -1
- package/dist/src/contracts.d.ts +2 -213
- package/dist/src/contracts.js +1 -1
- package/dist/src/debug-symbols.js +5 -3
- package/dist/src/device-input-state.js +2 -0
- package/dist/src/devices.js +1 -1
- package/dist/src/devices2.js +1 -0
- package/dist/src/devices3.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.d.ts +2 -81
- package/dist/src/finders.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/handler-utils.js +1 -1
- package/dist/src/helper.js +2 -0
- package/dist/src/host-process.js +2 -0
- package/dist/src/index.d.ts +1444 -1786
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +3 -1
- package/dist/src/input-actions2.js +1 -0
- package/dist/src/install-source.d.ts +13 -14
- package/dist/src/install-source.js +1 -1
- package/dist/src/install-source2.js +1 -0
- package/dist/src/interaction-snapshot.js +1 -0
- package/dist/src/interaction.js +1 -1
- package/dist/src/interactor.js +2 -1
- package/dist/src/internal/bin.d.ts +1 -1
- package/dist/src/internal/bin.js +2 -5
- package/dist/src/internal/companion-tunnel.d.ts +1 -1
- package/dist/src/internal/companion-tunnel.js +1 -1
- package/dist/src/internal/daemon.d.ts +1 -1
- package/dist/src/internal/daemon.js +18 -1
- package/dist/src/internal/png-worker.d.ts +29 -26
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/update-check-entry.d.ts +1 -1
- package/dist/src/internal/update-check-entry.js +1 -1
- package/dist/src/io.d.ts +2 -85
- package/dist/src/io.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/manifest.js +1 -0
- package/dist/src/metro.d.ts +69 -113
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -0
- package/dist/src/notifications.js +1 -1
- package/dist/src/output-path.js +1 -0
- package/dist/src/path-resolution.js +1 -0
- package/dist/src/png-worker-contract.js +1 -0
- package/dist/src/points.js +4 -0
- package/dist/src/project-runtime.js +1 -0
- package/dist/src/provider.js +1 -1
- package/dist/src/providers.js +1 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace-recording.js +2 -5
- package/dist/src/record-trace.js +1 -1
- package/dist/src/recording-provider.js +1 -1
- package/dist/src/registry.js +38 -0
- package/dist/src/remote-config.d.ts +2 -83
- package/dist/src/reporting.js +9 -0
- package/dist/src/rolldown-runtime.js +1 -0
- package/dist/src/runner-client.js +1 -0
- package/dist/src/runner-provider.js +1 -0
- package/dist/src/runner-sequence.js +1 -1
- package/dist/src/runtime-transport.js +1 -0
- package/dist/src/runtime.js +3 -0
- package/dist/src/scoped-provider.js +1 -0
- package/dist/src/sdk-android-adb.d.ts +144 -0
- package/dist/src/sdk-android-adb.js +4 -0
- package/dist/src/sdk-app-inventory.d.ts +4 -0
- package/dist/src/sdk-app-inventory.js +1 -0
- package/dist/src/sdk-batch-runner.d.ts +39 -0
- package/dist/src/sdk-batch-runner.js +2 -0
- package/dist/src/sdk-batch.js +2 -0
- package/dist/src/sdk-contracts.d.ts +386 -0
- package/dist/src/sdk-contracts.js +2 -0
- package/dist/src/sdk-finders.d.ts +60 -0
- package/dist/src/sdk-finders.js +1 -0
- package/dist/src/sdk-io.d.ts +78 -0
- package/dist/src/sdk-io.js +1 -0
- package/dist/src/sdk-remote-config.d.ts +139 -0
- package/dist/src/sdk-remote-config.js +1 -0
- package/dist/src/sdk-selectors.js +1 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +38 -137
- package/dist/src/selectors.js +1 -1
- package/dist/src/selectors2.js +1 -0
- package/dist/src/server.js +3 -2
- package/dist/src/session.js +10 -11
- package/dist/src/setting-state.js +1 -0
- package/dist/src/simctl.js +1 -0
- package/dist/src/simulator.js +1 -2
- package/dist/src/snapshot-diagnostics.js +3 -0
- package/dist/src/snapshot-helper.js +5 -0
- package/dist/src/snapshot-quality.js +1 -0
- package/dist/src/snapshot.js +1 -2
- package/dist/src/snapshot2.js +2 -0
- package/dist/src/{5560.js → timeouts.js} +1 -1
- package/dist/src/tool-provider.js +3 -0
- package/dist/src/tool-provider2.js +1 -0
- package/dist/src/ttl-memo.js +1 -0
- package/dist/src/tv-remote.js +14 -0
- package/dist/src/update-check.js +1 -0
- package/dist/src/url.js +1 -0
- package/dist/src/version.js +1 -0
- package/dist/src/web.js +1 -1
- package/dist/src/xml.js +2 -0
- package/package.json +13 -19
- package/server.json +2 -2
- package/skills/agent-device/SKILL.md +8 -7
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.18.3.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.18.3.apk.sha256 +0 -1
- package/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +0 -443
- package/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -169
- package/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +0 -220
- package/dist/src/1404.js +0 -1
- package/dist/src/1986.js +0 -1
- package/dist/src/2748.js +0 -1
- package/dist/src/2948.js +0 -30
- package/dist/src/3006.js +0 -1
- package/dist/src/314.js +0 -1
- package/dist/src/3340.js +0 -8
- package/dist/src/4418.js +0 -1
- package/dist/src/4428.js +0 -3
- package/dist/src/485.js +0 -1
- package/dist/src/4917.js +0 -1
- package/dist/src/495.js +0 -5
- package/dist/src/5448.js +0 -3
- package/dist/src/5484.js +0 -1
- package/dist/src/5643.js +0 -1
- package/dist/src/587.js +0 -1
- package/dist/src/5913.js +0 -4
- package/dist/src/6849.js +0 -1
- package/dist/src/6918.js +0 -1
- package/dist/src/6967.js +0 -1
- package/dist/src/760.js +0 -1
- package/dist/src/7871.js +0 -1
- package/dist/src/8184.js +0 -1
- package/dist/src/8225.js +0 -1
- package/dist/src/8391.js +0 -1
- package/dist/src/8404.js +0 -2
- package/dist/src/8414.js +0 -2
- package/dist/src/8875.js +0 -4
- package/dist/src/893.js +0 -1
- package/dist/src/8936.js +0 -1
- package/dist/src/9414.js +0 -1
- package/dist/src/9581.js +0 -22
- package/dist/src/9612.js +0 -1
- package/dist/src/9624.js +0 -1
- package/dist/src/9722.js +0 -39
- package/dist/src/devices~1.js +0 -1
- package/dist/src/devices~2.js +0 -1
- package/dist/src/input-actions~1.js +0 -1
- package/dist/src/rslib-runtime.js +0 -1
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/xcshareddata/xcschemes/AgentDeviceRunner.xcscheme +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests-Bridging-Header.h +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests.entitlements +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerObjCExceptionCatcher.h +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerObjCExceptionCatcher.m +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/AgentDeviceRunnerUITests.xctestplan +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/RecordingScripts/recording-resize.swift +0 -0
- /package/{apple-runner → dist/apple-runner}/AgentDeviceRunner/RecordingScripts/recording-trim.swift +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import Foundation
|
|
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
|
|
3
2
|
import AVFoundation
|
|
4
3
|
|
|
5
4
|
let url = URL(fileURLWithPath: CommandLine.arguments[1])
|
|
@@ -21,6 +20,4 @@ Task {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
semaphore.wait()
|
|
24
|
-
exit(exitCode)
|
|
25
|
-
`.trim();async function J(e,t={}){let r,a=t.pollMs??150,o=t.attempts??12,n=0;for(let t=0;t<o;t+=1){let t=0;try{t=i.statSync(e).size}catch{t=0}if(t>0&&t===r){if((n+=1)>=2)return}else n=0;r=t,await f(a)}}async function X(e){try{let t=await Z(),r=await p(t,[e],{allowFailure:!0,timeoutMs:1e4,env:z()});if(0===r.exitCode)return!0;if(ee(r.stderr,r.stdout))return et(e);return!1}catch(r){var t;if((t=r)instanceof d&&("TOOL_MISSING"===t.code||ee(String(t.details?.stderr??""),String(t.details?.stdout??""))))return et(e);throw r}}async function Z(){e??=G({source:Q,cacheName:"video-validator",timeoutMs:3e4});try{return await e}catch(t){throw e=void 0,t}}async function Y(e,t={}){let r=t.pollMs??150,a=t.attempts??12;for(let t=0;t<a;t+=1){if(await X(e))return;await f(r)}}function ee(e,t){let r=`${e}
|
|
26
|
-
${t}`;return/\b(no such module ['"]AVFoundation['"]|unable to find utility ["']swiftc?["']|xcrun: error: unable to find utility ["']swiftc?["'])\b/i.test(r)}function et(e){try{let t=i.statSync(e);if(!t.isFile()||t.size<=0)return!1}catch{return!1}let t=function(e){try{let t=i.openSync(e,"r");try{let e=i.fstatSync(t).size,r=0,a=[];for(;r+8<=e&&a.length<16;){let e=Buffer.alloc(8);if(8>i.readSync(t,e,0,8,r))break;let o=e.readUInt32BE(0),n=e.toString("latin1",4,8);if(a.push(n),1===o){let e=Buffer.alloc(8);if(8>i.readSync(t,e,0,8,r+8))break;o=Number(e.readBigUInt64BE(0))}if(!Number.isFinite(o)||o<=0)break;r+=o}return a}finally{i.closeSync(t)}}catch{return[]}}(e);return t.includes("ftyp")&&t.includes("moov")}function er(e){let t=o.parse(e);return o.join(t.dir,`${t.name}.gesture-telemetry.json`)}function ea(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function ei(e){var t,r,a;let o,n,{recording:s,trimStartMs:c}=e,d=(o=er((t={videoPath:s.outPath,events:s.gestureEvents,trimStartMs:c}).videoPath),n={version:1,generatedAt:new Date().toISOString(),events:(r=t.events,(a=t.trimStartMs??0)>0?ea(r.flatMap(e=>{let t=e.tMs-a,r="durationMs"in e?e.durationMs:void 0;return("number"==typeof r?t+r:t)<=0?[]:[{...e,tMs:Math.max(0,t)}]})):ea(r))},i.writeFileSync(o,JSON.stringify(n,null,2)),o);return s.telemetryPath=d,d}function eo(e){let t=o.dirname(c(import.meta.url)),r=[c(new URL(`./${e}`,import.meta.url)),o.resolve(t,`../../apple-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(t,`../../../apple-runner/AgentDeviceRunner/RecordingScripts/${e}`),o.resolve(process.cwd(),`apple-runner/AgentDeviceRunner/RecordingScripts/${e}`)];for(let e of r)if(i.existsSync(e))return e;throw new d("COMMAND_FAILED",`Missing recording helper script: ${e}`,{hint:"Ensure apple-runner/AgentDeviceRunner/RecordingScripts is present in this checkout or bundled with the package.",scriptName:e,searchedPaths:r})}async function en(e){var t;let r,a,{videoPath:n,scriptPath:s,scriptArgs:c,commandDescription:u}=e;await J(n),await Y(n);let l=(t=n,r=o.parse(t),a=`${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,o.join(r.dir,`.${r.name}.agent-device-${a}${r.ext||".mp4"}`));try{let e=await K({sourcePath:s});await p(e,["--input",n,"--output",l,...c],{timeoutMs:12e4,env:z()}),await Y(l),i.renameSync(l,n)}catch(t){let e=t instanceof d?t:new d("COMMAND_FAILED",String(t),void 0,t instanceof Error?t:void 0);throw new d("COMMAND_FAILED",u,{...e.details,videoPath:n,script:s},e)}finally{i.rmSync(l,{force:!0})}}async function es(e){let{videoPath:t,trimStartMs:a}=e;a>0&&await en({videoPath:t,scriptPath:r??=eo("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(a)],commandDescription:"Failed to trim the start of the iOS recording"})}async function ec(e){let{videoPath:r,telemetryPath:a,exportQuality:i="medium",targetLabel:o="recording"}=e;await en({videoPath:r,scriptPath:t??=eo("recording-overlay.swift"),scriptArgs:["--events",a,"--quality",i],commandDescription:`Failed to add touch overlays to the ${o}`})}async function ed(e){let{videoPath:t,maxSize:r,exportQuality:i="medium",targetLabel:o="recording"}=e;await en({videoPath:t,scriptPath:a??=eo("recording-resize.swift"),scriptArgs:["--max-size",String(r),"--quality",i],commandDescription:`Failed to resize the ${o}`})}function eu(e){return e instanceof Error?e.message:String(e)}function el(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function ep(e,t,r=Date.now()){let a=Math.max(0,r-t.startedAt);return a>=1e3?{message:e,tooShort:!1}:{message:`${e}. Recording stopped after ${Math.round(a)}ms; wait at least 1000ms between record start and record stop so the recorder can finalize a playable MP4`,tooShort:!0}}async function em(e){let{recording:t,deps:r,trimStartMs:a,targetLabel:i}=e,o=ei({recording:t,trimStartMs:a});if(!t.showTouches)return void l({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void l({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"no_gesture_events"}});let n=function(e=process.platform){if("darwin"!==e)return"touch overlay burn-in is only available on macOS hosts; returning raw video plus gesture telemetry"}();if(n){t.overlayWarning??=n;return}try{await u("record_stop_overlay_export",()=>r.overlayRecordingTouches({videoPath:t.outPath,telemetryPath:o,exportQuality:t.exportQuality,targetLabel:i}),{targetLabel:i,gestureEventCount:t.gestureEvents.length})}catch(e){t.overlayWarning??=`failed to overlay recording touches: ${eu(e)}`}}function eh(e,t){if(1===t)return e;let r=o.parse(e),a=r.ext||".mp4";return o.join(r.dir,`${r.name}.part-${String(t).padStart(3,"0")}${a}`)}function ef(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function ew(e){let{recording:t,startNextChunk:r,finishCurrentChunk:a}=e;if(t.stopping)return;let i=await a();if(i)throw Error(i);if(t.stopping)return;let n=ef(t),s=n.length+1,c=await r(o.posix.dirname(t.remotePath));t.remotePath=c.remotePath,t.remotePid=c.remotePid,n.push({index:s,path:eh(t.outPath,s),remotePath:c.remotePath}),t.warning??="Android adb screenrecord is capped at 180s, so this recording was split into multiple MP4 chunks."}async function eg(e){let{recording:t,deps:r}=e;ef(t).length<=1?await em({recording:t,deps:r,targetLabel:"Android recording"}):(ei({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 ey(e){for(let t of e.chunks){let r=await e_({deps:e.deps,deviceId:e.deviceId,remotePath:t.remotePath,outPath:t.path});if(r)return`failed to copy recording chunk ${t.index}: ${r}`}}async function e_(e){let t,{deps:r,deviceId:a,remotePath:o,outPath:n}=e;for(let e=0;e<2;e+=1){ev(n);let s=w(a),c=await y(o,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=el(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(l({level:"debug",phase:"record_stop_android_pull_validation",data:{deviceId:a,remotePath:o,outPath:n,attempt:e+1,fileSize:function(e){try{return i.statSync(e).size}catch{return 0}}(n),playable:t}}),t)return;l({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:a,remotePath:o,outPath:n,attempt:e+1}})}e<1&&await f(750)}return t?`failed to copy recording from device: ${t}`:(ev(n),"failed to copy recording from device: pulled file is not a playable MP4")}function ev(e){try{i.rmSync(e,{force:!0})}catch{}}let eP={medium:8e6,high:2e7};async function eS(e,t,r){return await g(w(e),t,r)}async function eA(e,t){let r=await eS(e,["shell","ps","-o","pid=","-p",t],{allowFailure:!0});return 0===r.exitCode&&r.stdout.split(/\s+/).map(e=>e.trim()).includes(t)}async function eb(e,t){for(let r=0;r<40;r+=1){if(!await eA(e,t))return!0;await f(250)}return!await eA(e,t)}async function eM(e,t){let r,a=0;for(let i=0;i<20;i+=1){let i=await eS(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?i.stdout.trim():"";if(o.length>0&&o===r){if((a+=1)>=4)return}else a=0;r=o,await f(250)}}async function eC(e,t,r){for(let a=0;a<8;a+=1){let i=await eS(e,["shell","stat","-c","%s",t],{allowFailure:!0}),o=0===i.exitCode?Number(i.stdout.trim()):NaN;if(Number.isFinite(o)&&o>0)return!0;if(!await eA(e,r))break;if(a+1>=2)return!0;await f(250)}return!1}async function ex(e){let{deviceId:t,maxSize:r}=e;if(void 0===r)return;let a=await eS(t,["shell","wm","size"],{allowFailure:!0}),i=a.stdout.match(/Override size:\s*(\d+)x(\d+)/)??a.stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(0!==a.exitCode||!i)throw Error(`failed to resolve Android screen size for recording max-size: ${el(a,"adb shell wm size")}`);var o={width:Number(i[1]),height:Number(i[2]),maxSize:r};let n=Math.max(o.width,o.height);if(n<=o.maxSize)return{width:o.width,height:o.height};let s=o.maxSize/n;return{width:eR(o.width,s),height:eR(o.height,s)}}function eR(e,t){return Math.max(2,2*Math.round(e*t/2))}async function eI(e,t){await eS(e,["shell","rm","-f",t],{allowFailure:!0})}async function eD(e,t){let r=await eS(e,["shell","kill","-9",t],{allowFailure:!0});return l({level:"warn",phase:"record_stop_android_force_signal",data:{deviceId:e,remotePid:t,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),!(0!==r.exitCode&&await eA(e,t))&&await eb(e,t)}async function eN(e){var t;let r,a,{device:i,recordingSize:o,quality:n,preferredRemoteDir:s}=e,c="failed to start recording: Android screenrecord did not begin producing frames";for(let e of(t=Date.now(),r=`agent-device-recording-${t}.mp4`,a=["/sdcard","/data/local/tmp"],(s&&a.includes(s)?[s,...a.filter(e=>e!==s)]:a).map(e=>`${e}/${r}`))){let t=await eS(i.id,["shell",function(e,t,r){let a=["screenrecord"];return t&&a.push("--size",`${t.width}x${t.height}`),a.push("--bit-rate",String(eP[r])),a.push(e),`${a.join(" ")} >/dev/null 2>&1 & echo $!`}(e,o,n)],{allowFailure:!0});if(0!==t.exitCode){c=`failed to start recording: ${el(t,"adb shell screenrecord")}`;continue}let r=t.stdout.split(/\r?\n/).map(e=>e.trim()).filter(e=>/^\d+$/.test(e)).at(-1);if(!r){c="failed to start recording: adb did not return a valid Android screenrecord pid",await eI(i.id,e);continue}if(l({level:"debug",phase:"record_start_android_started",data:{deviceId:i.id,remotePath:e,remotePid:r}}),await eC(i.id,e,r))return{remotePath:e,remotePid:r,startedAt:Date.now()};c="failed to start recording: Android screenrecord did not begin producing frames",await eD(i.id,r),await eI(i.id,e)}return{error:b("COMMAND_FAILED",c)}}async function eE(e){let t,{device:r,recordingBase:a}=e;try{t=await ex({deviceId:r.id,maxSize:a.maxSize})}catch(e){return b("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let i=a.exportQuality??"medium",o=await eN({device:r,recordingSize:t,quality:i});if("error"in o)return o.error;let n={platform:"android",remotePath:o.remotePath,remotePid:o.remotePid,chunks:[{index:1,path:a.outPath,remotePath:o.remotePath}],...a,startedAt:o.startedAt};return!function e(t){let{recording:r,startNextChunk:a,finishCurrentChunk:i}=t,o=setTimeout(()=>{r.rotationPromise=ew({recording:r,startNextChunk:a,finishCurrentChunk:i}).catch(e=>{r.rotationFailedReason=e instanceof Error?e.message:String(e)}).finally(()=>{r.rotationPromise=void 0,r.stopping||r.rotationFailedReason||e({recording:r,startNextChunk:a,finishCurrentChunk:i})})},17e4);o.unref?.(),r.rotationTimer=o}({recording:n,finishCurrentChunk:async()=>await e$({device:r,recording:n,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let a=await eN({device:r,recordingSize:t,quality:i,preferredRemoteDir:e});if("error"in a)throw Error(a.error.ok?"failed to start next Android recording chunk":a.error.error.message);return a}}),n}async function e$(e){let{device:t,recording:r,waitForRemoteFileStability:a=!0}=e;await eA(t.id,r.remotePid)||(r.warning??=function(e){if(!(Date.now()-e.startedAt<178e3))return"Android adb screenrecord stopped before record stop, likely after reaching the 180s platform limit. The MP4 may be truncated; final interactions after the limit are not in the video."}(r));let i=await eS(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(l({level:"debug",phase:"record_stop_android_signal",data:{deviceId:t.id,remotePath:r.remotePath,remotePid:r.remotePid,exitCode:i.exitCode,stdout:i.stdout.trim(),stderr:i.stderr.trim()}}),0!==i.exitCode)return await eO(t.id,r.remotePid,i);let o=await ek(t.id,r.remotePid);if(o)return o;a&&await eM(t.id,r.remotePath)}async function eO(e,t,r){if(await eA(e,t)&&!await eD(e,t))return`failed to stop recording: ${el(r,"adb shell kill")}`}async function ek(e,t){if(!await eb(e,t)&&!await eD(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function eF(e){let t,{deps:r,device:a,recording:i,stopRequestedAt:o}=e;l({level:"debug",phase:"record_stop_android_enter",data:{deviceId:a.id,remotePath:i.remotePath,remotePid:i.remotePid}}),i.stopping=!0,i.rotationTimer&&(clearTimeout(i.rotationTimer),i.rotationTimer=void 0),await i.rotationPromise;let n=await e$({device:a,recording:i});if(i.rotationFailedReason&&!n&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`),!n){let e=await ey({deps:r,deviceId:a.id,chunks:ef(i)});if(e)return await s(),b("COMMAND_FAILED",eT(e,i,o));await eg({recording:i,deps:r})}if(await s(),n)return b("COMMAND_FAILED",eT(n,i,o));if(t)return b("COMMAND_FAILED",t);return null;async function s(){for(let e of ef(i)){let r=await eS(a.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});l({level:"debug",phase:"record_stop_android_cleanup",data:{deviceId:a.id,remotePath:e.remotePath,exitCode:r.exitCode,stdout:r.stdout.trim(),stderr:r.stderr.trim()}}),0===r.exitCode||n||(t=`failed to clean up remote recording: ${el(r,"adb shell rm")}`)}}}function eT(e,t,r){return ep(e,t,r).message}function eL(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function eU(e,t,r){return N({req:e,logPath:t,traceLogPath:r.trace?.outPath})}async function ez(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=eL(r);try{await o.runAppleRunnerCommand(a,{command:"recordStop",appBundleId:n},eU(t,i,r))}catch(e){l({level:"warn",phase:"record_stop_runner_failed",data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:r.name,error:eu(e)}})}}async function eK(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=eL(r);if(n)try{let e=await o.runAppleRunnerCommand(a,{command:"snapshot",appBundleId:n,interactiveOnly:!0,depth:1},eU(t,i,r)),s=Date.now();if("number"==typeof e.currentUptimeMs&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0)return l({level:"debug",phase:"record_start_gesture_clock_anchor",data:{source:"warm_snapshot"}}),{gestureClockOriginAtMs:s,gestureClockOriginUptimeMs:e.currentUptimeMs};return}catch(e){l({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:a.id,session:r.name,appBundleId:n,error:eu(e)}});return}}async function eG(e){let t,r,{req:a,activeSession:i,sessionStore:o,device:n,logPath:s,deps:c,fpsFlag:d,recordingBase:u,appBundleId:p}=e,m=`agent-device-recording-${Date.now()}.mp4`,h=`tmp/${m}`,f=eU(a,s,i),w=async()=>c.runAppleRunnerCommand(n,{command:"recordStart",outPath:m,fps:d,maxSize:u.maxSize,appBundleId:p},f);try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(a){var g,y;if(!eu(a).toLowerCase().includes("recording already in progress"))return b("COMMAND_FAILED",`failed to start recording: ${eu(a)}`);l({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:i.name,error:eu(a)}});let e=(g=n.id,y=i.name,o.toArray().find(e=>e.name!==y&&D(e.device)&&"device"===e.device.kind&&e.device.id===g&&e.recording?.platform==="ios-device-runner"));if(e)return b("COMMAND_FAILED",`failed to start recording: recording already in progress in session '${e.name}'`);try{await c.runAppleRunnerCommand(n,{command:"recordStop",appBundleId:p},f)}catch{}try{let e=await w();t="number"==typeof e.recorderStartUptimeMs?e.recorderStartUptimeMs:void 0,r="number"==typeof e.targetAppReadyUptimeMs?e.targetAppReadyUptimeMs:void 0}catch(e){return b("COMMAND_FAILED",`failed to start recording: ${eu(e)}`)}}return{platform:"ios-device-runner",remotePath:h,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...u}}async function eV(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}=e;try{await o.runAppleRunnerCommand(a,{command:"recordStart",outPath:s.outPath,fps:n,maxSize:s.maxSize,appBundleId:c},eU(t,i,r))}catch(e){return b("COMMAND_FAILED",`failed to start recording: ${eu(e)}`)}return{platform:"macos-runner",...s}}async function eH(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;await ez({req:t,activeSession:r,device:a,logPath:i,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of S)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",a.id,"--source",n.remotePath,"--destination",n.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(0!==s.exitCode){let e=s.stderr.trim()||s.stdout.trim()||`devicectl exited with code ${s.exitCode}`;return b("COMMAND_FAILED",`failed to copy recording from device: ${e}`)}let c="number"!=typeof n.runnerStartedAtUptimeMs||"number"!=typeof n.targetAppReadyUptimeMs?0:Math.max(0,n.targetAppReadyUptimeMs-n.runnerStartedAtUptimeMs);return c>0&&await o.trimRecordingStart({videoPath:n.outPath,trimStartMs:c}),await em({recording:n,deps:o,trimStartMs:c,targetLabel:"iOS recording"}),null}async function ej(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;return await ez({req:t,activeSession:r,device:a,logPath:i,deps:o}),await em({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eq(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let a=await eW(r.wait,5e3);return a||(await eB(t,r,"SIGINT"),(a=await eW(r.wait,2e3))||(r.child.kill("SIGTERM"),await eB(t,r,"SIGTERM"),a=await eW(r.wait,2e3)))?a:(r.child.kill("SIGKILL"),await eB(t,r,"SIGKILL"),await eW(r.wait,2e3))}async function eW(e,t){return await Promise.race([e,f(t).then(()=>null)])}async function eB(e,t,r){await eJ(e,t,r)||await eQ(e,t.outPath,r)}async function eQ(e,t,r){let a,i=`simctl.*recordVideo.*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`;try{a=await e.runCmd("pgrep",["-f",i],{allowFailure:!0})}catch(e){l({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:eu(e)}});return}let o=eZ(e0(a.stdout)),n=eY(o,r);l({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_recorders",data:{outPath:t,signal:r,matchedPidCount:o.length,signaled:n,pgrepExitCode:a.exitCode}})}async function eJ(e,t,r){let a=t.recorderPid??t.child.pid;if("number"!=typeof a||!Number.isInteger(a)||a<=0)return l({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let i=await eX(e,a,t.outPath,r),o=eZ([a,...i.pids]),n=eY(o,r);return l({level:n>0?"warn":"debug",phase:"record_stop_ios_simulator_signal_owned_recorder",data:{outPath:t.outPath,signal:r,recorderPid:a,childPidCount:i.pids.length,matchedPidCount:o.length,signaled:n,pgrepExitCode:i.exitCode}}),n>0}async function eX(e,t,r,a){let i;try{i=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return l({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:a,parentPid:t,error:eu(e)}}),{pids:[]}}return{pids:e0(i.stdout),exitCode:i.exitCode}}function eZ(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eY(e,t){let r=0;for(let a of e)try{process.kill(a,t),r+=1}catch{}return r}function e0(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}async function e1(e){let t,r,{req:a,activeSession:i,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e,u=c.showTouches?await eK({req:a,activeSession:i,device:o,logPath:n,deps:s}):void 0,{child:l,wait:p}=s.startIosSimulatorRecording({device:o,outPath:d}),m=await e4(d);if(u)t=u.gestureClockOriginAtMs,r=u.gestureClockOriginUptimeMs;else if(c.showTouches)try{let e=Date.now(),c=await s.runAppleRunnerCommand(o,{command:"uptime",appBundleId:eL(i)},eU(a,n,i)),d=Date.now();t=Math.round((e+d)/2),r="number"==typeof c.currentUptimeMs?c.currentUptimeMs:void 0}catch{}return{platform:"ios",child:l,wait:p,...c,recorderPid:l.pid,startedAt:m,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function e2(e){let{deps:t,recording:r,stopRequestedAt:a}=e;await u("record_stop_tail_settle",()=>t.waitForRecordingTail(r),{platform:r.platform,gestureEventCount:r.gestureEvents.length});let i=await u("record_stop_ios_simulator_process",()=>eq({deps:t,recording:r}),{outPath:r.outPath});if(!i)return e5("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",r,a);if(0!==i.exitCode)return e5(`failed to stop recording: ${el(i,"simctl recordVideo")}`,r,a);if(await u("record_stop_video_stable",()=>t.waitForStableFile(r.outPath,{pollMs:150,attempts:12}),{outPath:r.outPath}),!await u("record_stop_video_playable_check",()=>t.isPlayableVideo(r.outPath),{outPath:r.outPath}))return e5(`failed to stop recording: ${r.outPath} was not finalized into a playable video`,r,a);if(void 0!==r.maxSize)try{await u("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: ${eu(e)}`}return await u("record_stop_finalize_overlay",()=>em({recording:r,deps:t,targetLabel:"iOS recording"}),{outPath:r.outPath,showTouches:r.showTouches,gestureEventCount:r.gestureEvents.length}),null}async function e4(e){for(let t=0;t<2;t+=1){try{if(i.statSync(e).size>0)return Date.now()}catch{}if(t+1>=2)break;await f(250)}return Date.now()}function e5(e,t,r){let a=ep(e,t,r);return function(e){try{i.rmSync(e,{force:!0})}catch{}}(t.outPath),b("COMMAND_FAILED",a.message)}function e8(e){return tr[v(e.platform)?.recording?.resolveBackendTag(e)??"unsupported"]}function e3({req:e}){return e.positionals?.[1]??$(void 0)}x();let e6={validateStart:e=>(function(e){let t,r=(t=[],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);return r.length>0?b("INVALID_ARGS",`web recordings do not support ${r.join(", ")}; agent-browser records WebM directly`):null})(e),resolveOutputPath:function({req:e}){let t=e.positionals?.[1];return void 0===t?$("web"):O(t,".webm")},start:async({activeSession:e,recordingBase:t,resolvedOut:r})=>{var a;let i=(a=r,".webm"!==o.extname(a).toLowerCase()?b("INVALID_ARGS","web recordings must use a .webm output path"):null);if(i)return i;if(e.recordOnlySession)return b("INVALID_ARGS","record on web requires an active browser session; run open <url> --platform web first");let n=k();return n.startRecording?(await n.startRecording(r),{...t,outPath:r,startedAt:Date.now(),platform:"web",showTouches:!1}):b("UNSUPPORTED_OPERATION","record is not supported by this web provider")},stop:async({recording:e})=>await ta({recording:e}),cleanupRecordOnlySession:async()=>{try{await k().close()}catch{}}},e7={resolveOutputPath:e3,start:async({req:e,activeSession:t,sessionStore:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s})=>{let c=eL(t);return c?await eG({req:e,activeSession:t,sessionStore:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}):b("INVALID_ARGS","record on physical iOS devices requires an active app session; run open <app> first")},stop:async({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})=>await eH({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})},e9={resolveOutputPath:e3,start:async({req:e,activeSession:t,device:r,logPath:a,deps:i,fpsFlag:o,recordingBase:n})=>{let s=eL(t);return s?await eV({req:e,activeSession:t,device:r,logPath:a,deps:i,fpsFlag:o,recordingBase:n,appBundleId:s}):b("INVALID_ARGS","record on macOS requires an active app session; run open <app> first")},stop:async({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})=>await ej({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})},te={resolveOutputPath:e3,start:async({req:e,activeSession:t,device:r,logPath:a,deps:i,recordingBase:o,resolvedOut:n})=>await e1({req:e,activeSession:t,device:r,logPath:a,deps:i,recordingBase:o,resolvedOut:n}),stop:async({deps:e,recording:t,stopRequestedAt:r})=>await e2({deps:e,recording:t,stopRequestedAt:r})},tt={resolveOutputPath:e3,start:async({device:e,recordingBase:t})=>await eE({device:e,recordingBase:t}),stop:async({deps:e,device:t,recording:r,stopRequestedAt:a})=>await eF({deps:e,device:t,recording:r,stopRequestedAt:a})},tr={web:e6,android:tt,macos:e9,"ios-device":e7,"ios-simulator":te,unsupported:{resolveOutputPath:e3,start:async()=>b("UNSUPPORTED_OPERATION","record is not supported on this device"),stop:async()=>b("UNSUPPORTED_OPERATION","record is not supported on this device")}};async function ta(e){let{recording:t}=e,r=k();if(!r.stopRecording)return b("UNSUPPORTED_OPERATION","record is not supported by this web provider");if(await r.stopRecording(),!function(e){try{return i.statSync(e).size>0}catch{return!1}}(t.outPath)){var a=t.outPath;try{i.rmSync(a,{force:!0})}catch{}return b("COMMAND_FAILED",`failed to stop recording: ${t.outPath} was not finalized into a WebM video`)}return null}async function ti(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await f(350)}async function to(e){let t,{req:r,sessionName:a,sessionStore:n,activeSession:s,device:c,logPath:d,deps:u}=e;if(s.recording)return b("INVALID_ARGS","recording already in progress");let l=r.flags?.fps,p=r.flags?.quality,m=r.flags?.screenshotMaxSize,h=e8(c),f=h.validateStart?.(r)??null;if(f)return f;if(void 0!==l&&(!Number.isInteger(l)||l<1||l>120))return b("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==p&&void 0===T(p))return b("INVALID_ARGS",`quality must be one of: ${L.join(", ")} (legacy numeric values 5-10 are accepted)`);if(void 0!==m&&(!Number.isInteger(m)||m<1))return b("INVALID_ARGS","max-size must be a positive integer");let w=A("record",c);if(w)return w;let g=h.resolveOutputPath({req:r}),y=P.expandHome(g,r.meta?.cwd),_=(t=T(r.flags?.quality),{outPath:y,clientOutPath:r.meta?.clientArtifactPaths?.outPath,startedAt:Date.now(),maxSize:r.flags?.screenshotMaxSize,exportQuality:t??"medium",showTouches:r.flags?.hideTouches!==!0,gestureEvents:[]});i.mkdirSync(o.dirname(y),{recursive:!0}),i.rmSync(y,{force:!0});let v=await h.start({req:r,activeSession:s,sessionStore:n,device:c,logPath:d,deps:u,fpsFlag:l,recordingBase:_,resolvedOut:y});if("ok"in v)return v;s.recording=v,n.set(a,s);let S=n.ensureSessionDir(a);return U(n,s,r,r.command,{action:"start",showTouches:v.showTouches}),{ok:!0,data:{recording:"started",outPath:v.clientOutPath??g,sessionStateDir:S,showTouches:v.showTouches}}}async function tn(e){var t;let r,a,{req:i,activeSession:n,device:s,logPath:c,deps:d}=e;if(!n.recording)return b("INVALID_ARGS","no active recording");let u=n.recording,l=Date.now(),p=u.invalidatedReason;n.recording=void 0;let m=await function(e){let{recording:t}=e;switch(t.platform){case"android":return tt.stop({...e,recording:t});case"ios":return te.stop({...e,recording:t});case"ios-device-runner":return e7.stop({...e,recording:t});case"macos-runner":return e9.stop({...e,recording:t});case"web":return e6.stop({...e,recording:t})}return t}({req:i,activeSession:n,device:s,logPath:c,deps:d,recording:u,stopRequestedAt:l});if(m)return m;if(p&&"ios"===u.platform&&u.showTouches)u.overlayWarning??=`overlay unavailable: ${p}`;else if(p)return b("COMMAND_FAILED",p);return r="android"===(t=u).platform?t.chunks:void 0,a=[{field:"outPath",path:t.outPath,localPath:t.clientOutPath,fileName:o.basename(t.clientOutPath??t.outPath)}],r&&r.length>1&&a.push(...r.slice(1).map(e=>({field:"chunkPath",path:e.path,localPath:ts(t,e.index),fileName:o.basename(ts(t,e.index)??e.path)}))),t.telemetryPath&&a.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return er(e.clientOutPath)}(t),fileName:o.basename(t.telemetryPath)}),{ok:!0,data:{recording:"stopped",outPath:t.outPath,telemetryPath:t.telemetryPath,artifacts:a,showTouches:t.showTouches,warning:t.warning,overlayWarning:t.overlayWarning,chunks:r?.map(e=>({index:e.index,path:ts(t,e.index)??e.path}))}}}function ts(e,t){if("android"===e.platform&&e.clientOutPath)return eh(e.clientOutPath,t)}async function tc(e,t,r,a={}){if(!r.recordOnlySession)return;let i=e8(r.device);await i.cleanupRecordOnlySession?.(r),a.writeLog&&e.writeSessionLog(r),e.delete(t)}async function td(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await _(t,r):await p(e,t,r),startIosSimulatorRecording:e=>F().startIosSimulatorRecording(e),runAppleRunnerCommand:I,waitForRecordingTail:ti,waitForStableFile:J,isPlayableVideo:X,trimRecordingStart:es,resizeRecording:ed,overlayRecordingTouches:ec},n=a.get(r),s=n?.device??await R(t.flags??{});n||await E(s);let c=n??{name:C(t),sessionScope:M(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return b("INVALID_ARGS","record requires start|stop");if("start"===d)return to({req:t,sessionName:r,sessionStore:a,activeSession:c,device:s,logPath:i,deps:o});let u=await tn({req:t,activeSession:c,device:s,logPath:i,deps:o});return u.ok?(U(a,c,t,t.command,{action:"stop",outPath:u.data?.outPath,showTouches:u.data?.showTouches}),await tc(a,r,c,{writeLog:!0})):await tc(a,r,c),u}export{td as handleRecordCommand};
|
|
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{t as e}from"./rolldown-runtime.js";import{y as t}from"./sdk-android-adb.js";import{t as n}from"./scoped-provider.js";import{n as r}from"./simctl.js";var i=e({createLocalRecordingProvider:()=>s,resolveRecordingProvider:()=>c,withRecordingProvider:()=>l});const a={startIosSimulatorRecording({device:e,outPath:n}){return t(`xcrun`,r(e,[`io`,e.id,`recordVideo`,n]),{allowFailure:!0})}},o=n(a,s);function s(e={}){return{...a,...e}}function c(e){return o.resolve(e)}async function l(e,t){return await o.run(e,t)}export{c as n,i as t};
|