agent-device 0.18.1 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.18.1.apk → agent-device-android-multitouch-helper-0.18.2.apk} +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.18.2.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.18.1.manifest.json → agent-device-android-multitouch-helper-0.18.2.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.18.1.apk → agent-device-android-snapshot-helper-0.18.2.apk} +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.18.2.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.18.1.manifest.json → agent-device-android-snapshot-helper-0.18.2.manifest.json} +6 -6
  7. package/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -1
  8. package/dist/src/1986.js +1 -1
  9. package/dist/src/2948.js +16 -16
  10. package/dist/src/3340.js +8 -8
  11. package/dist/src/4428.js +3 -3
  12. package/dist/src/495.js +5 -5
  13. package/dist/src/6849.js +1 -1
  14. package/dist/src/7871.js +1 -1
  15. package/dist/src/8184.js +1 -1
  16. package/dist/src/8414.js +2 -2
  17. package/dist/src/8875.js +4 -1
  18. package/dist/src/9624.js +1 -1
  19. package/dist/src/9722.js +36 -36
  20. package/dist/src/android.js +1 -1
  21. package/dist/src/apps.js +9 -9
  22. package/dist/src/audio-probe.js +1 -1
  23. package/dist/src/batch.d.ts +1 -1
  24. package/dist/src/cli-help.js +9 -7
  25. package/dist/src/cli.js +23 -23
  26. package/dist/src/contracts.d.ts +1 -1
  27. package/dist/src/devices.js +1 -1
  28. package/dist/src/devices~1.js +1 -1
  29. package/dist/src/index.d.ts +42 -15
  30. package/dist/src/input-actions.js +1 -1
  31. package/dist/src/interaction.js +1 -1
  32. package/dist/src/interactor.js +1 -1
  33. package/dist/src/internal/bin.js +1 -1
  34. package/dist/src/linux.js +1 -1
  35. package/dist/src/record-trace-recording.js +3 -3
  36. package/dist/src/remote-config.d.ts +1 -1
  37. package/dist/src/selector-runtime.js +1 -1
  38. package/dist/src/selectors.d.ts +8 -4
  39. package/dist/src/session.js +11 -11
  40. package/dist/src/simulator.js +2 -2
  41. package/dist/src/snapshot.js +2 -2
  42. package/dist/src/web.js +1 -1
  43. package/package.json +1 -1
  44. package/server.json +2 -2
  45. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.18.1.apk.sha256 +0 -1
  46. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.18.1.apk.sha256 +0 -1
  47. package/dist/src/432.js +0 -4
@@ -172,7 +172,7 @@ export declare function normalizeError(err: unknown, context?: {
172
172
  logPath?: string;
173
173
  }): NormalizedError;
174
174
 
175
- declare const PLATFORM_SELECTORS: readonly ["ios", "macos", "android", "linux", "web", "apple"];
175
+ declare const PLATFORM_SELECTORS: readonly ["apple", "android", "linux", "web", "ios", "macos"];
176
176
 
177
177
  declare type PlatformSelector = (typeof PLATFORM_SELECTORS)[number];
178
178
 
@@ -1 +1 @@
1
- import{promises as e}from"node:fs";import t from"node:os";import i from"node:path";import{AppError as r}from"./485.js";import{sortAppleDevicesForSelection as o}from"./6849.js";import{buildHostMacDevice as n}from"./devices~1.js";import{runXcrun as s,resolveAppleToolProvider as l,buildSimctlArgs as a}from"./9722.js";import{resolveIosSimulatorDeviceSetPath as u}from"./3340.js";let c=/^(iphone|ipad|ipod|appletv|realitydevice)/i,d=/ipad/i,p=/\b(apple vision|vision pro|xros|visionos|realitydevice)\b/i,f=/\b(iphone|ipad|ipod)\b/i,m=/^appletv/i,v=["apple tv","appletv","tvos"],_=/^==\s*(.+?)\s*==$/,h=/^(?<name>.+?)\s+\[(?<id>[^[\]]+)\]\s*$/;function w(e){return(e??"").trim().toLowerCase()}function S(e){return w(e.hardwareProperties?.platform)}function P(e){return e.includes("tvos")}function y(e){let t=w(e);return v.some(e=>t.includes(e))}function C(e,t){return"tv"===e?"tvos":t.some(e=>p.test(e))?"visionos":t.some(e=>d.test(e))?"ipados":"ios"}function b(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function O(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function A(e={}){let t,i,r=u(e.simulatorSetPath),n=e.target;try{t=await s(a(["list","devices","-j"],{simulatorSetPath:r}))}catch{return null}try{i=JSON.parse(t.stdout)}catch{return null}return o(N(i,r)).find(e=>!n||e.target===n)??null}function N(e,t){let i=[];for(let[r,o]of Object.entries(e.devices))if(function(e){let t=w(e);return t.includes("ios")||t.includes("tvos")||t.includes("xros")||t.includes("visionos")}(r))for(let e of o){if(!e.isAvailable)continue;let o=P(w(r))?"tv":"mobile";i.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:o,appleOs:C(o,[e.deviceTypeIdentifier??"",e.name]),booted:"Booted"===e.state,...t?{simulatorSetPath:t}:{}})}return i}function x(e,t){let i=new Set(e.map(e=>e.id)),r=[...e];for(let e of t)i.has(e.id)||(i.add(e.id),r.push(e));return r}async function M(){let r=null;try{r=i.join(t.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let o=await s(["devicectl","list","devices","--json-output",r],{allowFailure:!0,timeoutMs:8e3});if(0!==o.exitCode)return[];let n=await e.readFile(r,"utf8");return function(e){let t=[];for(let i of e.result?.devices??[]){if(!function(e){var t,i;let r=S(e);return!!(r.includes("ios")||r.includes("tvos")||(t=r).includes("xros")||t.includes("visionos"))||(i=O(e),!!c.test(i.trim())||b(e).some(y))}(i))continue;let e=i.hardwareProperties?.udid??i.identifier??"",r=i.name??i.deviceProperties?.name??e;if(!e)continue;let o=function(e){var t;return P(S(e))?"tv":(t=O(e),m.test(t.trim())||b(e).some(y))?"tv":"mobile"}(i);t.push({platform:"ios",id:e,name:r,kind:"device",target:o,appleOs:C(o,[O(i),...b(i)]),booted:!0})}return t}(JSON.parse(n))}catch{return[]}finally{r&&await e.rm(r,{force:!0}).catch(()=>{})}}async function K(){try{let e=await s(["xctrace","list","devices"],{allowFailure:!0});if(0!==e.exitCode)return[];return function(e){let t=[],i=null;for(let r of e.split(/\r?\n/)){let e=r.trim();if(!e)continue;let o=_.exec(e);if(o){i=o[1]?.trim()??null;continue}if("Devices"!==i)continue;let n=h.exec(e),s=n?.groups?.id?.trim()??"",l=n?.groups?.name?.trim()??"";if(!s||!l)continue;let a=function(e){return y(e)?"tv":f.test(e.trim())||p.test(e)?"mobile":null}(l);a&&t.push({platform:"ios",id:s,name:l,kind:"device",target:a,appleOs:C(a,[l]),booted:!0})}return t}(e.stdout)}catch{return[]}}async function T(e={}){if("darwin"!==process.platform)throw new r("UNSUPPORTED_PLATFORM","Apple tools are only available on macOS");if(!await l().whichCommand("xcrun"))throw new r("TOOL_MISSING","xcrun not found in PATH");let t=u(e.simulatorSetPath),i=await s(a(["list","devices","-j"],{simulatorSetPath:t})),c=[];try{let e=JSON.parse(i.stdout);c=N(e,t)}catch(e){throw new r("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(c.push(n()),e.udid&&c.some(t=>"ios"===t.platform&&t.id===e.udid))return c;if(t)return o(c);let[d,p]=await Promise.all([M(),K()]);return c=x(c,d),o(x(c,p))}export{A as findBootableIosSimulator,T as listAppleDevices};
1
+ import{promises as e}from"node:fs";import t from"node:os";import i from"node:path";import{AppError as r}from"./485.js";import{isIosFamily as o,sortAppleDevicesForSelection as n}from"./6849.js";import{buildHostMacDevice as s}from"./devices~1.js";import{runXcrun as l,resolveAppleToolProvider as a,buildSimctlArgs as u}from"./9722.js";import{markSimulatorBooted as c}from"./simulator.js";import{resolveIosSimulatorDeviceSetPath as d}from"./3340.js";let p=/^(iphone|ipad|ipod|appletv|realitydevice)/i,f=/ipad/i,m=/\b(apple vision|vision pro|xros|visionos|realitydevice)\b/i,v=/\b(iphone|ipad|ipod)\b/i,_=/^appletv/i,h=["apple tv","appletv","tvos"],S=/^==\s*(.+?)\s*==$/,w=/^(?<name>.+?)\s+\[(?<id>[^[\]]+)\]\s*$/;function P(e){return(e??"").trim().toLowerCase()}function y(e){return P(e.hardwareProperties?.platform)}function C(e){return e.includes("tvos")}function b(e){let t=P(e);return h.some(e=>t.includes(e))}function O(e,t){return"tv"===e?"tvos":t.some(e=>m.test(e))?"visionos":t.some(e=>f.test(e))?"ipados":"ios"}function A(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function N(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function K(e={}){let t,i,r=d(e.simulatorSetPath),o=e.target;try{t=await l(u(["list","devices","-j"],{simulatorSetPath:r}))}catch{return null}try{i=JSON.parse(t.stdout)}catch{return null}return n(M(i,r)).find(e=>!o||e.target===o)??null}function M(e,t){let i=[];for(let[r,o]of Object.entries(e.devices))if(function(e){let t=P(e);return t.includes("ios")||t.includes("tvos")||t.includes("xros")||t.includes("visionos")}(r))for(let e of o){if(!e.isAvailable)continue;let o=C(P(r))?"tv":"mobile",n={platform:"apple",id:e.udid,name:e.name,kind:"simulator",target:o,appleOs:O(o,[e.deviceTypeIdentifier??"",e.name]),booted:"Booted"===e.state,...t?{simulatorSetPath:t}:{}};n.booted&&c(n),i.push(n)}return i}function x(e,t){let i=new Set(e.map(e=>e.id)),r=[...e];for(let e of t)i.has(e.id)||(i.add(e.id),r.push(e));return r}async function E(){let r=null;try{r=i.join(t.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let o=await l(["devicectl","list","devices","--json-output",r],{allowFailure:!0,timeoutMs:8e3});if(0!==o.exitCode)return[];let n=await e.readFile(r,"utf8");return function(e){let t=[];for(let i of e.result?.devices??[]){if(!function(e){var t,i;let r=y(e);return!!(r.includes("ios")||r.includes("tvos")||(t=r).includes("xros")||t.includes("visionos"))||(i=N(e),!!p.test(i.trim())||A(e).some(b))}(i))continue;let e=i.hardwareProperties?.udid??i.identifier??"",r=i.name??i.deviceProperties?.name??e;if(!e)continue;let o=function(e){var t;return C(y(e))?"tv":(t=N(e),_.test(t.trim())||A(e).some(b))?"tv":"mobile"}(i);t.push({platform:"apple",id:e,name:r,kind:"device",target:o,appleOs:O(o,[N(i),...A(i)]),booted:!0})}return t}(JSON.parse(n))}catch{return[]}finally{r&&await e.rm(r,{force:!0}).catch(()=>{})}}async function R(){try{let e=await l(["xctrace","list","devices"],{allowFailure:!0});if(0!==e.exitCode)return[];return function(e){let t=[],i=null;for(let r of e.split(/\r?\n/)){let e=r.trim();if(!e)continue;let o=S.exec(e);if(o){i=o[1]?.trim()??null;continue}if("Devices"!==i)continue;let n=w.exec(e),s=n?.groups?.id?.trim()??"",l=n?.groups?.name?.trim()??"";if(!s||!l)continue;let a=function(e){return b(e)?"tv":v.test(e.trim())||m.test(e)?"mobile":null}(l);a&&t.push({platform:"apple",id:s,name:l,kind:"device",target:a,appleOs:O(a,[l]),booted:!0})}return t}(e.stdout)}catch{return[]}}async function T(e={}){if("darwin"!==process.platform)throw new r("UNSUPPORTED_PLATFORM","Apple tools are only available on macOS");if(!await a().whichCommand("xcrun"))throw new r("TOOL_MISSING","xcrun not found in PATH");let t=d(e.simulatorSetPath),i=await l(u(["list","devices","-j"],{simulatorSetPath:t})),c=[];try{let e=JSON.parse(i.stdout);c=M(e,t)}catch(e){throw new r("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(c.push(s()),e.udid&&c.some(t=>o(t)&&t.id===e.udid))return c;if(t)return n(c);let[p,f]=await Promise.all([E(),R()]);return c=x(c,p),n(x(c,f))}export{K as findBootableIosSimulator,T as listAppleDevices};
@@ -1 +1 @@
1
- import o from"node:os";function e(){return{platform:"macos",id:"host-macos-local",name:o.hostname(),kind:"device",target:"desktop",appleOs:"macos",booted:!0}}async function t(){return[e()]}export{e as buildHostMacDevice,t as listMacosDevices};
1
+ import o from"node:os";function e(){return{platform:"apple",id:"host-macos-local",name:o.hostname(),kind:"device",target:"desktop",appleOs:"macos",booted:!0}}async function t(){return[e()]}export{e as buildHostMacDevice,t as listMacosDevices};
@@ -124,12 +124,17 @@ declare type AgentDeviceCommandClient = {
124
124
  declare type AgentDeviceDaemonTransport = (req: Omit<DaemonRequest, 'token'>) => Promise<DaemonResponse>;
125
125
 
126
126
  declare type AgentDeviceDevice = {
127
- platform: Platform;
127
+ platform: PublicPlatform;
128
128
  target: DeviceTarget;
129
129
  kind: DeviceKind;
130
130
  id: string;
131
131
  name: string;
132
132
  booted?: boolean;
133
+ /**
134
+ * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
135
+ * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
136
+ */
137
+ appleOs?: AppleOS;
133
138
  identifiers: AgentDeviceIdentifiers;
134
139
  ios?: {
135
140
  udid: string;
@@ -172,10 +177,15 @@ declare type AgentDeviceSession = {
172
177
  };
173
178
 
174
179
  declare type AgentDeviceSessionDevice = {
175
- platform: Platform;
180
+ platform: PublicPlatform;
176
181
  target: DeviceTarget;
177
182
  id: string;
178
183
  name: string;
184
+ /**
185
+ * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
186
+ * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
187
+ */
188
+ appleOs?: AppleOS;
179
189
  identifiers: AgentDeviceIdentifiers;
180
190
  ios?: {
181
191
  udid: string;
@@ -242,7 +252,7 @@ declare type AppDeployOptions = AgentDeviceRequestOverrides & AgentDeviceSelecti
242
252
  declare type AppDeployResult = {
243
253
  app: string;
244
254
  appPath: string;
245
- platform: Platform;
255
+ platform: PublicPlatform;
246
256
  appId?: string;
247
257
  bundleId?: string;
248
258
  package?: string;
@@ -288,6 +298,10 @@ declare type AppInstallOptions = AgentDeviceRequestOverrides & AgentDeviceSelect
288
298
  appPath: string;
289
299
  };
290
300
 
301
+ declare const APPLE_OS_VALUES: readonly ['ios', 'ipados', 'tvos', 'watchos', 'visionos', 'macos'];
302
+
303
+ declare type AppleOS = (typeof APPLE_OS_VALUES)[number];
304
+
291
305
  declare type AppListOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
292
306
  appsFilter?: AppsFilter;
293
307
  };
@@ -444,11 +458,11 @@ declare type BatchStepResult = {
444
458
  /**
445
459
  * Closed result of the `boot` command. Mirrors the daemon handler's only
446
460
  * success return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed
447
- * object literal `{ platform, target, device, id, kind, booted }`. The handler
448
- * spreads nothing, so this shape is intentionally closed.
461
+ * object literal `{ platform, target, device, id, kind, booted }` plus the
462
+ * additive `appleOs` discriminant, emitted only for Apple devices.
449
463
  */
450
464
  declare type BootCommandResult = {
451
- platform: Platform;
465
+ platform: PublicPlatform;
452
466
  target: DeviceTarget;
453
467
  /** Human-readable device name (`device.name`). */
454
468
  device: string;
@@ -457,6 +471,12 @@ declare type BootCommandResult = {
457
471
  kind: DeviceKind;
458
472
  /** Always `true` on the success path. */
459
473
  booted: true;
474
+ /**
475
+ * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
476
+ * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
477
+ * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
478
+ */
479
+ appleOs?: AppleOS;
460
480
  };
461
481
 
462
482
  declare type CaptureDiffOptions = DeviceCommandBaseOptions & Pick<CaptureSnapshotOptions, 'interactiveOnly' | 'depth' | 'scope' | 'raw'> & {
@@ -1183,11 +1203,7 @@ declare type PinchOptions = DeviceCommandBaseOptions & {
1183
1203
  y?: number;
1184
1204
  };
1185
1205
 
1186
- declare type Platform = (typeof PLATFORMS)[number];
1187
-
1188
- declare const PLATFORM_SELECTORS: readonly ["ios", "macos", "android", "linux", "web", "apple"];
1189
-
1190
- declare const PLATFORMS: readonly ['ios', 'macos', 'android', 'linux', 'web'];
1206
+ declare const PLATFORM_SELECTORS: readonly ["apple", "android", "linux", "web", "ios", "macos"];
1191
1207
 
1192
1208
  declare type PlatformSelector = (typeof PLATFORM_SELECTORS)[number];
1193
1209
 
@@ -1232,6 +1248,10 @@ declare type PressCommandResult = ResolvedInteractionTarget & {
1232
1248
 
1233
1249
  declare type PressOptions = DeviceCommandBaseOptions & SelectorSnapshotCommandOptions & InteractionTarget & RepeatedPressOptions;
1234
1250
 
1251
+ declare const PUBLIC_PLATFORMS: readonly ['ios', 'macos', 'android', 'linux', 'web'];
1252
+
1253
+ declare type PublicPlatform = (typeof PUBLIC_PLATFORMS)[number];
1254
+
1235
1255
  declare type PublicSnapshotCaptureAnnotations = Pick<SnapshotCaptureAnnotations, 'androidSnapshot' | 'warnings'> & {
1236
1256
  snapshotQuality?: SnapshotQualityVerdict;
1237
1257
  };
@@ -1534,11 +1554,12 @@ declare type SettingsUpdateOptions = (DeviceCommandBaseOptions & {
1534
1554
  /**
1535
1555
  * Closed result of the `shutdown` command. Mirrors the daemon handler's success
1536
1556
  * return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed object
1537
- * literal `{ platform, target, device, id, kind, shutdown }`. The `shutdown`
1538
- * field is the raw {@link TargetShutdownResult} from `shutdownDeviceTarget`.
1557
+ * literal `{ platform, target, device, id, kind, shutdown }` plus the additive
1558
+ * `appleOs` discriminant (Apple devices only). The `shutdown` field is the raw
1559
+ * {@link TargetShutdownResult} from `shutdownDeviceTarget`.
1539
1560
  */
1540
1561
  declare type ShutdownCommandResult = {
1541
- platform: Platform;
1562
+ platform: PublicPlatform;
1542
1563
  target: DeviceTarget;
1543
1564
  /** Human-readable device name (`device.name`). */
1544
1565
  device: string;
@@ -1546,6 +1567,12 @@ declare type ShutdownCommandResult = {
1546
1567
  id: string;
1547
1568
  kind: DeviceKind;
1548
1569
  shutdown: TargetShutdownResult;
1570
+ /**
1571
+ * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
1572
+ * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
1573
+ * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
1574
+ */
1575
+ appleOs?: AppleOS;
1549
1576
  };
1550
1577
 
1551
1578
  declare type SnapshotCaptureAnalysis = {
@@ -1600,7 +1627,7 @@ declare type SnapshotTimingStats = {
1600
1627
  p95Ms: number;
1601
1628
  maxMs: number;
1602
1629
  slowThresholdMs: number;
1603
- platform?: Platform;
1630
+ platform?: PublicPlatform;
1604
1631
  backends?: Record<string, number>;
1605
1632
  };
1606
1633
 
@@ -1 +1 @@
1
- import{emitDiagnostic as t}from"./432.js";import{runAndroidAdb as e,resolveAndroidTextInjector as n}from"./3340.js";import{getAndroidKeyboardState as a,isAndroidInputMethodOwnedNode as r}from"./9624.js";import{captureAndroidUiHierarchyXml as i,androidUiNodes as o}from"./9722.js";import{AppError as u}from"./485.js";import{buildScrollGesturePlan as l}from"./2948.js";import{sleep as c}from"./5560.js";function s(t){var e;return!!t&&(!!t.password||!!(e=t.text)&&Array.from(e).every(f))}function d(t){if(!t)return null;let e=s(t);return{...t,text:e?null:t.text,...e?{textRedacted:!0}:{}}}function f(t){return"•"===t||"*"===t||"●"===t}async function p(t,e,n,a){let r=null,i=null,o=await m(t);for(let u of[0,150,350]){u>0&&await c(u);let l=await g(t,e,n,a,o);if(r=l,"ime_capture"===l.reason)return l;i=l.ok?l:null}return i??r??{ok:!1,actual:null,reason:"text_mismatch",targetInput:null,actualInput:null}}async function h(t,e,n){var a,r,o;return a=await i(t),r=e,o=n,w(a,r,o).actualInput?.text??null}async function g(t,e,n,a,r){return function(t,e,n,a,r={}){var i,o;let u,l=w(t,e,n,r);return!function(t){let{targetInput:e,actualInput:n}=t;return!!e&&!!n&&n!==e&&n.inputMethodOwned&&!e.inputMethodOwned}(l)?function(t,e){let n=t.actualInput;if(!n||!s(n))return null;let a=n.text??null,r=Array.from(a??"").length,i=Array.from(e).length,o=null!==a&&r>0&&i>0&&r===i;return{ok:o,actual:a,reason:o?void 0:"masked_unverified",masked:!0,targetInput:t.targetInput,actualInput:n}}(l,a)??(i=l,o=a,{ok:function(t,e){if(t===e)return!0;let n=y(t),a=y(e);return!!n&&!!a&&!!(n===a||function(t,e){if(t.length!==e.length||0===t.length||t.slice(1)!==e.slice(1))return!1;let n=t[0],a=e[0];return!!n&&!!a&&a.toLowerCase()===a&&n===a.toUpperCase()}(n,a))}(u=i.actualInput?.text??null,o),actual:u,reason:"text_mismatch",targetInput:i.targetInput,actualInput:i.actualInput}):{ok:!1,actual:l.actualInput?.text??null,reason:"ime_capture",targetInput:l.targetInput,actualInput:l.actualInput}}(await i(t),e,n,a,r)}function w(t,e,n,a={}){var i;let u,l={focusedEdit:null,editAtPoint:null,anyAtPoint:null};for(let i of o(t)){let t=function(t,e){if(!t.rect)return null;let n=t.text??"",a=Math.max(1,t.rect.width*t.rect.height);return{text:n||null,className:t.className,resourceId:t.resourceId,packageName:t.packageName,rect:t.rect,focused:t.focused??!1,password:!0===t.password,inputMethodOwned:r({packageName:t.packageName,resourceId:t.resourceId,activeInputMethodPackage:e.activeInputMethodPackage}),area:a,editText:function(t){let e=t.toLowerCase();return e.includes("edittext")||e.includes("textfield")}(t.className??"")}}(i,a);t&&function(t,e,n,a){var r,i,o;let u=(r=e.rect,i=n,o=a,i>=r.x&&i<=r.x+r.width&&o>=r.y&&o<=r.y+r.height);if(u&&e.editText&&(t.editAtPoint=_(t.editAtPoint,e)),e.focused&&e.editText){t.focusedEdit=_(t.focusedEdit,e);return}u&&e.text&&(t.anyAtPoint=_(t.anyAtPoint,e))}(l,t,e,n)}return{targetInput:u=(i=l).editAtPoint??i.anyAtPoint,actualInput:(i.focusedEdit?.text?i.focusedEdit:null)??u}}function y(t){return(t??"").replace(/\s+/g," ").trim()}async function m(e){try{return{activeInputMethodPackage:(await a(e)).inputMethodPackage}}catch(e){return t({level:"warn",phase:"android_fill_verification_input_method_probe_failed",data:{error:e instanceof Error?e.message:String(e)}}),{}}}function _(t,e){return t&&t.area<e.area?t:e}async function A(t,n,a){await e(t,["shell","input","tap",String(n),String(a)])}async function x(t,n,a,r,i,o=250){await e(t,["shell","input","swipe",String(n),String(a),String(r),String(i),String(o)])}async function I(t){await e(t,["shell","input","keyevent","4"])}async function M(t){await e(t,["shell","input","keyevent","3"])}async function k(t){await e(t,["shell","input","keyevent","ENTER"])}async function S(t,n){let a=function(t){switch(t){case"portrait":return"0";case"landscape-left":return"1";case"portrait-upside-down":return"2";case"landscape-right":return"3";default:throw new u("INVALID_ARGS",`Unsupported Android rotation: ${t}`)}}(n);await e(t,["shell","settings","put","system","accelerometer_rotation","0"]),await e(t,["shell","settings","put","system","user_rotation",a])}async function v(t){await e(t,["shell","input","keyevent","187"])}async function E(t,n,a,r=800){await e(t,["shell","input","swipe",String(n),String(a),String(n),String(a),String(r)])}async function C(t,e,a=0){let r=n(t);if(r){await r({action:"type",text:e,delayMs:a}),F("type","provider-native",e);return}(U(e),await K(t,"type"),a>0&&Array.from(e).length>1)?await L(t,{action:"type",text:e,chunkSize:1,delayMs:a}):await L(t,{action:"type",text:e,chunkSize:O,delayMs:0})}async function P(t,e,n){await A(t,e,n)}async function N(t,e,a,r,i=0){let o=n(t);if(o){await o({action:"fill",target:{x:e,y:a},text:r,delayMs:i}),F("fill","provider-native",r);let n=await p(t,e,a,r);if(n.ok)return;b(r,n)}U(r);let u=Array.from(r).length,l=null;for(let n of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:i>0?1:O,inputDelayMs:i},{clearPadding:24,minClear:16,maxClear:96,chunkSize:i>0?1:4,inputDelayMs:i>0?i:15}]){var c,s;await P(t,e,a),await K(t,"fill");let i=(c=u+n.clearPadding,s=n.minClear,Math.max(s,Math.min(n.maxClear,c)));await H(t,i),await L(t,{action:"fill",text:r,chunkSize:n.chunkSize,delayMs:n.inputDelayMs});let o=await p(t,e,a,r);if(l=o,o.ok)return;"ime_capture"===o.reason&&b(r,o)}b(r,l)}function b(t,e){let n;throw new u("COMMAND_FAILED",e?.reason==="ime_capture"?"Android fill input was captured by the active keyboard instead of the app field":e?.reason==="masked_unverified"?"Android fill verification could not confirm masked text value":"Android fill verification failed",(n=function(t,e){var n;if(!e)return{expected:t,actual:null,failureReason:"text_mismatch",targetInput:null,actualInput:null};let a=!0===(n=e).masked||s(n.targetInput)||s(n.actualInput),r={failureReason:e.reason??"text_mismatch",targetInput:d(e.targetInput),actualInput:d(e.actualInput)};return a?{...r,expectedLength:Array.from(t).length,actual:null,masked:!0,actualLength:Array.from(e.actual??"").length}:{...r,expected:t,actual:e.actual}}(t,e),e?.reason==="ime_capture"&&(n.hint="The focused input belongs to the Android keyboard/IME, not the app field. Disable handwriting/stylus input or switch to a standard IME, then retry fill."),n))}async function D(t,n,a){let r=await R(t),i=l({direction:n,amount:a?.amount,pixels:a?.pixels,referenceWidth:r.width,referenceHeight:r.height}),o=a?.durationMs??300;return await e(t,["shell","input","swipe",String(i.x1),String(i.y1),String(i.x2),String(i.y2),String(o)]),{...i,...a?.durationMs!==void 0?{durationMs:a.durationMs}:{}}}async function K(e,n){let r;try{r=await a(e)}catch(e){t({level:"warn",phase:"android_input_ownership_probe_failed",data:{action:n,error:e instanceof Error?e.message:String(e)}});return}if("ime"===r.inputOwner)throw new u("COMMAND_FAILED","KEYBOARD_OVERLAY_BLOCKING: Android text input is blocked because the focused input belongs to the active keyboard/IME.",{failureReason:"ime_capture",action:n,inputOwner:r.inputOwner,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,nextAction:"Focused input appears to be owned by the keyboard/IME; dismiss or change the IME before retrying text entry."})}async function R(t){let n=(await e(t,["shell","wm","size"])).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!n)throw new u("COMMAND_FAILED","Unable to read screen size");return{width:Number(n[1]),height:Number(n[2])}}let O=8;async function L(t,n){let a=n.text.split("\n");for(let[r,i]of a.entries()){let o=function(t,e){let n=Math.max(1,Math.floor(e)),a=[],r=Array.from(t);for(let t=0;t<r.length;t+=n)a.push(r.slice(t,t+n).join(""));return a.length>0?a:[""]}(i,n.chunkSize);for(let[e,i]of o.entries())await z(t,i),n.delayMs>0&&(e+1<o.length||r+1<a.length)&&await c(n.delayMs);r+1<a.length&&await e(t,["shell","input","keyevent","ENTER"])}F(n.action,"adb-shell",n.text)}async function z(t,n){if(n)try{await e(t,["shell","input","text",n.replace(/ /g,"%s")])}catch(t){if(function(t){if(!(t instanceof u)||"COMMAND_FAILED"!==t.code)return!1;let e=t.details?.stderr,n=("string"==typeof e?e:"").toLowerCase();return!!(n.includes("exception occurred while executing 'text'")||n.includes("nullpointerexception")&&n.includes("inputshellcommand.sendtext"))}(t))throw T(n,t);throw t}}function U(t){if(!function(t){for(let e of t){let t=e.codePointAt(0);if(void 0!==t&&"\n"!==e&&(t<32||t>126))return!1}return!0}(t))throw T(t)}function T(t,e){return new u("COMMAND_FAILED","Android text input requires provider-native text injection for non-ASCII/control characters; the current adb-shell fallback supports ASCII text only.",{backend:"adb-shell",textLength:Array.from(t).length,textPreview:t.slice(0,32)},e instanceof Error?e:void 0)}function F(e,n,a){t({phase:"android_text_injection",data:{action:e,backend:n,textLength:Array.from(a).length}})}async function H(t,n){let a=Math.max(0,n);await e(t,["shell","input","keyevent","KEYCODE_MOVE_END"],{allowFailure:!0});for(let n=0;n<a;n+=24){let r=Math.min(24,a-n);await e(t,["shell","input","keyevent",...Array(r).fill("KEYCODE_DEL")],{allowFailure:!0})}}export{v as appSwitcherAndroid,I as backAndroid,N as fillAndroid,P as focusAndroid,R as getAndroidScreenSize,M as homeAndroid,E as longPressAndroid,A as pressAndroid,k as pressAndroidEnter,h as readAndroidTextAtPoint,S as rotateAndroid,D as scrollAndroid,x as swipeAndroid,C as typeAndroid};
1
+ import{emitDiagnostic as t}from"./8875.js";import{runAndroidAdb as e,resolveAndroidTextInjector as n}from"./3340.js";import{getAndroidKeyboardState as a,isAndroidInputMethodOwnedNode as r}from"./9624.js";import{captureAndroidUiHierarchyXml as i,androidUiNodes as o}from"./9722.js";import{AppError as u}from"./485.js";import{buildScrollGesturePlan as l}from"./2948.js";import{sleep as c}from"./5560.js";function s(t){var e;return!!t&&(!!t.password||!!(e=t.text)&&Array.from(e).every(f))}function d(t){if(!t)return null;let e=s(t);return{...t,text:e?null:t.text,...e?{textRedacted:!0}:{}}}function f(t){return"•"===t||"*"===t||"●"===t}async function p(t,e,n,a){let r=null,i=null,o=await m(t);for(let u of[0,150,350]){u>0&&await c(u);let l=await g(t,e,n,a,o);if(r=l,"ime_capture"===l.reason)return l;i=l.ok?l:null}return i??r??{ok:!1,actual:null,reason:"text_mismatch",targetInput:null,actualInput:null}}async function h(t,e,n){var a,r,o;return a=await i(t),r=e,o=n,w(a,r,o).actualInput?.text??null}async function g(t,e,n,a,r){return function(t,e,n,a,r={}){var i,o;let u,l=w(t,e,n,r);return!function(t){let{targetInput:e,actualInput:n}=t;return!!e&&!!n&&n!==e&&n.inputMethodOwned&&!e.inputMethodOwned}(l)?function(t,e){let n=t.actualInput;if(!n||!s(n))return null;let a=n.text??null,r=Array.from(a??"").length,i=Array.from(e).length,o=null!==a&&r>0&&i>0&&r===i;return{ok:o,actual:a,reason:o?void 0:"masked_unverified",masked:!0,targetInput:t.targetInput,actualInput:n}}(l,a)??(i=l,o=a,{ok:function(t,e){if(t===e)return!0;let n=y(t),a=y(e);return!!n&&!!a&&!!(n===a||function(t,e){if(t.length!==e.length||0===t.length||t.slice(1)!==e.slice(1))return!1;let n=t[0],a=e[0];return!!n&&!!a&&a.toLowerCase()===a&&n===a.toUpperCase()}(n,a))}(u=i.actualInput?.text??null,o),actual:u,reason:"text_mismatch",targetInput:i.targetInput,actualInput:i.actualInput}):{ok:!1,actual:l.actualInput?.text??null,reason:"ime_capture",targetInput:l.targetInput,actualInput:l.actualInput}}(await i(t),e,n,a,r)}function w(t,e,n,a={}){var i;let u,l={focusedEdit:null,editAtPoint:null,anyAtPoint:null};for(let i of o(t)){let t=function(t,e){if(!t.rect)return null;let n=t.text??"",a=Math.max(1,t.rect.width*t.rect.height);return{text:n||null,className:t.className,resourceId:t.resourceId,packageName:t.packageName,rect:t.rect,focused:t.focused??!1,password:!0===t.password,inputMethodOwned:r({packageName:t.packageName,resourceId:t.resourceId,activeInputMethodPackage:e.activeInputMethodPackage}),area:a,editText:function(t){let e=t.toLowerCase();return e.includes("edittext")||e.includes("textfield")}(t.className??"")}}(i,a);t&&function(t,e,n,a){var r,i,o;let u=(r=e.rect,i=n,o=a,i>=r.x&&i<=r.x+r.width&&o>=r.y&&o<=r.y+r.height);if(u&&e.editText&&(t.editAtPoint=_(t.editAtPoint,e)),e.focused&&e.editText){t.focusedEdit=_(t.focusedEdit,e);return}u&&e.text&&(t.anyAtPoint=_(t.anyAtPoint,e))}(l,t,e,n)}return{targetInput:u=(i=l).editAtPoint??i.anyAtPoint,actualInput:(i.focusedEdit?.text?i.focusedEdit:null)??u}}function y(t){return(t??"").replace(/\s+/g," ").trim()}async function m(e){try{return{activeInputMethodPackage:(await a(e)).inputMethodPackage}}catch(e){return t({level:"warn",phase:"android_fill_verification_input_method_probe_failed",data:{error:e instanceof Error?e.message:String(e)}}),{}}}function _(t,e){return t&&t.area<e.area?t:e}async function A(t,n,a){await e(t,["shell","input","tap",String(n),String(a)])}async function x(t,n,a,r,i,o=250){await e(t,["shell","input","swipe",String(n),String(a),String(r),String(i),String(o)])}async function I(t){await e(t,["shell","input","keyevent","4"])}async function M(t){await e(t,["shell","input","keyevent","3"])}async function k(t){await e(t,["shell","input","keyevent","ENTER"])}async function S(t,n){let a=function(t){switch(t){case"portrait":return"0";case"landscape-left":return"1";case"portrait-upside-down":return"2";case"landscape-right":return"3";default:throw new u("INVALID_ARGS",`Unsupported Android rotation: ${t}`)}}(n);await e(t,["shell","settings","put","system","accelerometer_rotation","0"]),await e(t,["shell","settings","put","system","user_rotation",a])}async function v(t){await e(t,["shell","input","keyevent","187"])}async function E(t,n,a,r=800){await e(t,["shell","input","swipe",String(n),String(a),String(n),String(a),String(r)])}async function C(t,e,a=0){let r=n(t);if(r){await r({action:"type",text:e,delayMs:a}),F("type","provider-native",e);return}(U(e),await K(t,"type"),a>0&&Array.from(e).length>1)?await L(t,{action:"type",text:e,chunkSize:1,delayMs:a}):await L(t,{action:"type",text:e,chunkSize:O,delayMs:0})}async function P(t,e,n){await A(t,e,n)}async function N(t,e,a,r,i=0){let o=n(t);if(o){await o({action:"fill",target:{x:e,y:a},text:r,delayMs:i}),F("fill","provider-native",r);let n=await p(t,e,a,r);if(n.ok)return;b(r,n)}U(r);let u=Array.from(r).length,l=null;for(let n of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:i>0?1:O,inputDelayMs:i},{clearPadding:24,minClear:16,maxClear:96,chunkSize:i>0?1:4,inputDelayMs:i>0?i:15}]){var c,s;await P(t,e,a),await K(t,"fill");let i=(c=u+n.clearPadding,s=n.minClear,Math.max(s,Math.min(n.maxClear,c)));await H(t,i),await L(t,{action:"fill",text:r,chunkSize:n.chunkSize,delayMs:n.inputDelayMs});let o=await p(t,e,a,r);if(l=o,o.ok)return;"ime_capture"===o.reason&&b(r,o)}b(r,l)}function b(t,e){let n;throw new u("COMMAND_FAILED",e?.reason==="ime_capture"?"Android fill input was captured by the active keyboard instead of the app field":e?.reason==="masked_unverified"?"Android fill verification could not confirm masked text value":"Android fill verification failed",(n=function(t,e){var n;if(!e)return{expected:t,actual:null,failureReason:"text_mismatch",targetInput:null,actualInput:null};let a=!0===(n=e).masked||s(n.targetInput)||s(n.actualInput),r={failureReason:e.reason??"text_mismatch",targetInput:d(e.targetInput),actualInput:d(e.actualInput)};return a?{...r,expectedLength:Array.from(t).length,actual:null,masked:!0,actualLength:Array.from(e.actual??"").length}:{...r,expected:t,actual:e.actual}}(t,e),e?.reason==="ime_capture"&&(n.hint="The focused input belongs to the Android keyboard/IME, not the app field. Disable handwriting/stylus input or switch to a standard IME, then retry fill."),n))}async function D(t,n,a){let r=await R(t),i=l({direction:n,amount:a?.amount,pixels:a?.pixels,referenceWidth:r.width,referenceHeight:r.height}),o=a?.durationMs??300;return await e(t,["shell","input","swipe",String(i.x1),String(i.y1),String(i.x2),String(i.y2),String(o)]),{...i,...a?.durationMs!==void 0?{durationMs:a.durationMs}:{}}}async function K(e,n){let r;try{r=await a(e)}catch(e){t({level:"warn",phase:"android_input_ownership_probe_failed",data:{action:n,error:e instanceof Error?e.message:String(e)}});return}if("ime"===r.inputOwner)throw new u("COMMAND_FAILED","KEYBOARD_OVERLAY_BLOCKING: Android text input is blocked because the focused input belongs to the active keyboard/IME.",{failureReason:"ime_capture",action:n,inputOwner:r.inputOwner,inputType:r.inputType,type:r.type,inputMethodPackage:r.inputMethodPackage,focusedPackage:r.focusedPackage,focusedResourceId:r.focusedResourceId,nextAction:"Focused input appears to be owned by the keyboard/IME; dismiss or change the IME before retrying text entry."})}async function R(t){let n=(await e(t,["shell","wm","size"])).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!n)throw new u("COMMAND_FAILED","Unable to read screen size");return{width:Number(n[1]),height:Number(n[2])}}let O=8;async function L(t,n){let a=n.text.split("\n");for(let[r,i]of a.entries()){let o=function(t,e){let n=Math.max(1,Math.floor(e)),a=[],r=Array.from(t);for(let t=0;t<r.length;t+=n)a.push(r.slice(t,t+n).join(""));return a.length>0?a:[""]}(i,n.chunkSize);for(let[e,i]of o.entries())await z(t,i),n.delayMs>0&&(e+1<o.length||r+1<a.length)&&await c(n.delayMs);r+1<a.length&&await e(t,["shell","input","keyevent","ENTER"])}F(n.action,"adb-shell",n.text)}async function z(t,n){if(n)try{await e(t,["shell","input","text",n.replace(/ /g,"%s")])}catch(t){if(function(t){if(!(t instanceof u)||"COMMAND_FAILED"!==t.code)return!1;let e=t.details?.stderr,n=("string"==typeof e?e:"").toLowerCase();return!!(n.includes("exception occurred while executing 'text'")||n.includes("nullpointerexception")&&n.includes("inputshellcommand.sendtext"))}(t))throw T(n,t);throw t}}function U(t){if(!function(t){for(let e of t){let t=e.codePointAt(0);if(void 0!==t&&"\n"!==e&&(t<32||t>126))return!1}return!0}(t))throw T(t)}function T(t,e){return new u("COMMAND_FAILED","Android text input requires provider-native text injection for non-ASCII/control characters; the current adb-shell fallback supports ASCII text only.",{backend:"adb-shell",textLength:Array.from(t).length,textPreview:t.slice(0,32)},e instanceof Error?e:void 0)}function F(e,n,a){t({phase:"android_text_injection",data:{action:e,backend:n,textLength:Array.from(a).length}})}async function H(t,n){let a=Math.max(0,n);await e(t,["shell","input","keyevent","KEYCODE_MOVE_END"],{allowFailure:!0});for(let n=0;n<a;n+=24){let r=Math.min(24,a-n);await e(t,["shell","input","keyevent",...Array(r).fill("KEYCODE_DEL")],{allowFailure:!0})}}export{v as appSwitcherAndroid,I as backAndroid,N as fillAndroid,P as focusAndroid,R as getAndroidScreenSize,M as homeAndroid,E as longPressAndroid,A as pressAndroid,k as pressAndroidEnter,h as readAndroidTextAtPoint,S as rotateAndroid,D as scrollAndroid,x as swipeAndroid,C as typeAndroid};
@@ -1 +1 @@
1
- import{__webpack_require__ as e}from"./rslib-runtime.js";import{createDaemonRuntimeSessionStore as t,setSessionSnapshot as r,dispatchCommand as a,requireCommandSupported as n,ensureAndroidBlockingSystemDialogReady as s,errorResponse as o,NO_ACTIVE_SESSION_MESSAGE as i,noActiveSessionError as l,recoverAndroidBlockingSystemDialog as c,getActiveAndroidSnapshotFreshness as f}from"./9722.js";import{buttonTag as u,resolveClickButton as d,readFillTargetFromPositionals as p,getClickButtonValidationError as g,successText as m}from"./2948.js";import{createAgentDevice as k}from"./7871.js";import{asAppError as y,normalizeError as w,AppError as h}from"./485.js";import{assertAndroidPressStayedInApp as b,isAndroidEscapeError as S,createDaemonRuntimePolicy as _,dispatchGetViaRuntime as x,dispatchIsViaRuntime as v,isDirectIosSelectorFallbackError as F,refSnapshotFlagGuardResponse as N,readSimpleIosSelectorTarget as M}from"./selector-runtime.js";import{resolveWebProvider as P}from"./provider.js";import{interaction_snapshot_captureSnapshotForSession as R,readSnapshotNodesReferenceFrame as C,resolveDirectTouchReferenceFrameSafely as q,buildTouchVisualizationResult as A,finalizeTouchInteraction as I}from"./8184.js";import{emitDiagnostic as H}from"./432.js";import{PUBLIC_COMMANDS as K}from"./1986.js";var E={};function D(e,t){return"macos"!==e.device.platform||"desktop"!==e.surface&&"menubar"!==e.surface||"menubar"===e.surface&&("click"===t||"press"===t)?null:o("UNSUPPORTED_OPERATION",`${t} is not supported on macOS ${e.surface} sessions yet. Open an app session to act, or use the ${e.surface} surface to inspect.`)}function O(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}function U(e,t){let r=O(e);if(r)return{ok:!0,target:{kind:"point",x:r.x,y:r.y}};let a=e[0]??"";if(a.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:a,fallbackLabel:e.slice(1).join(" ").trim()}};let n=e.join(" ").trim();return n?{ok:!0,target:{kind:"selector",selector:n}}:{ok:!1,response:o("INVALID_ARGS",`${t} requires @ref, selector expression, or x y coordinates`)}}function T(e){return"ref"===e.kind?{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),refLabel:e.refLabel,selectorChain:e.selectorChain}:"selector"===e.kind?{selector:e.target?.kind==="selector"?e.target.selector:void 0,selectorChain:e.selectorChain,refLabel:e.refLabel}:{}}function L(e){return e?.startsWith("@")?e.slice(1):e}function j(e){let n=e.sessionStore.get(e.sessionName);if(!n)throw new h("SESSION_NOT_FOUND",i);return k({backend:function(e){let{req:t,session:r}=e,n=function(e){if("web"!==e.device.platform)return;let t=P();return t.clickRef||t.fillRef?t:void 0}(r);return{platform:r.device.platform,captureSnapshot:async(a,n)=>({snapshot:await e.captureSnapshotForSession(r,t.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:n?.interactiveOnly===!0,includeRects:n?.includeRects===!0})}),tap:async(n,s)=>B(await a(r.device,"press",[String(s.x),String(s.y)],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),tapTarget:n?.clickRef?async(e,t)=>(await n.clickRef?.(t.ref),{ref:L(t.ref)}):void 0,fill:async(n,s,o)=>B(await a(r.device,"fill",[String(s.x),String(s.y),o],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),fillTarget:n?.fillRef?async(e,t,r,a)=>(await n.fillRef?.(t.ref,r,a),{ref:L(t.ref),text:r,delayMs:a?.delayMs??0}):void 0,longPress:async(n,s,o)=>B(await a(r.device,"longpress",[String(s.x),String(s.y),...o?.durationMs===void 0?[]:[String(o.durationMs)]],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath))),typeText:async(n,s)=>B(await a(r.device,"type",[s],t.flags?.out,e.contextFromFlags(t.flags,r.appBundleId,r.trace?.outPath)))}}({...e,session:n}),..._("interaction commands",{plural:!0}),sessions:t({sessionName:e.sessionName,getSession:()=>n,recordOptions:{includeSnapshot:!0},setRecord:t=>{t.snapshot&&(r(n,t.snapshot),e.sessionStore.set(e.sessionName,n))}})})}function B(e){return e&&"object"==typeof e?e:void 0}async function G(e){switch(e.req.command){case"press":return await W(e,"press");case"click":return await W(e,"click");case"longpress":return await W(e,"longpress");case"fill":return await z(e);default:return null}}async function W(e,t){let r,{req:a,sessionName:s,sessionStore:i}=e,c=i.get(s);if(!c)return l();let f="click"===t?"click":t,p="longpress"===t?"longpress":"press",m=D(c,f);if(m)return m;let k=n(p,c.device);if(k)return k;let y=d(a.flags),w=u(y);if("longpress"!==t&&"primary"!==y){let e=g({commandLabel:f,platform:c.device.platform,button:y,count:a.flags?.count,intervalMs:a.flags?.intervalMs,holdMs:a.flags?.holdMs,jitterPx:a.flags?.jitterPx,doubleTap:a.flags?.doubleTap});if(e)return o(e.code,e.message,e.details)}let h="longpress"===t?function(e){var t,r,a;let n,s=O(e);if(s){return{ok:!0,target:{kind:"point",x:s.x,y:s.y},...void 0===(t=e[2])?{}:{durationMs:Number(t)}}}let o=(n=(r=e).at(-1),r.length>1&&void 0!==(a=n)&&""!==a.trim()&&Number.isFinite(Number(a))?{targetPositionals:r.slice(0,-1),duration:{durationMs:Number(n)}}:{targetPositionals:r,duration:{}}),i=U(o.targetPositionals,"longpress");return i.ok?{ok:!0,target:i.target,...o.duration}:i}(a.positionals??[]):U(a.positionals??[],f);if(!h.ok)return h.response;if("ref"===h.target.kind){let n=e.refSnapshotFlagGuardResponse("longpress"===t?"longpress":"press",a.flags);if(n)return n;r=await ee(e,c)}let S=function(e){var t;let{session:r,commandLabel:a,target:n,flags:s}=e;if("click"!==a||"selector"!==n.kind||(t=s,t?.count!==void 0||t?.intervalMs!==void 0||t?.holdMs!==void 0||t?.jitterPx!==void 0||t?.doubleTap!==void 0||t?.clickButton!==void 0&&"primary"!==t.clickButton))return null;let o=M({session:r,selectorExpression:n.selector});return o?{...o,...s?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:c,commandLabel:f,target:h.target,flags:a.flags});if(S){let t=await X(e,c,S);if(t)return t}let _="longpress"===t?h.durationMs:void 0;return await Q(e,{androidFreshnessBaseline:r,run:async e=>await V({runtime:e,command:t,target:h.target,sessionName:s,requestId:a.meta?.requestId,clickButton:y,flags:a.flags,durationMs:_}),afterRun:async e=>{if(!c.lease?.leaseProvider){var t;await b(c,(t=h.target,"point"===t.kind?"coordinate tap":"ref"===e.kind&&e.target?.kind==="ref"?e.target.ref:"selector"===e.kind&&e.target?.kind==="selector"?e.target.selector:"target"))}},buildPayloads:async r=>{var a;let n="durationMs"in(a=r)?a.durationMs:void 0,s=await $({params:e,session:c,result:r,extra:"longpress"===t?{...void 0!==n?{durationMs:n}:{},gesture:"longpress"}:w});return{result:s,responseData:s}}})}async function V(e){let{runtime:t,command:r,target:a,sessionName:n,requestId:s,flags:o}=e;if("longpress"===r)return await t.interactions.longPress(a,{session:n,requestId:s,durationMs:e.durationMs});let i={session:n,requestId:s,button:e.clickButton,count:o?.count,intervalMs:o?.intervalMs,holdMs:o?.holdMs,jitterPx:o?.jitterPx,doubleTap:o?.doubleTap};return"click"===r?await t.interactions.click(a,i):await t.interactions.press(a,i)}async function $(e){let{params:t,session:r,result:a,extra:n}=e,s="point"===a.kind?await q({session:r,flags:t.req.flags,sessionStore:t.sessionStore,contextFromFlags:t.contextFromFlags,captureSnapshotForSession:t.captureSnapshotForSession}):C(r.snapshot?.nodes??[]);return A({data:a.backendResult,fallbackX:a.point?.x,fallbackY:a.point?.y,referenceFrame:s,extra:{...T(a),...n}})}async function X(e,t,r){return await Y({params:e,session:t,selector:r,command:"press",positionals:[],extra:{selector:r.raw},fallbackPhase:"ios_direct_selector_tap_fallback"})}async function Y(e){let{params:t,session:r,selector:n,command:s,positionals:o,extra:i,fallbackPhase:l}=e,c=Date.now();try{var f,u;let e,l,d=await a(r.device,s,o,t.req.flags?.out,{...t.contextFromFlags(t.req.flags,r.appBundleId,r.trace?.outPath),directElementSelector:n,surface:r.surface})??{},p=Date.now(),g=(f=d,e="number"==typeof f.x?f.x:void 0,l="number"==typeof f.y?f.y:void 0,void 0!==e&&void 0!==l?{x:e,y:l}:{x:0,y:0}),m=A({data:d,fallbackX:g.x,fallbackY:g.y,referenceFrame:(u=d,"number"==typeof u.referenceWidth&&"number"==typeof u.referenceHeight?{referenceWidth:u.referenceWidth,referenceHeight:u.referenceHeight}:void 0),extra:{...i,...function(e,t){if(!e.allowNonHittableCoordinateFallback)return{};let r="tapped via non-hittable coordinate fallback"===t.message;return{maestroNonHittableCoordinateFallbackAllowed:!0,maestroNonHittableCoordinateFallbackUsed:r,...r?{maestroFallbackReason:"non-hittable-coordinate"}:{}}}(n,d)}});return I({session:r,sessionStore:t.sessionStore,command:t.req.command,positionals:t.req.positionals??[],retryPositionals:et(g),flags:t.req.flags,result:m,responseData:m,actionStartedAt:c,actionFinishedAt:p})}catch(e){if(!F(e))return{ok:!1,error:w(e)};return H({level:"debug",phase:l,data:{selector:n.raw,error:e instanceof Error?e.message:String(e)}}),null}}async function z(e){let{req:t,sessionName:r,sessionStore:a}=e,s=a.get(r);if(s){let e=D(s,"fill");if(e)return e;let t=n("fill",s.device);if(t)return t}if(!s)return l();let i=function(e){let t=e[0]??"";if(t.startsWith("@")){var r;let a=p(e).text;return a?{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:(r=e).length>=3&&r[1]?.trim()||""},text:a}:{ok:!1,response:o("INVALID_ARGS","fill requires text after ref")}}let a=O(e);if(a){let t=e.slice(2).join(" ");return t?{ok:!0,target:{kind:"point",x:a.x,y:a.y},text:t}:{ok:!1,response:o("INVALID_ARGS","fill requires text after coordinates")}}let n=p(e);return"selector"!==n.kind?{ok:!1,response:o("INVALID_ARGS","fill requires x y text, @ref text, or selector text")}:n.text.trim()?{ok:!0,target:{kind:"selector",selector:n.target.selector},text:n.text}:{ok:!1,response:o("INVALID_ARGS","fill requires text after selector")}}(t.positionals??[]);if(!i.ok)return i.response;if("ref"===i.target.kind){let r=e.refSnapshotFlagGuardResponse("fill",t.flags);if(r)return r;await ee(e,s)}let c=function(e){let{session:t,target:r,flags:a}=e;if("selector"!==r.kind)return null;let n=M({session:t,selectorExpression:r.selector});return n?{...n,...a?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:s,target:i.target,flags:t.flags});if(c){let t=await J(e,s,c,i.text);if(t)return t}return await Q(e,{run:async e=>await e.interactions.fill(i.target,i.text,{session:r,requestId:t.meta?.requestId,delayMs:t.flags?.delayMs}),buildPayloads:e=>{let t="point"===e.kind?void 0:C(s.snapshot?.nodes??[]),r=A({data:e.backendResult,fallbackX:e.point?.x,fallbackY:e.point?.y,referenceFrame:t,extra:{...T(e),text:i.text}});e.warning&&(r.warning=e.warning);let a="ref"===e.kind?{...e.backendResult??{ref:L(e.target?.kind==="ref"?e.target.ref:void 0),...e.point?{x:e.point.x,y:e.point.y}:{}}}:r;return e.warning&&(a.warning=e.warning),{result:r,responseData:a}}})}async function J(e,t,r,a){return await Y({params:e,session:t,selector:r,command:"fill",positionals:[a],extra:{selector:r.raw,text:a},fallbackPhase:"ios_direct_selector_fill_fallback"})}async function Q(e,t){let r=e.sessionStore.get(e.sessionName);if(!r)return l();let a=j(e),n=Date.now();try{let{readiness:s,runtimeResult:o}=await Z(r,e.req.command,async()=>{let e=await t.run(a);return await t.afterRun?.(e),e}),i=Date.now(),{result:l,responseData:c}=await t.buildPayloads(o);return"recovered"===s.status&&(l.warning=s.warning,c.warning=s.warning),I({session:r,sessionStore:e.sessionStore,command:e.req.command,positionals:e.req.positionals??[],retryPositionals:function(e,t){if(("ref"!==t.kind||t.node)&&("click"===e||"press"===e)&&t.point)return et(t.point)}(e.req.command,o),flags:e.req.flags,result:l,responseData:c,actionStartedAt:n,actionFinishedAt:i,androidFreshnessBaseline:t.androidFreshnessBaseline})}catch(t){let e=y(t);if(S(e))throw e;return{ok:!1,error:w(t)}}}async function Z(e,t,r){if(e.lease?.leaseProvider)return{readiness:{status:"clear"},runtimeResult:await r()};let a=await s({session:e,command:t,phase:"before-command"}),n=await r();return await s({session:e,command:t,phase:"after-command"}),{readiness:a,runtimeResult:n}}async function ee(e,t){if(!f(t))return;let r=t.snapshot?.comparisonSafe===!0?t.snapshot:void 0;try{await e.captureSnapshotForSession(t,e.req.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:!0,androidFreshnessMode:"ref-refresh"})}catch(t){H({level:"warn",phase:"android_ref_snapshot_refresh_failed",data:{command:e.req.command,error:t instanceof Error?t.message:String(t)}})}return r}function et(e){return[String(e.x),String(e.y)]}async function er(e){let t=await G({...e,captureSnapshotForSession:R,refSnapshotFlagGuardResponse:N});if(t)return t;switch(e.req.command){case K.type:return await ea({...e,captureSnapshotForSession:R});case"get":return await x(e);case"is":return await v(e);default:return null}}async function ea(e){let{sessionName:t,sessionStore:r}=e,a=r.get(t);if(!a)return l();let s=n(K.type,a.device);if(s)return s;let o=await en(a);return o||await es(e,a)}async function en(e){return"android"===e.device.platform&&e.recording&&"failed"===(await c({session:e})).status?o("COMMAND_FAILED","Android system dialog blocked the recording session"):null}async function es(e,t){let{req:r,sessionName:a,sessionStore:n}=e,o=(r.positionals??[]).join(" "),i=j(e),l=Date.now();try{let e=await s({session:t,command:r.command,phase:"before-command"}),c=await i.interactions.typeText(o,{session:a,requestId:r.meta?.requestId,delayMs:r.flags?.delayMs});await s({session:t,command:r.command,phase:"after-command"});let f=Date.now(),u={...c.backendResult??{},text:c.text,delayMs:c.delayMs,...m(c.message??`Typed ${Array.from(c.text).length} chars`)};return"recovered"===e.status&&(u.warning=e.warning),I({session:t,sessionStore:n,command:r.command,positionals:r.positionals??[],flags:r.flags,result:u,responseData:u,actionStartedAt:l,actionFinishedAt:f})}catch(e){return{ok:!1,error:w(e)}}}e.r(E),e.d(E,{handleInteractionCommands:()=>er});export{E as interaction_namespaceObject};
1
+ import{__webpack_require__ as e}from"./rslib-runtime.js";import{isMacOs as t,publicPlatformString as r}from"./6849.js";import{createDaemonRuntimeSessionStore as a,setSessionSnapshot as n,dispatchCommand as s,requireCommandSupported as o,ensureAndroidBlockingSystemDialogReady as i,errorResponse as l,NO_ACTIVE_SESSION_MESSAGE as c,noActiveSessionError as f,recoverAndroidBlockingSystemDialog as u,getActiveAndroidSnapshotFreshness as d}from"./9722.js";import{buttonTag as p,resolveClickButton as g,readFillTargetFromPositionals as m,getClickButtonValidationError as k,successText as y}from"./2948.js";import{createAgentDevice as w}from"./7871.js";import{asAppError as _,normalizeError as S,AppError as h}from"./485.js";import{assertAndroidPressStayedInApp as b,isAndroidEscapeError as x,createDaemonRuntimePolicy as v,dispatchGetViaRuntime as F,dispatchIsViaRuntime as N,isDirectIosSelectorFallbackError as M,refSnapshotFlagGuardResponse as P,readSimpleIosSelectorTarget as R}from"./selector-runtime.js";import{resolveWebProvider as C}from"./provider.js";import{interaction_snapshot_captureSnapshotForSession as A,readSnapshotNodesReferenceFrame as q,resolveDirectTouchReferenceFrameSafely as I,buildTouchVisualizationResult as K,finalizeTouchInteraction as H}from"./8184.js";import{emitDiagnostic as E}from"./8875.js";import{PUBLIC_COMMANDS as D}from"./1986.js";var U={};function O(e,r){return t(e.device)&&("desktop"===e.surface||"menubar"===e.surface)&&("menubar"!==e.surface||"click"!==r&&"press"!==r)?l("UNSUPPORTED_OPERATION",`${r} is not supported on macOS ${e.surface} sessions yet. Open an app session to act, or use the ${e.surface} surface to inspect.`):null}function T(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}function L(e,t){let r=T(e);if(r)return{ok:!0,target:{kind:"point",x:r.x,y:r.y}};let a=e[0]??"";if(a.startsWith("@"))return{ok:!0,target:{kind:"ref",ref:a,fallbackLabel:e.slice(1).join(" ").trim()}};let n=e.join(" ").trim();return n?{ok:!0,target:{kind:"selector",selector:n}}:{ok:!1,response:l("INVALID_ARGS",`${t} requires @ref, selector expression, or x y coordinates`)}}function j(e){return"ref"===e.kind?{ref:B(e.target?.kind==="ref"?e.target.ref:void 0),refLabel:e.refLabel,selectorChain:e.selectorChain}:"selector"===e.kind?{selector:e.target?.kind==="selector"?e.target.selector:void 0,selectorChain:e.selectorChain,refLabel:e.refLabel}:{}}function B(e){return e?.startsWith("@")?e.slice(1):e}function G(e){let t=e.sessionStore.get(e.sessionName);if(!t)throw new h("SESSION_NOT_FOUND",c);return w({backend:function(e){let{req:t,session:a}=e,n=function(e){if("web"!==e.device.platform)return;let t=C();return t.clickRef||t.fillRef?t:void 0}(a);return{platform:r(a.device),captureSnapshot:async(r,n)=>({snapshot:await e.captureSnapshotForSession(a,t.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:n?.interactiveOnly===!0,includeRects:n?.includeRects===!0})}),tap:async(r,n)=>W(await s(a.device,"press",[String(n.x),String(n.y)],t.flags?.out,e.contextFromFlags(t.flags,a.appBundleId,a.trace?.outPath))),tapTarget:n?.clickRef?async(e,t)=>(await n.clickRef?.(t.ref),{ref:B(t.ref)}):void 0,fill:async(r,n,o)=>W(await s(a.device,"fill",[String(n.x),String(n.y),o],t.flags?.out,e.contextFromFlags(t.flags,a.appBundleId,a.trace?.outPath))),fillTarget:n?.fillRef?async(e,t,r,a)=>(await n.fillRef?.(t.ref,r,a),{ref:B(t.ref),text:r,delayMs:a?.delayMs??0}):void 0,longPress:async(r,n,o)=>W(await s(a.device,"longpress",[String(n.x),String(n.y),...o?.durationMs===void 0?[]:[String(o.durationMs)]],t.flags?.out,e.contextFromFlags(t.flags,a.appBundleId,a.trace?.outPath))),typeText:async(r,n)=>W(await s(a.device,"type",[n],t.flags?.out,e.contextFromFlags(t.flags,a.appBundleId,a.trace?.outPath)))}}({...e,session:t}),...v("interaction commands",{plural:!0}),sessions:a({sessionName:e.sessionName,getSession:()=>t,recordOptions:{includeSnapshot:!0},setRecord:r=>{r.snapshot&&(n(t,r.snapshot),e.sessionStore.set(e.sessionName,t))}})})}function W(e){return e&&"object"==typeof e?e:void 0}async function V(e){switch(e.req.command){case"press":return await $(e,"press");case"click":return await $(e,"click");case"longpress":return await $(e,"longpress");case"fill":return await Q(e);default:return null}}async function $(e,t){let a,{req:n,sessionName:s,sessionStore:i}=e,c=i.get(s);if(!c)return f();let u="click"===t?"click":t,d="longpress"===t?"longpress":"press",m=O(c,u);if(m)return m;let y=o(d,c.device);if(y)return y;let w=g(n.flags),_=p(w);if("longpress"!==t&&"primary"!==w){let e=k({commandLabel:u,platform:r(c.device),button:w,count:n.flags?.count,intervalMs:n.flags?.intervalMs,holdMs:n.flags?.holdMs,jitterPx:n.flags?.jitterPx,doubleTap:n.flags?.doubleTap});if(e)return l(e.code,e.message,e.details)}let S="longpress"===t?function(e){var t,r,a;let n,s=T(e);if(s){return{ok:!0,target:{kind:"point",x:s.x,y:s.y},...void 0===(t=e[2])?{}:{durationMs:Number(t)}}}let o=(n=(r=e).at(-1),r.length>1&&void 0!==(a=n)&&""!==a.trim()&&Number.isFinite(Number(a))?{targetPositionals:r.slice(0,-1),duration:{durationMs:Number(n)}}:{targetPositionals:r,duration:{}}),i=L(o.targetPositionals,"longpress");return i.ok?{ok:!0,target:i.target,...o.duration}:i}(n.positionals??[]):L(n.positionals??[],u);if(!S.ok)return S.response;if("ref"===S.target.kind){let r=e.refSnapshotFlagGuardResponse("longpress"===t?"longpress":"press",n.flags);if(r)return r;a=await er(e,c)}let h=function(e){var t;let{session:r,commandLabel:a,target:n,flags:s}=e;if("click"!==a||"selector"!==n.kind||(t=s,t?.count!==void 0||t?.intervalMs!==void 0||t?.holdMs!==void 0||t?.jitterPx!==void 0||t?.doubleTap!==void 0||t?.clickButton!==void 0&&"primary"!==t.clickButton))return null;let o=R({session:r,selectorExpression:n.selector});return o?{...o,...s?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:c,commandLabel:u,target:S.target,flags:n.flags});if(h){let t=await z(e,c,h);if(t)return t}let x="longpress"===t?S.durationMs:void 0;return await ee(e,{androidFreshnessBaseline:a,run:async e=>await X({runtime:e,command:t,target:S.target,sessionName:s,requestId:n.meta?.requestId,clickButton:w,flags:n.flags,durationMs:x}),afterRun:async e=>{if(!c.lease?.leaseProvider){var t;await b(c,(t=S.target,"point"===t.kind?"coordinate tap":"ref"===e.kind&&e.target?.kind==="ref"?e.target.ref:"selector"===e.kind&&e.target?.kind==="selector"?e.target.selector:"target"))}},buildPayloads:async r=>{var a;let n="durationMs"in(a=r)?a.durationMs:void 0,s=await Y({params:e,session:c,result:r,extra:"longpress"===t?{...void 0!==n?{durationMs:n}:{},gesture:"longpress"}:_});return{result:s,responseData:s}}})}async function X(e){let{runtime:t,command:r,target:a,sessionName:n,requestId:s,flags:o}=e;if("longpress"===r)return await t.interactions.longPress(a,{session:n,requestId:s,durationMs:e.durationMs});let i={session:n,requestId:s,button:e.clickButton,count:o?.count,intervalMs:o?.intervalMs,holdMs:o?.holdMs,jitterPx:o?.jitterPx,doubleTap:o?.doubleTap};return"click"===r?await t.interactions.click(a,i):await t.interactions.press(a,i)}async function Y(e){let{params:t,session:r,result:a,extra:n}=e,s="point"===a.kind?await I({session:r,flags:t.req.flags,sessionStore:t.sessionStore,contextFromFlags:t.contextFromFlags,captureSnapshotForSession:t.captureSnapshotForSession}):q(r.snapshot?.nodes??[]);return K({data:a.backendResult,fallbackX:a.point?.x,fallbackY:a.point?.y,referenceFrame:s,extra:{...j(a),...n}})}async function z(e,t,r){return await J({params:e,session:t,selector:r,command:"press",positionals:[],extra:{selector:r.raw},fallbackPhase:"ios_direct_selector_tap_fallback"})}async function J(e){let{params:t,session:r,selector:a,command:n,positionals:o,extra:i,fallbackPhase:l}=e,c=Date.now();try{var f,u;let e,l,d=await s(r.device,n,o,t.req.flags?.out,{...t.contextFromFlags(t.req.flags,r.appBundleId,r.trace?.outPath),directElementSelector:a,surface:r.surface})??{},p=Date.now(),g=(f=d,e="number"==typeof f.x?f.x:void 0,l="number"==typeof f.y?f.y:void 0,void 0!==e&&void 0!==l?{x:e,y:l}:{x:0,y:0}),m=K({data:d,fallbackX:g.x,fallbackY:g.y,referenceFrame:(u=d,"number"==typeof u.referenceWidth&&"number"==typeof u.referenceHeight?{referenceWidth:u.referenceWidth,referenceHeight:u.referenceHeight}:void 0),extra:{...i,...function(e,t){if(!e.allowNonHittableCoordinateFallback)return{};let r="tapped via non-hittable coordinate fallback"===t.message;return{maestroNonHittableCoordinateFallbackAllowed:!0,maestroNonHittableCoordinateFallbackUsed:r,...r?{maestroFallbackReason:"non-hittable-coordinate"}:{}}}(a,d)}});return H({session:r,sessionStore:t.sessionStore,command:t.req.command,positionals:t.req.positionals??[],retryPositionals:ea(g),flags:t.req.flags,result:m,responseData:m,actionStartedAt:c,actionFinishedAt:p})}catch(e){if(!M(e))return{ok:!1,error:S(e)};return E({level:"debug",phase:l,data:{selector:a.raw,error:e instanceof Error?e.message:String(e)}}),null}}async function Q(e){let{req:t,sessionName:r,sessionStore:a}=e,n=a.get(r);if(n){let e=O(n,"fill");if(e)return e;let t=o("fill",n.device);if(t)return t}if(!n)return f();let s=function(e){let t=e[0]??"";if(t.startsWith("@")){var r;let a=m(e).text;return a?{ok:!0,target:{kind:"ref",ref:t,fallbackLabel:(r=e).length>=3&&r[1]?.trim()||""},text:a}:{ok:!1,response:l("INVALID_ARGS","fill requires text after ref")}}let a=T(e);if(a){let t=e.slice(2).join(" ");return t?{ok:!0,target:{kind:"point",x:a.x,y:a.y},text:t}:{ok:!1,response:l("INVALID_ARGS","fill requires text after coordinates")}}let n=m(e);return"selector"!==n.kind?{ok:!1,response:l("INVALID_ARGS","fill requires x y text, @ref text, or selector text")}:n.text.trim()?{ok:!0,target:{kind:"selector",selector:n.target.selector},text:n.text}:{ok:!1,response:l("INVALID_ARGS","fill requires text after selector")}}(t.positionals??[]);if(!s.ok)return s.response;if("ref"===s.target.kind){let r=e.refSnapshotFlagGuardResponse("fill",t.flags);if(r)return r;await er(e,n)}let i=function(e){let{session:t,target:r,flags:a}=e;if("selector"!==r.kind)return null;let n=R({session:t,selectorExpression:r.selector});return n?{...n,...a?.maestro?.allowNonHittableCoordinateFallback?{allowNonHittableCoordinateFallback:!0}:{}}:null}({session:n,target:s.target,flags:t.flags});if(i){let t=await Z(e,n,i,s.text);if(t)return t}return await ee(e,{run:async e=>await e.interactions.fill(s.target,s.text,{session:r,requestId:t.meta?.requestId,delayMs:t.flags?.delayMs}),buildPayloads:e=>{let t="point"===e.kind?void 0:q(n.snapshot?.nodes??[]),r=K({data:e.backendResult,fallbackX:e.point?.x,fallbackY:e.point?.y,referenceFrame:t,extra:{...j(e),text:s.text}});e.warning&&(r.warning=e.warning);let a="ref"===e.kind?{...e.backendResult??{ref:B(e.target?.kind==="ref"?e.target.ref:void 0),...e.point?{x:e.point.x,y:e.point.y}:{}}}:r;return e.warning&&(a.warning=e.warning),{result:r,responseData:a}}})}async function Z(e,t,r,a){return await J({params:e,session:t,selector:r,command:"fill",positionals:[a],extra:{selector:r.raw,text:a},fallbackPhase:"ios_direct_selector_fill_fallback"})}async function ee(e,t){let r=e.sessionStore.get(e.sessionName);if(!r)return f();let a=G(e),n=Date.now();try{let{readiness:s,runtimeResult:o}=await et(r,e.req.command,async()=>{let e=await t.run(a);return await t.afterRun?.(e),e}),i=Date.now(),{result:l,responseData:c}=await t.buildPayloads(o);return"recovered"===s.status&&(l.warning=s.warning,c.warning=s.warning),H({session:r,sessionStore:e.sessionStore,command:e.req.command,positionals:e.req.positionals??[],retryPositionals:function(e,t){if(("ref"!==t.kind||t.node)&&("click"===e||"press"===e)&&t.point)return ea(t.point)}(e.req.command,o),flags:e.req.flags,result:l,responseData:c,actionStartedAt:n,actionFinishedAt:i,androidFreshnessBaseline:t.androidFreshnessBaseline})}catch(t){let e=_(t);if(x(e))throw e;return{ok:!1,error:S(t)}}}async function et(e,t,r){if(e.lease?.leaseProvider)return{readiness:{status:"clear"},runtimeResult:await r()};let a=await i({session:e,command:t,phase:"before-command"}),n=await r();return await i({session:e,command:t,phase:"after-command"}),{readiness:a,runtimeResult:n}}async function er(e,t){if(!d(t))return;let r=t.snapshot?.comparisonSafe===!0?t.snapshot:void 0;try{await e.captureSnapshotForSession(t,e.req.flags,e.sessionStore,e.contextFromFlags,{interactiveOnly:!0,androidFreshnessMode:"ref-refresh"})}catch(t){E({level:"warn",phase:"android_ref_snapshot_refresh_failed",data:{command:e.req.command,error:t instanceof Error?t.message:String(t)}})}return r}function ea(e){return[String(e.x),String(e.y)]}async function en(e){let t=await V({...e,captureSnapshotForSession:A,refSnapshotFlagGuardResponse:P});if(t)return t;switch(e.req.command){case D.type:return await es({...e,captureSnapshotForSession:A});case"get":return await F(e);case"is":return await N(e);default:return null}}async function es(e){let{sessionName:t,sessionStore:r}=e,a=r.get(t);if(!a)return f();let n=o(D.type,a.device);if(n)return n;let s=await eo(a);return s||await ei(e,a)}async function eo(e){return"android"===e.device.platform&&e.recording&&"failed"===(await u({session:e})).status?l("COMMAND_FAILED","Android system dialog blocked the recording session"):null}async function ei(e,t){let{req:r,sessionName:a,sessionStore:n}=e,s=(r.positionals??[]).join(" "),o=G(e),l=Date.now();try{let e=await i({session:t,command:r.command,phase:"before-command"}),c=await o.interactions.typeText(s,{session:a,requestId:r.meta?.requestId,delayMs:r.flags?.delayMs});await i({session:t,command:r.command,phase:"after-command"});let f=Date.now(),u={...c.backendResult??{},text:c.text,delayMs:c.delayMs,...y(c.message??`Typed ${Array.from(c.text).length} chars`)};return"recovered"===e.status&&(u.warning=e.warning),H({session:t,sessionStore:n,command:r.command,positionals:r.positionals??[],flags:r.flags,result:u,responseData:u,actionStartedAt:l,actionFinishedAt:f})}catch(e){return{ok:!1,error:S(e)}}}e.r(U),e.d(U,{handleInteractionCommands:()=>en});export{U as interaction_namespaceObject};
@@ -1 +1 @@
1
- import{readSnapshotQualityVerdict as a,normalizeScrollDurationMs as e,buildScrollGesturePlan as t,assertScrollGestureInput as n}from"./2948.js";import{isTvOsDevice as o}from"./6849.js";import{runMacOsScreenshotAction as d,runAppleRunnerCommand as i}from"./9722.js";import{parseRunnerSequenceResult as r,buildRunnerSequenceCommand as s}from"./runner-sequence.js";import{writeIosClipboardText as u,openIosApp as l,openIosDevice as p,screenshotIos as c,closeIosApp as m,setIosSetting as y,readIosClipboardText as v}from"./apps.js";import{withDiagnosticTimer as f}from"./432.js";import{AppError as h}from"./485.js";function I(a,e,t){return{command:"remotePress",remoteButton:a,...void 0!==t?{durationMs:t}:{},...void 0!==e?{appBundleId:e}:{}}}function w(a,e,n,o={includeDuration:!0}){let d=M(a.referenceWidth),i=M(a.referenceHeight);if(void 0===d||void 0===i)return _(a,{amount:n?.amount});let r=t({direction:e,amount:n?.amount,pixels:n?.pixels,referenceWidth:d,referenceHeight:i});return _(a,{amount:n?.amount,pixels:r.pixels,durationMs:o?.includeDuration?n?.durationMs:void 0,preferProvidedPixels:!0})}function B(a,e={includeDuration:!0}){return{...a?.amount!==void 0?{amount:a.amount}:{},...a?.pixels!==void 0?{pixels:a.pixels}:{},...e?.includeDuration&&a?.durationMs!==void 0?{durationMs:a.durationMs}:{}}}function M(a){return"number"==typeof a&&Number.isFinite(a)?a:void 0}function _(a,e){var t,n,o,d;let i,r,s,u,{x1:l,y1:p,x2:c,y2:m}=(i=M((t=a).x),r=M(t.y),s=M(t.x2),u=M(t.y2),{...void 0!==i?{x1:i}:{},...void 0!==r?{y1:r}:{},...void 0!==s?{x2:s}:{},...void 0!==u?{y2:u}:{}}),y=M(a.referenceWidth),v=M(a.referenceHeight),f=(n=e,o=void 0!==l&&void 0!==c?Math.round(Math.abs(c-l)):void 0,d=void 0!==p&&void 0!==m?Math.round(Math.abs(m-p)):void 0,n?.preferProvidedPixels&&void 0!==n.pixels?n.pixels:void 0!==o&&o>0?o:void 0!==d&&d>0?d:void 0);return{...void 0!==l?{x1:l}:{},...void 0!==p?{y1:p}:{},...void 0!==c?{x2:c}:{},...void 0!==m?{y2:m}:{},...void 0!==y?{referenceWidth:y}:{},...void 0!==v?{referenceHeight:v}:{},...e?.amount!==void 0?{amount:e.amount}:{},...void 0!==f?{pixels:f}:{},...e?.durationMs!==void 0?{durationMs:e.durationMs}:{}}}async function g(a,e,t,n,o,d){return w(await a(e,{command:"desktopScroll",direction:o,...B(d,{includeDuration:!0}),appBundleId:t.appBundleId},n),o,d,{includeDuration:!0})}function C(a,e,t,n){return{command:"tap",x:t,y:n,...S(a)?{synthesized:!0}:{},appBundleId:e.appBundleId}}function S(a){return"ios"===a.platform&&!o(a)}function x(a,e,t,n,d,i,r,s){var u,l;let p="ios"!==a.platform||o(a)?r??s.legacyDefaultDurationMs:(u=r,l=s.defaultDurationMs,void 0===u?l:Math.min(1e4,Math.max(16,Math.round(u))));return{command:"drag",x:t,y:n,x2:d,y2:i,...void 0!==p?{durationMs:p}:{},...!0===s.synthesized?{synthesized:!0}:{},appBundleId:e.appBundleId}}async function b(a,t,d,i,r,s){return(e(s?.durationMs,{invalidMessage:"scroll durationMs must be a non-negative integer at most 10000"}),o(t))?_(await a(t,I(r,d.appBundleId,s?.durationMs),i),{amount:s?.amount,durationMs:s?.durationMs}):(n(s??{}),"macos"===t.platform)?await g(a,t,d,i,r,s):w(await a(t,{command:"scroll",direction:r,...B(s),appBundleId:d.appBundleId},i),r,s)}function D(e,t){let n;if("watchos"===e.appleOs)throw new h("UNSUPPORTED_PLATFORM","watchOS is not supported: XCUITest cannot drive watchOS UI, so this device has no runner backend.");let{overrides:w,runnerOpts:B}={runnerOpts:n={verbose:t.verbose,logPath:t.logPath,traceLogPath:t.traceLogPath,requestId:t.requestId,iosXctestrunFile:t.iosXctestrunFile,iosXctestDerivedDataPath:t.iosXctestDerivedDataPath,iosXctestEnvDir:t.iosXctestEnvDir,runnerLeaseContext:t.runnerLeaseContext},overrides:{tap:async(a,o)=>await i(e,C(e,t,a,o),n),tapElementSelector:async a=>await i(e,{command:"tap",selectorKey:a.key,selectorValue:a.value,allowNonHittableCoordinateFallback:a.allowNonHittableCoordinateFallback,appBundleId:t.appBundleId},n),doubleTap:async(a,o)=>{let d=await i(e,s([{kind:"doubleTap",x:a,y:o}],t.appBundleId),n);return r(d),d},swipe:async(a,o,d,r,s)=>await i(e,x(e,t,a,o,d,r,s,{defaultDurationMs:250,synthesized:S(e)}),n),pan:async(a,o,d,r,s)=>await i(e,x(e,t,a,o,d,r,s,{defaultDurationMs:500,legacyDefaultDurationMs:500,synthesized:S(e)}),n),fling:async(a,o,d,r,s)=>await i(e,x(e,t,a,o,d,r,s,{defaultDurationMs:16,legacyDefaultDurationMs:16,synthesized:S(e)}),n),longPress:async(a,o,d)=>await i(e,{command:"longPress",x:a,y:o,durationMs:d,appBundleId:t.appBundleId},n),focus:async(a,o)=>await i(e,C(e,t,a,o),n),type:async(a,o)=>{await i(e,{command:"type",text:a,delayMs:o,textEntryMode:"\n"===a?void 0:"append",appBundleId:t.appBundleId},n)},fillElementSelector:async(a,o,d)=>await i(e,{command:"type",selectorKey:a.key,selectorValue:a.value,allowNonHittableCoordinateFallback:a.allowNonHittableCoordinateFallback,text:o,delayMs:d,textEntryMode:"replace",appBundleId:t.appBundleId},n),fill:async(a,o,d,r)=>await i(e,{command:"type",x:a,y:o,text:d,delayMs:r,textEntryMode:"replace",appBundleId:t.appBundleId},n),scroll:async(a,o)=>await b(i,e,t,n,a,o),pinch:async(a,o,d)=>{await i(e,{command:"pinch",scale:a,x:o,y:d,appBundleId:t.appBundleId},n)},rotateGesture:async(a,o,d,r)=>{await i(e,{command:"rotateGesture",degrees:a,x:o,y:d,velocity:r,appBundleId:t.appBundleId},n)},transformGesture:async a=>await i(e,{command:"transformGesture",x:a.x,y:a.y,dx:a.dx,dy:a.dy,scale:a.scale,degrees:a.degrees,durationMs:a.durationMs,appBundleId:t.appBundleId},n)}};return{open:(a,t)=>l(e,a,{appBundleId:t?.appBundleId,launchConsole:t?.launchConsole,launchArgs:t?.launchArgs,url:t?.url}),openDevice:()=>p(e),close:a=>m(e,a),screenshot:async(a,t)=>{"macos"===e.platform&&t?.surface&&"app"!==t.surface?await d(a,{surface:t.surface,fullscreen:t.fullscreen}):await c(e,a,{appBundleId:t?.appBundleId,fullscreen:t?.fullscreen,runnerOptions:B,normalizeStatusBar:t?.normalizeStatusBar,skipIosSimulatorBootCheck:t?.skipIosSimulatorBootCheck})},snapshot:async t=>{var n;let o={nodes:Array.isArray((n=await f("snapshot_capture",async()=>await i(e,{command:"snapshot",appBundleId:t?.appBundleId,interactiveOnly:t?.interactiveOnly,depth:t?.depth,scope:t?.scope,raw:t?.raw},B),{backend:"xctest"})).nodes)?n.nodes:void 0,truncated:"boolean"==typeof n.truncated?n.truncated:void 0,quality:a(n.snapshotQuality),message:"string"==typeof n.message&&n.message.trim().length>0?n.message:void 0},d=o.nodes??[];if(0===d.length&&"simulator"===e.kind)throw new h("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:d,truncated:o.truncated??!1,backend:"xctest",...o.quality?{quality:o.quality}:{},...!o.quality&&o.message?{warnings:[o.message]}:{}}},back:async a=>{o(e)?await i(e,I("menu",t.appBundleId),B):await i(e,{command:"system"===a?"backSystem":"backInApp",appBundleId:t.appBundleId},B)},home:async()=>{o(e)?await i(e,I("home",t.appBundleId),B):await i(e,{command:"home",appBundleId:t.appBundleId},B)},rotate:async a=>{await i(e,{command:"rotate",orientation:a,appBundleId:t.appBundleId},B)},appSwitcher:async()=>{await i(e,{command:"appSwitcher",appBundleId:t.appBundleId},B)},readClipboard:()=>v(e),writeClipboard:a=>u(e,a),setSetting:(a,t,n,o)=>y(e,a,t,n,o),...w}}export{D as createAppleInteractor};
1
+ import{readSnapshotQualityVerdict as e,normalizeScrollDurationMs as a,buildScrollGesturePlan as t,assertScrollGestureInput as n}from"./2948.js";import{isIosFamily as o,isTvOsDevice as d,isMacOs as i}from"./6849.js";import{runMacOsScreenshotAction as r,runAppleRunnerCommand as s}from"./9722.js";import{parseRunnerSequenceResult as u,buildRunnerSequenceCommand as l}from"./runner-sequence.js";import{writeIosClipboardText as p,openIosApp as c,openIosDevice as m,screenshotIos as y,closeIosApp as v,setIosSetting as h,readIosClipboardText as f}from"./apps.js";import{withDiagnosticTimer as I}from"./8875.js";import{AppError as w}from"./485.js";function B(e,a,t){return{command:"remotePress",remoteButton:e,...void 0!==t?{durationMs:t}:{},...void 0!==a?{appBundleId:a}:{}}}function M(e,a,n,o={includeDuration:!0}){let d=g(e.referenceWidth),i=g(e.referenceHeight);if(void 0===d||void 0===i)return C(e,{amount:n?.amount});let r=t({direction:a,amount:n?.amount,pixels:n?.pixels,referenceWidth:d,referenceHeight:i});return C(e,{amount:n?.amount,pixels:r.pixels,durationMs:o?.includeDuration?n?.durationMs:void 0,preferProvidedPixels:!0})}function _(e,a={includeDuration:!0}){return{...e?.amount!==void 0?{amount:e.amount}:{},...e?.pixels!==void 0?{pixels:e.pixels}:{},...a?.includeDuration&&e?.durationMs!==void 0?{durationMs:e.durationMs}:{}}}function g(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function C(e,a){var t,n,o,d;let i,r,s,u,{x1:l,y1:p,x2:c,y2:m}=(i=g((t=e).x),r=g(t.y),s=g(t.x2),u=g(t.y2),{...void 0!==i?{x1:i}:{},...void 0!==r?{y1:r}:{},...void 0!==s?{x2:s}:{},...void 0!==u?{y2:u}:{}}),y=g(e.referenceWidth),v=g(e.referenceHeight),h=(n=a,o=void 0!==l&&void 0!==c?Math.round(Math.abs(c-l)):void 0,d=void 0!==p&&void 0!==m?Math.round(Math.abs(m-p)):void 0,n?.preferProvidedPixels&&void 0!==n.pixels?n.pixels:void 0!==o&&o>0?o:void 0!==d&&d>0?d:void 0);return{...void 0!==l?{x1:l}:{},...void 0!==p?{y1:p}:{},...void 0!==c?{x2:c}:{},...void 0!==m?{y2:m}:{},...void 0!==y?{referenceWidth:y}:{},...void 0!==v?{referenceHeight:v}:{},...a?.amount!==void 0?{amount:a.amount}:{},...void 0!==h?{pixels:h}:{},...a?.durationMs!==void 0?{durationMs:a.durationMs}:{}}}async function S(e,a,t,n,o,d){return M(await e(a,{command:"desktopScroll",direction:o,..._(d,{includeDuration:!0}),appBundleId:t.appBundleId},n),o,d,{includeDuration:!0})}function x(e,a,t,n){return{command:"tap",x:t,y:n,...b(e)?{synthesized:!0}:{},appBundleId:a.appBundleId}}function b(e){return o(e)&&!d(e)}function D(e,a,t,n,i,r,s,u){var l,p;let c=o(e)&&!d(e)?(l=s,p=u.defaultDurationMs,void 0===l?p:Math.min(1e4,Math.max(16,Math.round(l)))):s??u.legacyDefaultDurationMs;return{command:"drag",x:t,y:n,x2:i,y2:r,...void 0!==c?{durationMs:c}:{},...!0===u.synthesized?{synthesized:!0}:{},appBundleId:a.appBundleId}}async function P(e,t,o,r,s,u){return(a(u?.durationMs,{invalidMessage:"scroll durationMs must be a non-negative integer at most 10000"}),d(t))?C(await e(t,B(s,o.appBundleId,u?.durationMs),r),{amount:u?.amount,durationMs:u?.durationMs}):(n(u??{}),i(t))?await S(e,t,o,r,s,u):M(await e(t,{command:"scroll",direction:s,..._(u),appBundleId:o.appBundleId},r),s,u)}function k(a,t){let n;if("watchos"===a.appleOs)throw new w("UNSUPPORTED_PLATFORM","watchOS is not supported: XCUITest cannot drive watchOS UI, so this device has no runner backend.");let{overrides:o,runnerOpts:M}={runnerOpts:n={verbose:t.verbose,logPath:t.logPath,traceLogPath:t.traceLogPath,requestId:t.requestId,iosXctestrunFile:t.iosXctestrunFile,iosXctestDerivedDataPath:t.iosXctestDerivedDataPath,iosXctestEnvDir:t.iosXctestEnvDir,runnerLeaseContext:t.runnerLeaseContext},overrides:{tap:async(e,o)=>await s(a,x(a,t,e,o),n),tapElementSelector:async e=>await s(a,{command:"tap",selectorKey:e.key,selectorValue:e.value,allowNonHittableCoordinateFallback:e.allowNonHittableCoordinateFallback,appBundleId:t.appBundleId},n),doubleTap:async(e,o)=>{let d=await s(a,l([{kind:"doubleTap",x:e,y:o}],t.appBundleId),n);return u(d),d},swipe:async(e,o,d,i,r)=>await s(a,D(a,t,e,o,d,i,r,{defaultDurationMs:250,synthesized:b(a)}),n),pan:async(e,o,d,i,r)=>await s(a,D(a,t,e,o,d,i,r,{defaultDurationMs:500,legacyDefaultDurationMs:500,synthesized:b(a)}),n),fling:async(e,o,d,i,r)=>await s(a,D(a,t,e,o,d,i,r,{defaultDurationMs:16,legacyDefaultDurationMs:16,synthesized:b(a)}),n),longPress:async(e,o,d)=>await s(a,{command:"longPress",x:e,y:o,durationMs:d,appBundleId:t.appBundleId},n),focus:async(e,o)=>await s(a,x(a,t,e,o),n),type:async(e,o)=>{await s(a,{command:"type",text:e,delayMs:o,textEntryMode:"\n"===e?void 0:"append",appBundleId:t.appBundleId},n)},fillElementSelector:async(e,o,d)=>await s(a,{command:"type",selectorKey:e.key,selectorValue:e.value,allowNonHittableCoordinateFallback:e.allowNonHittableCoordinateFallback,text:o,delayMs:d,textEntryMode:"replace",appBundleId:t.appBundleId},n),fill:async(e,o,d,i)=>await s(a,{command:"type",x:e,y:o,text:d,delayMs:i,textEntryMode:"replace",appBundleId:t.appBundleId},n),scroll:async(e,o)=>await P(s,a,t,n,e,o),pinch:async(e,o,d)=>{await s(a,{command:"pinch",scale:e,x:o,y:d,appBundleId:t.appBundleId},n)},rotateGesture:async(e,o,d,i)=>{await s(a,{command:"rotateGesture",degrees:e,x:o,y:d,velocity:i,appBundleId:t.appBundleId},n)},transformGesture:async e=>await s(a,{command:"transformGesture",x:e.x,y:e.y,dx:e.dx,dy:e.dy,scale:e.scale,degrees:e.degrees,durationMs:e.durationMs,appBundleId:t.appBundleId},n)}};return{open:(e,t)=>c(a,e,{appBundleId:t?.appBundleId,launchConsole:t?.launchConsole,launchArgs:t?.launchArgs,terminateRunningApp:t?.terminateRunningApp,url:t?.url}),openDevice:()=>m(a),close:e=>v(a,e),screenshot:async(e,t)=>{i(a)&&t?.surface&&"app"!==t.surface?await r(e,{surface:t.surface,fullscreen:t.fullscreen}):await y(a,e,{appBundleId:t?.appBundleId,fullscreen:t?.fullscreen,runnerOptions:M,normalizeStatusBar:t?.normalizeStatusBar,skipIosSimulatorBootCheck:t?.skipIosSimulatorBootCheck})},snapshot:async t=>{var n;let o={nodes:Array.isArray((n=await I("snapshot_capture",async()=>await s(a,{command:"snapshot",appBundleId:t?.appBundleId,interactiveOnly:t?.interactiveOnly,depth:t?.depth,scope:t?.scope,raw:t?.raw},M),{backend:"xctest"})).nodes)?n.nodes:void 0,truncated:"boolean"==typeof n.truncated?n.truncated:void 0,quality:e(n.snapshotQuality),message:"string"==typeof n.message&&n.message.trim().length>0?n.message:void 0},d=o.nodes??[];if(0===d.length&&"simulator"===a.kind)throw new w("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:d,truncated:o.truncated??!1,backend:"xctest",...o.quality?{quality:o.quality}:{},...!o.quality&&o.message?{warnings:[o.message]}:{}}},back:async e=>{d(a)?await s(a,B("menu",t.appBundleId),M):await s(a,{command:"system"===e?"backSystem":"backInApp",appBundleId:t.appBundleId},M)},home:async()=>{d(a)?await s(a,B("home",t.appBundleId),M):await s(a,{command:"home",appBundleId:t.appBundleId},M)},rotate:async e=>{await s(a,{command:"rotate",orientation:e,appBundleId:t.appBundleId},M)},appSwitcher:async()=>{await s(a,{command:"appSwitcher",appBundleId:t.appBundleId},M)},readClipboard:()=>f(a),writeClipboard:e=>p(a,e),setSetting:(e,t,n,o)=>h(a,e,t,n,o),...o}}export{k as createAppleInteractor};
@@ -1,5 +1,5 @@
1
1
  var e,t,r,s;let n,o=process.argv.slice(2);function c(e){return"--help"===e||"-h"===e}function i(e){import("../cli.js").then(({runCli:t})=>t(e)).catch(p)}function p(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}
2
- `),process.exit(1)}1===(t=e=o).length&&("--version"===(r=t[0])||"-V"===r)&&(process.stdout.write(`0.18.1
2
+ `),process.exit(1)}1===(t=e=o).length&&("--version"===(r=t[0])||"-V"===r)&&(process.stdout.write(`0.18.2
3
3
  `),1)||0===e.length&&(import("../cli-help.js").then(({buildUsageText:e})=>{process.stdout.write(`${e()}
4
4
  `),process.exit(1)}).catch(p),1)||void 0!==(n=function(e){var t,r,s,n;switch(e.length){case 1:return"help"===(t=e[0])||c(t)?null:void 0;case 2:return r=e[0],s=e[1],"help"===r?s:(n=r,c(s)?n:void 0);default:return}}(s=e))&&(import("../cli-help.js").then(({buildCommandUsageText:e,buildUsageText:t})=>{var r;if(null===n)return void process.stdout.write(`${t()}
5
5
  `);let o=e("long-press"===(r=n)?"longpress":"metrics"===r?"perf":r);o?process.stdout.write(o):i(s)}).catch(p),1)||("mcp"!==o[0]||o.includes("--help")||o.includes("-h")?i(o):import("../server.js").then(({runAgentDeviceMcpServer:e})=>e()).catch(p));export{};
package/dist/src/linux.js CHANGED
@@ -1 +1 @@
1
- import{longPressLinux as t,pressLinux as e,typeLinux as n,scrollLinux as o,sendKey as r,fillLinux as a,focusLinux as i,swipeLinux as s,doubleClickLinux as p}from"./input-actions~1.js";import{snapshotLinux as u,resolveLinuxToolProvider as c}from"./9722.js";import{AppError as w}from"./485.js";import{withDiagnosticTimer as _}from"./432.js";async function P(t){await c().desktop.openTarget(t)}async function d(t){await c().desktop.closeApp(t)}async function O(){await r("alt+Left",["56:1","105:1","105:0","56:0"])}async function f(){await r("super+d",["125:1","32:1","32:0","125:0"])}async function l(){return await c().clipboard.readText()}async function S(t){await c().clipboard.writeText(t)}async function E(t,e){await c().screenshot.capture(t,e)}function N(){return{open:t=>P(t),openDevice:()=>Promise.resolve(),close:t=>d(t),tap:(t,n)=>e(t,n),doubleTap:(t,e)=>p(t,e),swipe:(t,e,n,o,r)=>s(t,e,n,o,r),pan:(t,e,n,o,r)=>s(t,e,n,o,r),fling:()=>{throw new w("UNSUPPORTED_OPERATION","gesture fling not supported on Linux")},longPress:(e,n,o)=>t(e,n,o),focus:(t,e)=>i(t,e),type:(t,e)=>n(t,e),fill:(t,e,n,o)=>a(t,e,n,o),scroll:(t,e)=>o(t,e),pinch:()=>{throw new w("UNSUPPORTED_OPERATION","gesture pinch not supported on Linux")},screenshot:(t,e)=>E(t,e),snapshot:async t=>{let e=await _("snapshot_capture",async()=>await u(t?.surface),{backend:"linux-atspi"});return{nodes:e.nodes??[],truncated:e.truncated??!1,backend:"linux-atspi"}},back:()=>O(),home:()=>f(),rotate:()=>{throw new w("UNSUPPORTED_OPERATION","rotate not supported on Linux")},rotateGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture rotate not supported on Linux")},transformGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture transform not supported on Linux")},appSwitcher:()=>{throw new w("UNSUPPORTED_OPERATION","appSwitcher not yet supported on Linux")},readClipboard:()=>l(),writeClipboard:t=>S(t),setSetting:()=>{throw new w("UNSUPPORTED_OPERATION","setSetting not supported on Linux")}}}export{N as createLinuxInteractor};
1
+ import{longPressLinux as t,pressLinux as e,typeLinux as n,scrollLinux as o,sendKey as r,fillLinux as a,focusLinux as i,swipeLinux as s,doubleClickLinux as p}from"./input-actions~1.js";import{snapshotLinux as u,resolveLinuxToolProvider as c}from"./9722.js";import{AppError as w}from"./485.js";import{withDiagnosticTimer as _}from"./8875.js";async function P(t){await c().desktop.openTarget(t)}async function d(t){await c().desktop.closeApp(t)}async function O(){await r("alt+Left",["56:1","105:1","105:0","56:0"])}async function f(){await r("super+d",["125:1","32:1","32:0","125:0"])}async function l(){return await c().clipboard.readText()}async function S(t){await c().clipboard.writeText(t)}async function E(t,e){await c().screenshot.capture(t,e)}function N(){return{open:t=>P(t),openDevice:()=>Promise.resolve(),close:t=>d(t),tap:(t,n)=>e(t,n),doubleTap:(t,e)=>p(t,e),swipe:(t,e,n,o,r)=>s(t,e,n,o,r),pan:(t,e,n,o,r)=>s(t,e,n,o,r),fling:()=>{throw new w("UNSUPPORTED_OPERATION","gesture fling not supported on Linux")},longPress:(e,n,o)=>t(e,n,o),focus:(t,e)=>i(t,e),type:(t,e)=>n(t,e),fill:(t,e,n,o)=>a(t,e,n,o),scroll:(t,e)=>o(t,e),pinch:()=>{throw new w("UNSUPPORTED_OPERATION","gesture pinch not supported on Linux")},screenshot:(t,e)=>E(t,e),snapshot:async t=>{let e=await _("snapshot_capture",async()=>await u(t?.surface),{backend:"linux-atspi"});return{nodes:e.nodes??[],truncated:e.truncated??!1,backend:"linux-atspi"}},back:()=>O(),home:()=>f(),rotate:()=>{throw new w("UNSUPPORTED_OPERATION","rotate not supported on Linux")},rotateGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture rotate not supported on Linux")},transformGesture:()=>{throw new w("UNSUPPORTED_OPERATION","gesture transform not supported on Linux")},appSwitcher:()=>{throw new w("UNSUPPORTED_OPERATION","appSwitcher not yet supported on Linux")},readClipboard:()=>l(),writeClipboard:t=>S(t),setSetting:()=>{throw new w("UNSUPPORTED_OPERATION","setSetting not supported on Linux")}}}export{N as createLinuxInteractor};
@@ -1,4 +1,4 @@
1
- let e,t,r,a;import i from"node:fs";import o from"node:path";import{createHash as n}from"node:crypto";import s from"node:os";import{fileURLToPath as c}from"node:url";import{AppError as d}from"./485.js";import{runCmd as l}from"./8875.js";import{acquireProcessLock as u}from"./8391.js";import{readProcessStartTime as p}from"./9414.js";import{sleep as m}from"./5560.js";import{withDiagnosticTimer as h,emitDiagnostic as f}from"./432.js";import{androidDeviceForSerial as w,runAndroidAdb as g,pullAndroidAdbFile as y}from"./3340.js";import{runXcrun as _,SessionStore as v,IOS_RUNNER_CONTAINER_BUNDLE_IDS as P,requireCommandSupported as S,errorResponse as A,resolveImplicitSessionScope as b,resolvePublicSessionName as M,resolveTargetDevice as C,runAppleRunnerCommand as x}from"./9722.js";import{buildAppleRunnerRequestOptions as R,ensureDeviceReady as I}from"./8414.js";import{defaultRecordingPath as D,appendRecordingExtensionWhenMissing as N}from"./5643.js";import{resolveWebProvider as E}from"./provider.js";import{resolveRecordingProvider as $}from"./recording-provider.js";import{recordingQualityInputToExportQuality as O,RECORDING_EXPORT_QUALITIES as k}from"./2948.js";import{recordSessionAction as F}from"./handler-utils.js";function T(e=process.env){let t=z(),r=o.join(t,"home"),a=o.join(t,"module-cache");return i.mkdirSync(r,{recursive:!0}),i.mkdirSync(a,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:a}}async function L(e){let t=i.statSync(e.sourcePath),r=i.readFileSync(e.sourcePath),a=H(e.cacheName??o.basename(e.sourcePath,o.extname(e.sourcePath))),n=j(["2",process.platform,process.arch,o.resolve(e.sourcePath),t.size,r]),s=o.join(z(),"bin",`${a}-${n}`);return await K({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function U(e){let t=H(e.cacheName),r=j(["2",process.platform,process.arch,e.source]),a=o.join(z(),"sources",`${t}-${r}.swift`),i=o.join(z(),"bin",`${t}-${r}`);return await K({sourcePath:a,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function z(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?o.resolve(e):o.join(s.tmpdir(),"agent-device-swift-cache")}async function K(e){if(V(e.executablePath))return;let t=o.dirname(e.executablePath);i.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`,a=await G(r,e.executablePath,e.timeoutMs??12e4);if(!a)return;let n=i.mkdtempSync(o.join(t,`.${o.basename(e.executablePath)}.${process.pid}.`)),s=o.join(n,o.basename(e.executablePath));try{if(V(e.executablePath))return;void 0===e.sourceText||i.existsSync(e.sourcePath)||(i.mkdirSync(o.dirname(e.sourcePath),{recursive:!0}),i.writeFileSync(e.sourcePath,e.sourceText)),await l("xcrun",["swiftc",e.sourcePath,"-o",s],{timeoutMs:e.timeoutMs??12e4,env:T()}),i.renameSync(s,e.executablePath)}finally{i.rmSync(n,{recursive:!0,force:!0}),await a()}}async function G(e,t,r){if(V(t))return null;try{return await u({lockDirPath:e,owner:{pid:process.pid,startTime:p(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${e} (${r}ms)`})}catch(t){if(t instanceof d&&t.message.startsWith("Timed out waiting for Swift cache lock:"))throw new d("COMMAND_FAILED",t.message,{...t.details,lockDir:e,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${e}" and retry.`});throw t}}function V(e){try{return i.accessSync(e,i.constants.X_OK),i.statSync(e).isFile()}catch{return!1}}function H(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function j(e){let t=n("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}let q=`
1
+ let e,t,r,a;import i from"node:fs";import o from"node:path";import{createHash as n}from"node:crypto";import s from"node:os";import{fileURLToPath as c}from"node:url";import{AppError as d}from"./485.js";import{withDiagnosticTimer as u,emitDiagnostic as l,runCmd as p}from"./8875.js";import{acquireProcessLock as m}from"./8391.js";import{readProcessStartTime as h}from"./9414.js";import{sleep as f}from"./5560.js";import{androidDeviceForSerial as w,runAndroidAdb as g,pullAndroidAdbFile as y}from"./3340.js";import{runXcrun as _,tryGetPlugin as v,SessionStore as P,IOS_RUNNER_CONTAINER_BUNDLE_IDS as S,requireCommandSupported as A,errorResponse as b,resolveImplicitSessionScope as M,resolvePublicSessionName as C,registerBuiltinPlatformPlugins as x,resolveTargetDevice as R,runAppleRunnerCommand as I}from"./9722.js";import{isIosFamily as D}from"./6849.js";import{buildAppleRunnerRequestOptions as N,ensureDeviceReady as E}from"./8414.js";import{defaultRecordingPath as $,appendRecordingExtensionWhenMissing as O}from"./5643.js";import{resolveWebProvider as k}from"./provider.js";import{resolveRecordingProvider as F}from"./recording-provider.js";import{recordingQualityInputToExportQuality as T,RECORDING_EXPORT_QUALITIES as L}from"./2948.js";import{recordSessionAction as U}from"./handler-utils.js";function z(e=process.env){let t=V(),r=o.join(t,"home"),a=o.join(t,"module-cache");return i.mkdirSync(r,{recursive:!0}),i.mkdirSync(a,{recursive:!0}),{...e,HOME:r,CLANG_MODULE_CACHE_PATH:a}}async function K(e){let t=i.statSync(e.sourcePath),r=i.readFileSync(e.sourcePath),a=W(e.cacheName??o.basename(e.sourcePath,o.extname(e.sourcePath))),n=B(["2",process.platform,process.arch,o.resolve(e.sourcePath),t.size,r]),s=o.join(V(),"bin",`${a}-${n}`);return await H({sourcePath:e.sourcePath,executablePath:s,timeoutMs:e.timeoutMs}),s}async function G(e){let t=W(e.cacheName),r=B(["2",process.platform,process.arch,e.source]),a=o.join(V(),"sources",`${t}-${r}.swift`),i=o.join(V(),"bin",`${t}-${r}`);return await H({sourcePath:a,executablePath:i,sourceText:e.source,timeoutMs:e.timeoutMs}),i}function V(){let e=process.env.AGENT_DEVICE_SWIFT_CACHE_DIR?.trim();return e?o.resolve(e):o.join(s.tmpdir(),"agent-device-swift-cache")}async function H(e){if(q(e.executablePath))return;let t=o.dirname(e.executablePath);i.mkdirSync(t,{recursive:!0});let r=`${e.executablePath}.lock`,a=await j(r,e.executablePath,e.timeoutMs??12e4);if(!a)return;let n=i.mkdtempSync(o.join(t,`.${o.basename(e.executablePath)}.${process.pid}.`)),s=o.join(n,o.basename(e.executablePath));try{if(q(e.executablePath))return;void 0===e.sourceText||i.existsSync(e.sourcePath)||(i.mkdirSync(o.dirname(e.sourcePath),{recursive:!0}),i.writeFileSync(e.sourcePath,e.sourceText)),await p("xcrun",["swiftc",e.sourcePath,"-o",s],{timeoutMs:e.timeoutMs??12e4,env:z()}),i.renameSync(s,e.executablePath)}finally{i.rmSync(n,{recursive:!0,force:!0}),await a()}}async function j(e,t,r){if(q(t))return null;try{return await m({lockDirPath:e,owner:{pid:process.pid,startTime:h(process.pid),acquiredAtMs:Date.now()},timeoutMs:r,pollMs:25,ownerGraceMs:r,description:`Swift cache lock: ${e} (${r}ms)`})}catch(t){if(t instanceof d&&t.message.startsWith("Timed out waiting for Swift cache lock:"))throw new d("COMMAND_FAILED",t.message,{...t.details,lockDir:e,timeoutMs:r,hint:`Another agent-device process may still be compiling this Swift helper. Retry shortly; if no agent-device process is active, remove "${e}" and retry.`});throw t}}function q(e){try{return i.accessSync(e,i.constants.X_OK),i.statSync(e).isFile()}catch{return!1}}function W(e){return e.replaceAll(/[^A-Za-z0-9._-]/g,"-").replaceAll(/^-+|-+$/g,"")||"swift-helper"}function B(e){let t=n("sha256");for(let r of e)t.update(Buffer.isBuffer(r)?r:String(r)),t.update("\0");return t.digest("hex").slice(0,16)}let Q=`
2
2
  import Foundation
3
3
  import AVFoundation
4
4
 
@@ -22,5 +22,5 @@ Task {
22
22
 
23
23
  semaphore.wait()
24
24
  exit(exitCode)
25
- `.trim();async function W(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 m(a)}}async function B(e){try{let t=await Q(),r=await l(t,[e],{allowFailure:!0,timeoutMs:1e4,env:T()});if(0===r.exitCode)return!0;if(X(r.stderr,r.stdout))return Z(e);return!1}catch(r){var t;if((t=r)instanceof d&&("TOOL_MISSING"===t.code||X(String(t.details?.stderr??""),String(t.details?.stdout??""))))return Z(e);throw r}}async function Q(){e??=U({source:q,cacheName:"video-validator",timeoutMs:3e4});try{return await e}catch(t){throw e=void 0,t}}async function J(e,t={}){let r=t.pollMs??150,a=t.attempts??12;for(let t=0;t<a;t+=1){if(await B(e))return;await m(r)}}function X(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 Z(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 Y(e){let t=o.parse(e);return o.join(t.dir,`${t.name}.gesture-telemetry.json`)}function ee(e){return[...e].sort((e,t)=>e.tMs-t.tMs)}function et(e){var t,r,a;let o,n,{recording:s,trimStartMs:c}=e,d=(o=Y((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?ee(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)}]})):ee(r))},i.writeFileSync(o,JSON.stringify(n,null,2)),o);return s.telemetryPath=d,d}function er(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 ea(e){var t;let r,a,{videoPath:n,scriptPath:s,scriptArgs:c,commandDescription:u}=e;await W(n),await J(n);let p=(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 L({sourcePath:s});await l(e,["--input",n,"--output",p,...c],{timeoutMs:12e4,env:T()}),await J(p),i.renameSync(p,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(p,{force:!0})}}async function ei(e){let{videoPath:t,trimStartMs:a}=e;a>0&&await ea({videoPath:t,scriptPath:r??=er("recording-trim.swift"),scriptArgs:["--trim-start-ms",String(a)],commandDescription:"Failed to trim the start of the iOS recording"})}async function eo(e){let{videoPath:r,telemetryPath:a,exportQuality:i="medium",targetLabel:o="recording"}=e;await ea({videoPath:r,scriptPath:t??=er("recording-overlay.swift"),scriptArgs:["--events",a,"--quality",i],commandDescription:`Failed to add touch overlays to the ${o}`})}async function en(e){let{videoPath:t,maxSize:r,exportQuality:i="medium",targetLabel:o="recording"}=e;await ea({videoPath:t,scriptPath:a??=er("recording-resize.swift"),scriptArgs:["--max-size",String(r),"--quality",i],commandDescription:`Failed to resize the ${o}`})}function es(e){return e instanceof Error?e.message:String(e)}function ec(e,t){return e.stderr.trim()||e.stdout.trim()||`${t} exited with code ${e.exitCode}`}function ed(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 el(e){let{recording:t,deps:r,trimStartMs:a,targetLabel:i}=e,o=et({recording:t,trimStartMs:a});if(!t.showTouches)return void f({level:"debug",phase:"record_stop_overlay_skipped",data:{reason:"hide_touches"}});if(0===t.gestureEvents.length)return void f({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 h("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: ${es(e)}`}}function eu(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 ep(e){return e.chunks??=[{index:1,path:e.outPath,remotePath:e.remotePath}],e.chunks}async function em(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=ep(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:eu(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 eh(e){let{recording:t,deps:r}=e;ep(t).length<=1?await el({recording:t,deps:r,targetLabel:"Android recording"}):(et({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 ef(e){for(let t of e.chunks){let r=await ew({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 ew(e){let t,{deps:r,deviceId:a,remotePath:o,outPath:n}=e;for(let e=0;e<2;e+=1){eg(n);let s=w(a),c=await y(o,n,{allowFailure:!0,device:s});if(0!==c.exitCode)t=ec(c,"adb pull");else{await r.waitForStableFile(n,{pollMs:250,attempts:20});let t=await r.isPlayableVideo(n);if(f({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;f({level:"warn",phase:"record_stop_android_invalid_video_retry",data:{deviceId:a,remotePath:o,outPath:n,attempt:e+1}})}e<1&&await m(750)}return t?`failed to copy recording from device: ${t}`:(eg(n),"failed to copy recording from device: pulled file is not a playable MP4")}function eg(e){try{i.rmSync(e,{force:!0})}catch{}}let ey={medium:8e6,high:2e7};async function e_(e,t,r){return await g(w(e),t,r)}async function ev(e,t){let r=await e_(e,["shell","ps","-o","pid=","-p",t],{allowFailure:!0});return 0===r.exitCode&&r.stdout.split(/\s+/).map(e=>e.trim()).includes(t)}async function eP(e,t){for(let r=0;r<40;r+=1){if(!await ev(e,t))return!0;await m(250)}return!await ev(e,t)}async function eS(e,t){let r,a=0;for(let i=0;i<20;i+=1){let i=await e_(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 m(250)}}async function eA(e,t,r){for(let a=0;a<8;a+=1){let i=await e_(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 ev(e,r))break;if(a+1>=2)return!0;await m(250)}return!1}async function eb(e){let{deviceId:t,maxSize:r}=e;if(void 0===r)return;let a=await e_(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: ${ec(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:eM(o.width,s),height:eM(o.height,s)}}function eM(e,t){return Math.max(2,2*Math.round(e*t/2))}async function eC(e,t){await e_(e,["shell","rm","-f",t],{allowFailure:!0})}async function ex(e,t){let r=await e_(e,["shell","kill","-9",t],{allowFailure:!0});return f({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 ev(e,t))&&await eP(e,t)}async function eR(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 e_(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(ey[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: ${ec(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 eC(i.id,e);continue}if(f({level:"debug",phase:"record_start_android_started",data:{deviceId:i.id,remotePath:e,remotePid:r}}),await eA(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 ex(i.id,r),await eC(i.id,e)}return{error:A("COMMAND_FAILED",c)}}async function eI(e){let t,{device:r,recordingBase:a}=e;try{t=await eb({deviceId:r.id,maxSize:a.maxSize})}catch(e){return A("COMMAND_FAILED",e instanceof Error?e.message:String(e))}let i=a.exportQuality??"medium",o=await eR({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=em({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 eD({device:r,recording:n,waitForRemoteFileStability:!1}),startNextChunk:async e=>{let a=await eR({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 eD(e){let{device:t,recording:r,waitForRemoteFileStability:a=!0}=e;await ev(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 e_(t.id,["shell","kill","-2",r.remotePid],{allowFailure:!0});if(f({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 eN(t.id,r.remotePid,i);let o=await eE(t.id,r.remotePid);if(o)return o;a&&await eS(t.id,r.remotePath)}async function eN(e,t,r){if(await ev(e,t)&&!await ex(e,t))return`failed to stop recording: ${ec(r,"adb shell kill")}`}async function eE(e,t){if(!await eP(e,t)&&!await ex(e,t))return`failed to stop recording: Android screenrecord pid ${t} did not exit`}async function e$(e){let t,{deps:r,device:a,recording:i,stopRequestedAt:o}=e;f({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 eD({device:a,recording:i});if(i.rotationFailedReason&&!n&&(i.warning??=`Android recording chunk rotation failed: ${i.rotationFailedReason}`),!n){let e=await ef({deps:r,deviceId:a.id,chunks:ep(i)});if(e)return await s(),A("COMMAND_FAILED",eO(e,i,o));await eh({recording:i,deps:r})}if(await s(),n)return A("COMMAND_FAILED",eO(n,i,o));if(t)return A("COMMAND_FAILED",t);return null;async function s(){for(let e of ep(i)){let r=await e_(a.id,["shell","rm","-f",e.remotePath],{allowFailure:!0});f({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: ${ec(r,"adb shell rm")}`)}}}function eO(e,t,r){return ed(e,t,r).message}function ek(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function eF(e,t,r){return R({req:e,logPath:t,traceLogPath:r.trace?.outPath})}async function eT(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=ek(r);try{await o.runAppleRunnerCommand(a,{command:"recordStop",appBundleId:n},eF(t,i,r))}catch(e){f({level:"warn",phase:"record_stop_runner_failed",data:{platform:a.platform,kind:a.kind,deviceId:a.id,session:r.name,error:es(e)}})}}async function eL(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o}=e,n=ek(r);if(n)try{let e=await o.runAppleRunnerCommand(a,{command:"snapshot",appBundleId:n,interactiveOnly:!0,depth:1},eF(t,i,r)),s=Date.now();if("number"==typeof e.currentUptimeMs&&Number.isFinite(e.currentUptimeMs)&&e.currentUptimeMs>0)return f({level:"debug",phase:"record_start_gesture_clock_anchor",data:{source:"warm_snapshot"}}),{gestureClockOriginAtMs:s,gestureClockOriginUptimeMs:e.currentUptimeMs};return}catch(e){f({level:"warn",phase:"record_start_simulator_runner_warm_failed",data:{deviceId:a.id,session:r.name,appBundleId:n,error:es(e)}});return}}async function eU(e){let t,r,{req:a,activeSession:i,sessionStore:o,device:n,logPath:s,deps:c,fpsFlag:d,recordingBase:l,appBundleId:u}=e,p=`agent-device-recording-${Date.now()}.mp4`,m=`tmp/${p}`,h=eF(a,s,i),w=async()=>c.runAppleRunnerCommand(n,{command:"recordStart",outPath:p,fps:d,maxSize:l.maxSize,appBundleId:u},h);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(!es(a).toLowerCase().includes("recording already in progress"))return A("COMMAND_FAILED",`failed to start recording: ${es(a)}`);f({level:"warn",phase:"record_start_runner_desynced",data:{platform:n.platform,kind:n.kind,deviceId:n.id,session:i.name,error:es(a)}});let e=(g=n.id,y=i.name,o.toArray().find(e=>e.name!==y&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===g&&e.recording?.platform==="ios-device-runner"));if(e)return A("COMMAND_FAILED",`failed to start recording: recording already in progress in session '${e.name}'`);try{await c.runAppleRunnerCommand(n,{command:"recordStop",appBundleId:u},h)}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 A("COMMAND_FAILED",`failed to start recording: ${es(e)}`)}}return{platform:"ios-device-runner",remotePath:m,runnerStartedAtUptimeMs:t,targetAppReadyUptimeMs:r,...l}}async function ez(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},eF(t,i,r))}catch(e){return A("COMMAND_FAILED",`failed to start recording: ${es(e)}`)}return{platform:"macos-runner",...s}}async function eK(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;await eT({req:t,activeSession:r,device:a,logPath:i,deps:o});let s={stdout:"",stderr:"",exitCode:1};for(let e of P)if(0===(s=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",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 A("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 el({recording:n,deps:o,trimStartMs:c,targetLabel:"iOS recording"}),null}async function eG(e){let{req:t,activeSession:r,device:a,logPath:i,deps:o,recording:n}=e;return await eT({req:t,activeSession:r,device:a,logPath:i,deps:o}),await el({recording:n,deps:o,targetLabel:"macOS recording"}),null}async function eV(e){let{deps:t,recording:r}=e;r.child.kill("SIGINT");let a=await eH(r.wait,5e3);return a||(await ej(t,r,"SIGINT"),(a=await eH(r.wait,2e3))||(r.child.kill("SIGTERM"),await ej(t,r,"SIGTERM"),a=await eH(r.wait,2e3)))?a:(r.child.kill("SIGKILL"),await ej(t,r,"SIGKILL"),await eH(r.wait,2e3))}async function eH(e,t){return await Promise.race([e,m(t).then(()=>null)])}async function ej(e,t,r){await eW(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){f({level:"warn",phase:"record_stop_ios_simulator_pgrep_failed",data:{outPath:t,signal:r,error:es(e)}});return}let o=eQ(eX(a.stdout)),n=eJ(o,r);f({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 eW(e,t,r){let a=t.recorderPid??t.child.pid;if("number"!=typeof a||!Number.isInteger(a)||a<=0)return f({level:"debug",phase:"record_stop_ios_simulator_owned_recorder_unavailable",data:{outPath:t.outPath,signal:r,reason:"missing_recorder_pid"}}),!1;let i=await eB(e,a,t.outPath,r),o=eQ([a,...i.pids]),n=eJ(o,r);return f({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 eB(e,t,r,a){let i;try{i=await e.runCmd("pgrep",["-P",String(t)],{allowFailure:!0})}catch(e){return f({level:"warn",phase:"record_stop_ios_simulator_owned_pgrep_failed",data:{outPath:r,signal:a,parentPid:t,error:es(e)}}),{pids:[]}}return{pids:eX(i.stdout),exitCode:i.exitCode}}function eQ(e){return Array.from(new Set(e)).filter(e=>Number.isInteger(e)&&e>0&&e!==process.pid)}function eJ(e,t){let r=0;for(let a of e)try{process.kill(a,t),r+=1}catch{}return r}function eX(e){return e.split(/\s+/).map(e=>Number(e)).filter(e=>Number.isInteger(e)&&e>0)}async function eZ(e){let t,r,{req:a,activeSession:i,device:o,logPath:n,deps:s,recordingBase:c,resolvedOut:d}=e,l=c.showTouches?await eL({req:a,activeSession:i,device:o,logPath:n,deps:s}):void 0,{child:u,wait:p}=s.startIosSimulatorRecording({device:o,outPath:d}),m=await e0(d);if(l)t=l.gestureClockOriginAtMs,r=l.gestureClockOriginUptimeMs;else if(c.showTouches)try{let e=Date.now(),c=await s.runAppleRunnerCommand(o,{command:"uptime",appBundleId:ek(i)},eF(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:u,wait:p,...c,recorderPid:u.pid,startedAt:m,gestureClockOriginAtMs:void 0===r?void 0:t,gestureClockOriginUptimeMs:r}}async function eY(e){let{deps:t,recording:r,stopRequestedAt:a}=e;await h("record_stop_tail_settle",()=>t.waitForRecordingTail(r),{platform:r.platform,gestureEventCount:r.gestureEvents.length});let i=await h("record_stop_ios_simulator_process",()=>eV({deps:t,recording:r}),{outPath:r.outPath});if(!i)return e1("failed to stop recording: simctl recordVideo did not exit after 5000ms and forced cleanup",r,a);if(0!==i.exitCode)return e1(`failed to stop recording: ${ec(i,"simctl recordVideo")}`,r,a);if(await h("record_stop_video_stable",()=>t.waitForStableFile(r.outPath,{pollMs:150,attempts:12}),{outPath:r.outPath}),!await h("record_stop_video_playable_check",()=>t.isPlayableVideo(r.outPath),{outPath:r.outPath}))return e1(`failed to stop recording: ${r.outPath} was not finalized into a playable video`,r,a);if(void 0!==r.maxSize)try{await h("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: ${es(e)}`}return await h("record_stop_finalize_overlay",()=>el({recording:r,deps:t,targetLabel:"iOS recording"}),{outPath:r.outPath,showTouches:r.showTouches,gestureEventCount:r.gestureEvents.length}),null}async function e0(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 m(250)}return Date.now()}function e1(e,t,r){let a=ed(e,t,r);return function(e){try{i.rmSync(e,{force:!0})}catch{}}(t.outPath),A("COMMAND_FAILED",a.message)}function e2(e){return"web"===e.platform?e5:"android"===e.platform?e6:"macos"===e.platform?e3:"ios"===e.platform&&"device"===e.kind?e8:"ios"===e.platform?e7:e9}function e4({req:e}){return e.positionals?.[1]??D(void 0)}let e5={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?A("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?D("web"):N(t,".webm")},start:async({activeSession:e,recordingBase:t,resolvedOut:r})=>{var a;let i=(a=r,".webm"!==o.extname(a).toLowerCase()?A("INVALID_ARGS","web recordings must use a .webm output path"):null);if(i)return i;if(e.recordOnlySession)return A("INVALID_ARGS","record on web requires an active browser session; run open <url> --platform web first");let n=E();return n.startRecording?(await n.startRecording(r),{...t,outPath:r,startedAt:Date.now(),platform:"web",showTouches:!1}):A("UNSUPPORTED_OPERATION","record is not supported by this web provider")},stop:async({recording:e})=>await te({recording:e}),cleanupRecordOnlySession:async()=>{try{await E().close()}catch{}}},e8={resolveOutputPath:e4,start:async({req:e,activeSession:t,sessionStore:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s})=>{let c=ek(t);return c?await eU({req:e,activeSession:t,sessionStore:r,device:a,logPath:i,deps:o,fpsFlag:n,recordingBase:s,appBundleId:c}):A("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 eK({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})},e3={resolveOutputPath:e4,start:async({req:e,activeSession:t,device:r,logPath:a,deps:i,fpsFlag:o,recordingBase:n})=>{let s=ek(t);return s?await ez({req:e,activeSession:t,device:r,logPath:a,deps:i,fpsFlag:o,recordingBase:n,appBundleId:s}):A("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 eG({req:e,activeSession:t,device:r,logPath:a,deps:i,recording:o})},e7={resolveOutputPath:e4,start:async({req:e,activeSession:t,device:r,logPath:a,deps:i,recordingBase:o,resolvedOut:n})=>await eZ({req:e,activeSession:t,device:r,logPath:a,deps:i,recordingBase:o,resolvedOut:n}),stop:async({deps:e,recording:t,stopRequestedAt:r})=>await eY({deps:e,recording:t,stopRequestedAt:r})},e6={resolveOutputPath:e4,start:async({device:e,recordingBase:t})=>await eI({device:e,recordingBase:t}),stop:async({deps:e,device:t,recording:r,stopRequestedAt:a})=>await e$({deps:e,device:t,recording:r,stopRequestedAt:a})},e9={resolveOutputPath:e4,start:async()=>A("UNSUPPORTED_OPERATION","record is not supported on this device"),stop:async()=>A("UNSUPPORTED_OPERATION","record is not supported on this device")};async function te(e){let{recording:t}=e,r=E();if(!r.stopRecording)return A("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 A("COMMAND_FAILED",`failed to stop recording: ${t.outPath} was not finalized into a WebM video`)}return null}async function tt(e){"ios"!==e.platform||0!==e.gestureEvents.length&&await m(350)}async function tr(e){let t,{req:r,sessionName:a,sessionStore:n,activeSession:s,device:c,logPath:d,deps:l}=e;if(s.recording)return A("INVALID_ARGS","recording already in progress");let u=r.flags?.fps,p=r.flags?.quality,m=r.flags?.screenshotMaxSize,h=e2(c),f=h.validateStart?.(r)??null;if(f)return f;if(void 0!==u&&(!Number.isInteger(u)||u<1||u>120))return A("INVALID_ARGS","fps must be an integer between 1 and 120");if(void 0!==p&&void 0===O(p))return A("INVALID_ARGS",`quality must be one of: ${k.join(", ")} (legacy numeric values 5-10 are accepted)`);if(void 0!==m&&(!Number.isInteger(m)||m<1))return A("INVALID_ARGS","max-size must be a positive integer");let w=S("record",c);if(w)return w;let g=h.resolveOutputPath({req:r}),y=v.expandHome(g,r.meta?.cwd),_=(t=O(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 P=await h.start({req:r,activeSession:s,sessionStore:n,device:c,logPath:d,deps:l,fpsFlag:u,recordingBase:_,resolvedOut:y});if("ok"in P)return P;s.recording=P,n.set(a,s);let b=n.ensureSessionDir(a);return F(n,s,r,r.command,{action:"start",showTouches:P.showTouches}),{ok:!0,data:{recording:"started",outPath:P.clientOutPath??g,sessionStateDir:b,showTouches:P.showTouches}}}async function ta(e){var t;let r,a,{req:i,activeSession:n,device:s,logPath:c,deps:d}=e;if(!n.recording)return A("INVALID_ARGS","no active recording");let l=n.recording,u=Date.now(),p=l.invalidatedReason;n.recording=void 0;let m=await function(e){let{recording:t}=e;switch(t.platform){case"android":return e6.stop({...e,recording:t});case"ios":return e7.stop({...e,recording:t});case"ios-device-runner":return e8.stop({...e,recording:t});case"macos-runner":return e3.stop({...e,recording:t});case"web":return e5.stop({...e,recording:t})}return t}({req:i,activeSession:n,device:s,logPath:c,deps:d,recording:l,stopRequestedAt:u});if(m)return m;if(p&&"ios"===l.platform&&l.showTouches)l.overlayWarning??=`overlay unavailable: ${p}`;else if(p)return A("COMMAND_FAILED",p);return r="android"===(t=l).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:ti(t,e.index),fileName:o.basename(ti(t,e.index)??e.path)}))),t.telemetryPath&&a.push({field:"telemetryPath",path:t.telemetryPath,localPath:function(e){if(e.clientOutPath)return Y(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:ti(t,e.index)??e.path}))}}}function ti(e,t){if("android"===e.platform&&e.clientOutPath)return eu(e.clientOutPath,t)}async function to(e,t,r,a={}){if(!r.recordOnlySession)return;let i=e2(r.device);await i.cleanupRecordOnlySession?.(r),a.writeLog&&e.writeSessionLog(r),e.delete(t)}async function tn(e){let{req:t,sessionName:r,sessionStore:a,logPath:i}=e,o={runCmd:async(e,t,r)=>"xcrun"===e?await _(t,r):await l(e,t,r),startIosSimulatorRecording:e=>$().startIosSimulatorRecording(e),runAppleRunnerCommand:x,waitForRecordingTail:tt,waitForStableFile:W,isPlayableVideo:B,trimRecordingStart:ei,resizeRecording:en,overlayRecordingTouches:eo},n=a.get(r),s=n?.device??await C(t.flags??{});n||await I(s);let c=n??{name:M(t),sessionScope:b(t),device:s,createdAt:Date.now(),recordOnlySession:!0,actions:[]},d=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(d))return A("INVALID_ARGS","record requires start|stop");if("start"===d)return tr({req:t,sessionName:r,sessionStore:a,activeSession:c,device:s,logPath:i,deps:o});let u=await ta({req:t,activeSession:c,device:s,logPath:i,deps:o});return u.ok?(F(a,c,t,t.command,{action:"stop",outPath:u.data?.outPath,showTouches:u.data?.showTouches}),await to(a,r,c,{writeLog:!0})):await to(a,r,c),u}export{tn as handleRecordCommand};
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};
@@ -29,7 +29,7 @@ declare type LeaseBackend = (typeof LEASE_BACKENDS)[number];
29
29
 
30
30
  declare type MetroPrepareKind = 'auto' | 'react-native' | 'expo';
31
31
 
32
- declare const PLATFORM_SELECTORS: readonly ["ios", "macos", "android", "linux", "web", "apple"];
32
+ declare const PLATFORM_SELECTORS: readonly ["apple", "android", "linux", "web", "ios", "macos"];
33
33
 
34
34
  declare type PlatformSelector = (typeof PLATFORM_SELECTORS)[number];
35
35