agent-device 0.21.21 → 0.21.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.21.apk → agent-device-android-ime-helper-0.21.23.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.23.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.21.manifest.json → agent-device-android-ime-helper-0.21.23.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.23.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.23.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.21.manifest.json → agent-device-android-snapshot-helper-0.21.23.manifest.json} +6 -6
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/back-mode.js +1 -1
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-options.js +3 -3
- package/dist/src/cloud-artifacts.d.ts +6 -0
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/daemon-registration-owner.js +1 -1
- package/dist/src/device-session.js +3 -1
- package/dist/src/dispatch-resolve.js +1 -1
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/durable-capture-resource.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/ime-rebind.js +1 -0
- package/dist/src/ime-state.js +1 -0
- package/dist/src/instance-client.js +1 -1
- package/dist/src/interactor.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +1 -1
- package/dist/src/ios-client.js +4 -4
- package/dist/src/ios-settings.js +1 -1
- package/dist/src/ios-snapshot-engine.js +1 -1
- package/dist/src/log-stream.js +33 -0
- package/dist/src/mechanics.js +16 -16
- package/dist/src/node-http.js +1 -0
- package/dist/src/owner-identity.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/process.js +1 -1
- package/dist/src/proxy.js +2 -2
- package/dist/src/registry.js +1 -1
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-start-budget.js +1 -1
- package/dist/src/runtime10.js +1 -1
- package/dist/src/screenshot-overlay-draw.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +5 -4
- package/dist/src/simctl-settings.js +1 -1
- package/dist/src/store.js +1 -1
- package/package.json +11 -8
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.21.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk.sha256 +0 -1
- package/dist/src/session-stream.js +0 -27
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0268a637de0047d0c8d2e6af9dc0603f96a308dda4369b3f0c2e52a76e67c517 agent-device-android-ime-helper-0.21.23.apk
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-ime-helper",
|
|
3
|
-
"version": "0.21.
|
|
4
|
-
"assetName": "agent-device-android-ime-helper-0.21.
|
|
5
|
-
"sha256": "
|
|
3
|
+
"version": "0.21.23",
|
|
4
|
+
"assetName": "agent-device-android-ime-helper-0.21.23.apk",
|
|
5
|
+
"sha256": "0268a637de0047d0c8d2e6af9dc0603f96a308dda4369b3f0c2e52a76e67c517",
|
|
6
6
|
"packageName": "com.callstack.agentdevice.imehelper",
|
|
7
|
-
"versionCode":
|
|
7
|
+
"versionCode": 21023,
|
|
8
8
|
"serviceComponent": "com.callstack.agentdevice.imehelper/.TestInputMethodService",
|
|
9
9
|
"broadcastProtocol": "android-ime-helper-v1"
|
|
10
10
|
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ea650a2a591be10b417cb5743214d0f23d81d9b433ce5c77d962b29081950c7e agent-device-android-snapshot-helper-0.21.23.apk
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-snapshot-helper",
|
|
3
|
-
"version": "0.21.
|
|
4
|
-
"releaseTag": "v0.21.
|
|
5
|
-
"assetName": "agent-device-android-snapshot-helper-0.21.
|
|
3
|
+
"version": "0.21.23",
|
|
4
|
+
"releaseTag": "v0.21.23",
|
|
5
|
+
"assetName": "agent-device-android-snapshot-helper-0.21.23.apk",
|
|
6
6
|
"apkUrl": null,
|
|
7
|
-
"sha256": "
|
|
8
|
-
"checksumName": "agent-device-android-snapshot-helper-0.21.
|
|
7
|
+
"sha256": "ea650a2a591be10b417cb5743214d0f23d81d9b433ce5c77d962b29081950c7e",
|
|
8
|
+
"checksumName": "agent-device-android-snapshot-helper-0.21.23.apk.sha256",
|
|
9
9
|
"packageName": "com.callstack.agentdevice.snapshothelper",
|
|
10
|
-
"versionCode":
|
|
10
|
+
"versionCode": 21023,
|
|
11
11
|
"instrumentationRunner": "com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",
|
|
12
12
|
"minSdk": 23,
|
|
13
13
|
"targetSdk": 36,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{b as e}from"./sdk-contracts.js";import{Gr as t,Lr as n,ei as r,jr as i,qr as a}from"./sdk-batch.js";import{n as o,t as s}from"./rect-center.js";const c=new WeakMap;function l(e,t){return c.set(e,{...c.get(e),...t}),e}function u(e,t){return l(e,{clickability:t})}function d(e){return e?c.get(e)?.clickability:void 0}function f(e,t){let n=d(e);return n?u(t,n):t}function p(e,t){return l(e,{occlusionContext:t})}function m(e){return e?c.get(e)?.occlusionContext:void 0}const h=[`tabbar`,`toolbar`,`navigationbar`,`bottomnavigation`,`bottomnavigationview`,`sheet`,`dialog`,`alert`,`popover`,`menu`],g=[`tabbar`,`toolbar`,`navigationbar`],_=[`toolbar`],v=[`scrollbar`,`scrollindicator`],y=[`button`,`link`,`menuitem`,`tabitem`,`textfield`,`searchfield`,`edittext`,`checkbox`,`radio`,`switch`,`cell`];function b(e){let t=new Map,n=new Map;for(let r of e){if(t.set(r.index,r),typeof r.parentIndex!=`number`)continue;let e=n.get(r.parentIndex);e?e.push(r):n.set(r.parentIndex,[r])}return{byIndex:t,childrenByParent:n}}function x(e,t={}){if(e.length<2)return e;let n=b(e),r={nodes:e,byIndex:n.byIndex,neighbourhood:n,overlayPositions:e.flatMap((e,r)=>A(e,n,t)?[r]:[]),coverCache:new Map},i=[];for(let[n,a]of e.entries())k(a)&&T(r,n,a,t)&&i.push(n);return C(e,i)}function S(e,t){let n=[];for(let[r,i]of e.entries())k(i)&&t(i)&&n.push(r);return C(e,n)}function C(e,t){if(t.length===0)return e;let n=[...e];for(let r of t){let t=e[r];n[r]={...t,hittable:!1,interactionBlocked:`covered`,presentationHints:G(t.presentationHints)}}return n}function w(e){return e.interactionBlocked!==void 0}function T(t,n,r,i){let a=t.coverCache.get(n);if(a!==void 0)return a;t.coverCache.set(n,null);let o=W(r.rect);if(!o)return E(t,n,null);let s=e(o),c=i.isAdditionalOverlayNode?.(r)===!0;for(let e of t.overlayPositions){if(!ee(t,e,n,c,i))continue;let a=t.nodes[e];if(D(t,e,r,o,s,i))return E(t,n,a)}return E(t,n,null)}function ee(e,t,n,r,i){let a=e.nodes[t];return a?t>n?!0:t===n||r?!1:i.isAdditionalOverlayNode?.(a)===!0:!1}function E(e,t,n){return e.coverCache.set(t,n),n}function D(e,t,n,r,i,o){if(!e.nodes[t])return!1;let s=O(e,t,n,r,o);return!!(s&&a(s,i.x,i.y))}function O(e,t,n,r,i){let a=e.nodes[t];if(!a||!A(a,e.neighbourhood,i)||H(n,a,e.byIndex))return null;let o=W(a.rect);return!o||s(r,o)||T(e,t,a,i)?null:o}function k(e){return W(e.rect)?e.hittable===!0||z(e)?!0:!!(e.label?.trim()||e.value?.trim()||e.identifier?.trim()):!1}function A(e,t,n){return!W(e.rect)||i(e)||F(e,t.byIndex)||j(e,t)||M(e,t)?!1:B(e,h)||I(e,t.byIndex,n)}function j(e,t){if(!B(e,g)||typeof e.parentIndex!=`number`)return!1;let n=W(e.rect);return n?(t.childrenByParent.get(e.parentIndex)??[]).some(t=>t.index!==e.index&&s(n,t.rect)):!1}function M(e,t){if(!B(e,_)||typeof e.parentIndex!=`number`)return!1;let n=W(e.rect);if(!n)return!1;let r=t.childrenByParent.get(e.parentIndex),i=r.findIndex(t=>t.index===e.index),a=N(r,i),o=!1;for(let[e,t]of r.entries())if(!(e===i||!P(n,t))){if(e<a||e>i)return!1;o=!0}return o}function N(e,t){for(let n=t-1;n>=0;n--)if(B(e[n],_))return n+1;return 0}function P(e,n){let i=B(n,g)||t(n)&&!B(n,v),a=W(n.rect);return!!(i&&a&&r(e,a))}function F(e,t){if(!B(e,g))return!1;let n=W(e.rect);if(!n)return!1;let r=typeof e.parentIndex==`number`?t.get(e.parentIndex):void 0,a=new Set;for(;r&&!a.has(r.index);){if(i(r)){let e=W(r.rect);return!!(e&&s(n,e))}a.add(r.index),r=typeof r.parentIndex==`number`?t.get(r.parentIndex):void 0}return!1}function I(e,t,n){return n.isAdditionalOverlayNode?.(e)===!0&&!L(e,t,n)}function L(e,t,n){let r=typeof e.parentIndex==`number`?t.get(e.parentIndex):void 0,i=new Set;for(;r&&!i.has(r.index);){if(R(r,n))return!0;i.add(r.index),r=typeof r.parentIndex==`number`?t.get(r.parentIndex):void 0}return!1}function R(e,t){return t.isAdditionalOverlayNode?.(e)===!0&&W(e.rect)!==null&&!i(e)}function z(e){return B(e,y)}function B(e,t){let n=V(e);return t.some(e=>n.includes(e))}function V(e){return[e.type,e.role,e.subrole].map(e=>n(e??``)).join(` `)}function H(e,t,n){return U(e,t,n)||U(t,e,n)}function U(e,t,n){let r=typeof t.parentIndex==`number`?n.get(t.parentIndex):void 0,i=new Set;for(;r&&!i.has(r.index);){if(r.index===e.index)return!0;i.add(r.index),r=typeof r.parentIndex==`number`?n.get(r.parentIndex):void 0}return!1}function W(e){let t=o(e);return t&&t.width>0&&t.height>0?t:null}function G(e){return Array.from(new Set([...e??[],`covered`]))}const K=new Set([`com.google.android.inputmethod.latin`,`com.samsung.android.honeyboard`,`com.touchtype.swiftkey`,`com.microsoft.swiftkey`]);function q(e){let t=$(e.packageName),n=(e.resourceId??``).toLowerCase(),r=$(e.activeInputMethodPackage);if(t&&r&&t===r)return{inputMethodOwned:!0,source:`active-input-method`};if(r&&n.startsWith(`${r}:id/`))return{inputMethodOwned:!0,source:`active-input-method-resource`};if(t&&K.has(t))return{inputMethodOwned:!0,source:`known-ime-package`};for(let e of K)if(n.startsWith(`${e}:id/`))return{inputMethodOwned:!0,source:`known-ime-resource`};return{inputMethodOwned:!1,source:`app`}}function J(e,t,n){return q({packageName:e,resourceId:t,activeInputMethodPackage:n}).inputMethodOwned}function Y(e){return q(e).inputMethodOwned}function X(e){return Y({packageName:e.bundleId,resourceId:e.identifier})}function Z(e){let t=$(e);return!!(t&&K.has(t))}function Q(e){let t=(e??``).toLowerCase();for(let e of K)if(t.startsWith(`${e}:id/`))return!0;return!1}function te(e,t,n){return!e&&!t?`unknown`:J(e,t,n)?`ime`:`app`}function ne(e){for(let t of[/\bmCurMethodId=([^\s]+)/i,/\bmCurId=([^\s]+)/i,/\bmCurrentInputMethodId=([^\s]+)/i,/\bcurMethodId=([^\s]+)/i]){let n=re(e.match(t)?.[1]);if(n)return n}}function re(e){let t=(e??``).trim();if(t)return $((t.split(`/`)[0]??``).match(/[a-zA-Z0-9_.]+/)?.[0])}function $(e){return(e??``).trim().toLowerCase()||void 0}export{Q as a,S as c,p as d,f,Z as i,w as l,m,X as n,ne as o,d as p,Y as r,x as s,te as t,u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./device2.js";import{r as t}from"./client-options.js";import{
|
|
1
|
+
import{r as e}from"./device2.js";import{r as t}from"./client-options.js";import{N as n}from"./log-stream.js";import{t as r}from"./ios-client.js";import{t as i}from"./instance-client.js";import{t as a}from"./async-lifecycle.js";async function o(e){if(e.signal?.throwIfAborted(),e.descriptor.ownership===`attached`)return await s(e.instances??{},e.descriptor,e.dependencies);let r=t(e.limrun,`Reconnecting app logs`);try{return e.descriptor.platform===`ios`?await l({...e,limrun:r}):await d({...e,limrun:r})}catch(e){if(e instanceof n)return{status:`missing`};throw e}}async function s(e,t,n){return t.platform===`ios`?c(e.ios,t)?await u(e.ios,t):{status:`ownership-lost`}:c(e.android,t)?await f(e.android,t,n):{status:`ownership-lost`}}function c(t,n){return t!==void 0&&e(t.apiUrl)===n.instanceId}async function l(e){let t=await p(async()=>await e.limrun.iosInstances.get(e.descriptor.instanceId,{timeout:5e3,maxRetries:0,signal:e.signal}),e.descriptor);return t.status===`active`?await u({apiUrl:t.apiUrl,token:t.token},e.descriptor):t}async function u(e,t){let n=await r({apiUrl:e.apiUrl,token:e.token,logLevel:`warn`});return{status:`opened`,reader:{platform:`ios`,leaseId:t.leaseId,instanceId:t.instanceId,ownership:t.ownership,readLogs:async(e,t)=>await n.appLogTail(e,t),[Symbol.asyncDispose]:async()=>n.disconnect()}}}async function d(e){let t=await p(async()=>await e.limrun.androidInstances.get(e.descriptor.instanceId,{timeout:5e3,maxRetries:0,signal:e.signal}),e.descriptor);if(t.status!==`active`)return t;let{instance:n}=t;return n.status.adbWebSocketUrl?await f({apiUrl:t.apiUrl,adbUrl:n.status.adbWebSocketUrl,token:t.token},e.descriptor,e.dependencies):{status:`missing`}}async function f(e,t,n){let r=await i({apiUrl:e.apiUrl,adbUrl:e.adbUrl,token:e.token,logLevel:`warn`}),o=new a,s=!1;o.defer(async()=>{s||r.disconnect()});try{let e=await r.startAdbTunnel();o.defer(async()=>{s||e.close()});let i=`${e.address.address}:${e.address.port}`,a=async(e,t)=>await n.host.runAdb(n.android.deviceAdbInvocation(i,e),t),c={platform:`android`,leaseId:t.leaseId,instanceId:t.instanceId,ownership:t.ownership,readLogs:async(e,t)=>await n.android.readLogs(a,t),[Symbol.asyncDispose]:async()=>{await n.host.runAdb(n.android.hostAdbInvocation([`disconnect`,i]),{allowFailure:!0,timeoutMs:1e4}).catch(()=>void 0);let t=(await Promise.allSettled([Promise.resolve().then(()=>e.close()),Promise.resolve().then(()=>r.disconnect())])).flatMap(e=>e.status===`rejected`?[e.reason]:[]);if(t.length===1)throw t[0];if(t.length>1)throw AggregateError(t,`Limrun Android app-log reader cleanup failed`)}};return s=!0,{status:`opened`,reader:c}}finally{await o[Symbol.asyncDispose]()}}async function p(e,t){let n=await e();if(!m(n.metadata.labels,t))return{status:`ownership-lost`};let{apiUrl:r,token:i}=n.status;return n.status.state===`terminated`||!r||!i?{status:`missing`}:{status:`active`,instance:n,apiUrl:r,token:i}}function m(e,t){return e?.provider===`limrun`&&e.leaseId===t.leaseId}export{o as reconnectLimrunAppLogReader};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{P as e}from"./sdk-contracts.js";import{p as t}from"./sdk-device.js";import{$t as n,tn as r}from"./sdk-batch.js";import{a as i,o as a}from"./device2.js";import{n as o,r as s}from"./request-cancellation.js";import{n as c,t as l}from"./application-lifecycle-runtime.js";import{A as u,B as d,C as f,D as ee,F as te,G as p,I as m,J as h,M as ne,N as re,R as ie,U as ae,V as g,d as _,h as
|
|
2
|
-
`)?r:`${r}\n`),a=`active`}catch{if(o)return;a=`recovering`}await e.host.clock.sleep(1e3)}})(),l;return
|
|
1
|
+
import{P as e}from"./sdk-contracts.js";import{p as t}from"./sdk-device.js";import{$t as n,tn as r}from"./sdk-batch.js";import{a as i,o as a}from"./device2.js";import{n as o,r as s}from"./request-cancellation.js";import{n as c,t as l}from"./application-lifecycle-runtime.js";import{A as u,B as d,C as f,D as ee,F as te,G as p,I as m,J as h,M as ne,N as re,R as ie,U as ae,V as g,d as _,h as oe,k as se,n as ce,o as le,q as ue,s as de,v as fe,w as v,x as y,z as pe}from"./alert-runtime.js";import{n as me}from"./audio-probe-runtime.js";import{n as he}from"./perf-runtime.js";import{i as ge,n as _e}from"./touch-runtime.js";import{r as ve}from"./platform-runtime-unavailable.js";import{a as ye,n as be}from"./durable-resource.js";import{t as xe}from"./async-lifecycle.js";import{a as b,d as Se,f as Ce,n as we,o as Te,u as Ee}from"./src7.js";import{i as De,t as Oe}from"./gesture-admission.js";import{n as ke}from"./interactor-operation-catalog.js";import{t as x}from"./app-log-runtime.js";import{r as Ae,t as je}from"./application-lifecycle-interaction.js";import{n as Me,r as Ne,t as Pe}from"./screen-recording-transport.js";import{setTimeout as Fe}from"node:timers/promises";const S=Object.freeze({available:!0}),Ie=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions do not expose portable gesture execution yet.`}),Le=Object.freeze({available:!1,reason:`unsupported-provider-mode`}),Re=Object.freeze({available:!1,reason:`unsupported-provider-mode`}),ze=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:Oe}),Be=Object.freeze({available:!1,reason:`unsupported-platform-leaf`,hint:De});function C(e,t){if(!t.available)return m({unsupported:t});if(e.platform!==`android`)return m({unsupported:Ie});let n=e.target===`tv`;return m({unsupported:Le,plan:S,directionalFling:S,multiTouch:n?ze:S,targetAuthoredDrag:n?Be:S,viewport:S})}const Ve=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions do not expose tv remote control.`}),He=Object.freeze({available:!1,reason:`unsupported-device-kind`,hint:`tv-remote is supported only on Android TV targets.`}),Ue=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions do not expose keyboard actions.`}),We=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions cannot read settings back.`}),Ge=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions do not expose app switcher yet.`}),w=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`No Limrun session exposes this system button.`});function T(e,n){let r=n??S,i=Object.freeze({available:!1,reason:`unsupported-provider-mode`});return Object.freeze({...pe({focus:r}),...u({type:r}),...ge({unsupported:i,tap:r,longPress:r,hover:n??i,fill:r,tapElementSelector:n??(t(e)?r:i)}),...C(e,r),...re({scroll:r})})}function Ke(e){let{device:t,signal:n}=e,r=n=>e.getInteractor(t,n);return Object.freeze({...ae({device:t,signal:n,resolveInteractor:r,presentIosAcquisition:e.presentIosAcquisition}),...ie({device:t,signal:n,resolveInteractor:r}),...se({device:t,signal:n,resolveInteractor:r}),..._e({device:t,signal:n,resolveInteractor:r,facts:T(t),pause:async e=>await Fe(e,void 0,{signal:n})}),...ue({device:t,signal:n,resolveInteractor:r}),...te({device:t,signal:n,facts:C(t,S),resolveInteractor:r}),...ne({device:t,signal:n,resolveInteractor:r})})}function E(e,t){return t?Object.freeze({...v({back:t}),...f({orientation:t}),...y({tvRemote:t})}):e.platform===`android`?Object.freeze({...v({back:S}),...f({orientation:S}),...y({tvRemote:e.target===`tv`?S:He})}):Object.freeze({...v({back:S}),...f({orientation:S}),...y({tvRemote:Ve})})}function D(e){return Object.freeze(e?{...oe({unsupported:e})}:{...oe({unsupported:Re,read:S,write:S})})}const qe=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS direct sessions do not expose alert inspection yet.`});function O(e,t){let n=t??(e.platform===`android`?S:qe);return Object.freeze({...ce({read:n,wait:n,accept:n,dismiss:n})})}function k(e,t){return t?_({unsupported:t}):e.platform===`android`?_({unsupported:w,home:S,appSwitcher:S}):_({unsupported:w,home:S,appSwitcher:Ge})}const A=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`fold runs a HID helper through simctl spawn inside a foldable iPhone simulator on the daemon host; a Limrun session has no such simulator.`});function j(){return Object.freeze({setFoldPose:A})}function M(e,t){return Object.freeze({...de({triggerAppEvent:t??S})})}function N(e,t){let n=t??S,r=t??(e.platform===`android`?S:We);return Object.freeze({...le({setSetting:n,readSetting:r})})}function P(e,t){let n=t??Ue,r=t===void 0&&e.platform===`android`;return Object.freeze({...fe(r?{unsupported:n,status:S,dismiss:S,enter:S}:{unsupported:n})})}const F=Object.freeze({resourceKind:x,version:1,encode:e=>({...e}),decode:e=>{let t=Ye(e.ownership);return!t||e.transport!==`limrun-log-poller`||e.platform!==`ios`&&e.platform!==`android`||!I(e.leaseId)||!I(e.instanceId)||!I(e.appBundleId)||!I(e.outputPath)?{status:`invalid`,message:`Invalid Limrun app-log descriptor`}:{status:`decoded`,descriptor:Object.freeze({transport:`limrun-log-poller`,platform:e.platform,leaseId:e.leaseId,instanceId:e.instanceId,ownership:t,appBundleId:e.appBundleId,outputPath:e.outputPath})}}});function Je(e){if(e.device.platform===`apple`&&!e.device.appleOs)throw TypeError(`Limrun Apple app-log persistence requires an explicit appleOs identity`);return be({resourceKind:x,sessionId:e.sessionId,device:{id:e.device.id,family:e.device.platform,...e.device.appleOs===void 0?{}:{appleOs:e.device.appleOs},kind:e.device.kind,...e.device.target===void 0?{}:{target:e.device.target},...e.device.iosPhysicalDeviceBackend===void 0?{}:{iosPhysicalDeviceBackend:e.device.iosPhysicalDeviceBackend}},owner:e.owner,fence:e.fence,lifecycle:`open`,descriptor:ye(F,e.descriptor)})}function Ye(e){return e===void 0?`created`:e===`created`||e===`attached`?e:void 0}function I(e){return typeof e==`string`&&e.trim().length>0}async function L(e){let t=new xe,n=!1;t.defer(async()=>{n||await e.reader[Symbol.asyncDispose]()});try{let r=await e.host.outputs.readTail(e.outputPath,262144),i=await e.host.outputs.openAppend(e.outputPath);t.defer(async()=>{n||await i[Symbol.asyncDispose]()});let a=Xe(e,i,tt(r));return n=!0,a}finally{await t[Symbol.asyncDispose]()}}function Xe(e,t,n){let r=rt(e.reader),i=e.host.clock.now(),a=`active`,o=!1,s=n,c=(async()=>{for(;!o;){try{let n=await Ze(e);if(n.status===`timeout`){a=`failed`;return}if(o)return;let r=Qe(s,n.text);s=n.text,r&&await t.write(r.endsWith(`
|
|
2
|
+
`)?r:`${r}\n`),a=`active`}catch{if(o)return;a=`recovering`}await e.host.clock.sleep(1e3)}})(),l;return Ee({inspect:()=>({backend:r,state:a,startedAt:i}),finish:async()=>l??=(async()=>(o=!0,await c,(await nt([e.reader,t])).length>0?(a=`failed`,{status:`cleanup-pending`,reason:`transport-failed`,message:`Limrun app-log cleanup did not settle every owned resource`}):(a=`ended`,{status:`completed`,result:{backend:r,outputPath:e.outputPath,completedAt:e.host.clock.now()}})))()})}async function Ze(e){let t=new AbortController,n=o(e.reader.readLogs(e.appBundleId,1e3),t.signal,`App-log provider read aborted`).then(e=>({status:`read`,text:e}));try{let r=await Promise.race([n,e.host.clock.sleep(5e3,t.signal).then(()=>({status:`timeout`}))]);return r.status===`timeout`&&(t.abort(),await n.catch(()=>void 0)),r}finally{t.abort()}}function Qe(e,t){if(!e||!t)return t;let n=$e(t),r=Math.min(e.length,t.length),i=e.slice(e.length-r);return t.slice(et(i,t,n))}function $e(e){let t=new Uint32Array(e.length),n=0;for(let r=1;r<e.length;r+=1){for(;n>0&&e[r]!==e[n];)n=t[n-1];e[r]===e[n]&&(n+=1),t[r]=n}return t}function et(e,t,n){let r=0;for(let i=0;i<e.length;i+=1){for(;r>0&&e[i]!==t[r];)r=n[r-1];e[i]===t[r]&&(r+=1),r===t.length&&i<e.length-1&&(r=n[r-1])}return r}function tt(e){return e.split(`
|
|
3
3
|
`).filter(e=>!e.startsWith(`[agent-device][mark]`)).join(`
|
|
4
|
-
`)}async function rt(e){return(await Promise.allSettled(e.map(async e=>await e[Symbol.asyncDispose]()))).flatMap(e=>e.status===`rejected`?[e.reason]:[])}function it(e){return e.platform===`ios`?`ios-simulator`:`android`}function at(e){let t=Ae({owner:`Limrun`,openTargetIdentity:`bundle-id`,closeBeforeRelaunch:!0,configureProviderPortReverse:async t=>await e.configurePortReverse(t),binding:ke({device:e.device,signal:e.signal,resolveInteractor:t=>e.getInteractor(e.device,t)})}),n=e.resolveAppReference;return n?Object.freeze({...t,resolveOpenTarget:async e=>await t.resolveOpenTarget(ot(e,n)),openApplication:async e=>await t.openApplication(st(e,n)),closeApplication:async e=>await t.closeApplication(ct(e,n))}):t}function ot(e,t){return e.target===void 0?e:{...e,target:t(e.target)}}function st(e,t){return{...e,target:B(e.target,t),positionals:z(e.positionals,t),appBundleId:B(e.appBundleId,t)}}function ct(e,t){return{...e,positionals:z(e.positionals,t),appBundleId:B(e.appBundleId,t)}}function z(e,t){let n=e[0];return n===void 0?e:[t(n),...e.slice(1)]}function B(e,t){return e===void 0?void 0:t(e)}function lt(e){let t=a(e.id);return!t||e.target!==`mobile`?!1:t.platform===`ios`?e.platform===`apple`&&e.appleOs===`ios`&&e.kind===`simulator`&&e.iosPhysicalDeviceBackend===void 0:e.platform===`android`&&e.appleOs===void 0&&e.kind===`emulator`&&e.iosPhysicalDeviceBackend===void 0}const ut=Object.freeze({available:!0}),V=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`The Limrun provider session is no longer active for this device.`}),dt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Push notifications are unavailable for Limrun provider-owned devices.`});function H(e,t){let n=pt(e,t);return Object.freeze({deployApp:n,materializeAppSource:n,deployMaterializedApp:n,sendPushNotification:U(e,t)?dt:V})}function ft(e,t,n,r){let i=e.deployApp,a=e.deployMaterializedApp;return!H(e,t).deployApp.available||!i||!a?Object.freeze({}):Object.freeze({deployApp:async e=>W(await i(t,e,n,r)),materializeAppSource:async r=>await mt(e.host,t,r,n),deployMaterializedApp:async e=>W(await a(t,e,n,r))})}function pt(e,t){return lt(t)&&U(e,t)&&e.deployApp&&e.deployMaterializedApp?ut:V}function U(e,t){return e.isSessionActive?.(t)??e.ownsDevice(t)}async function mt(e,t,n,r){return await(t.platform===`apple`?e.appleDeployment:e.androidDeployment).prepareArtifact(n,{signal:r})}function W(t){if(!t)throw new e(`UNSUPPORTED_OPERATION`,`The Limrun provider session is no longer active.`);return t}const ht=Object.freeze({medium:5,high:8});function gt(e){return Object.freeze({screenRecordingStart:async t=>await _t(e,t),screenRecordingReattach:async()=>Me(`Limrun recordings cannot be reattached after daemon restart.`),screenRecordingCleanup:async()=>je(`Limrun recordings cannot be cleaned after daemon restart; the instance disposes them when it terminates.`)})}async function _t(t,n){let r=t.getDeviceSession(t.device);if(!r)throw new e(`UNSUPPORTED_OPERATION`,`Limrun recording requires a live provider session for this device.`,{deviceId:t.device.id});return await Ne({host:t.host,device:t.device,owner:t.owner,input:n,signal:t.signal,transport:{backend:`limrun-recorder`,targetLabel:`Limrun recording`,start:async()=>{await r.startRecording({quality:ht[n.exportQuality??`medium`]})},stop:async()=>(await r.stopRecording()).downloadUrl,collect:async(e,t)=>{await r.downloadRecording({downloadUrl:e,outPath:t})}},support:{scopes:[`app`,`device`,`system`],fps:!1,exportQuality:!0,hideTouches:!1},unsupported:e=>`Limrun recordings do not support ${e.join(`, `)}`})}const G=Object.freeze({available:!0}),K=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Custom snapshot actions are available only for Limrun iOS simulator sessions.`}),vt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun does not expose viewport resizing.`}),q=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun-owned devices read element text from the captured tree only.`}),yt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Headless boot is unavailable for provider-owned devices.`}),J=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`Limrun requires a matching live provider session for this device.`}),bt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Apple runner preparation is unavailable for Limrun-owned devices.`}),xt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS appstate is session-owned; no sessionless provider foreground probe is exposed.`}),St=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun open requires a Limrun-owned iOS simulator or Android emulator.`}),Ct=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun close requires a Limrun-owned iOS simulator or Android emulator.`}),Y=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Runtime hints are not applied to provider-owned devices.`}),wt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun port reverse requires an active Android Limrun session.`}),Tt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun does not expose the audio probe.`});function Et(e){return{...e,isSessionActive:e.hasLiveSession}}function X(e,t){let n=Dt(e,t),r=Ot(e,t),i=kt(e,t);return l({resolveOpenTarget:n,prepareApplicationOpen:n,openApplication:n,applyRuntimeHints:Y,clearRuntimeHints:Y,closeApplication:r,finalizeApplicationClose:r,prepareAppleRunner:bt,configureProviderPortReverse:i})}function Dt(e,t){return i(e)?t?G:J:St}function Ot(e,t){return i(e)?t?G:J:Ct}function kt(e,t){return t?e.platform===`android`?G:wt:J}function Z(e,n){let r=H(Et(e),n),i=n.platform===`android`,a=t(n)&&n.kind===`simulator`?G:K;return Object.freeze({device:{family:n.platform,...n.appleOs===void 0?{}:{appleOs:n.appleOs},kind:n.kind,...n.target===void 0?{}:{target:n.target},...n.iosPhysicalDeviceBackend===void 0?{}:{iosPhysicalDeviceBackend:n.iosPhysicalDeviceBackend},providerMode:`provider-runtime`},operations:{appLogInspect:G,appLogDoctor:G,appLogStart:G,appLogReattach:G,appLogCleanup:G,...r,appState:i?G:xt,networkDump:G,screenRecordingStart:G,screenRecordingReattach:G,screenRecordingCleanup:G,...p({capture:G,customActions:a,withoutActiveApp:G}),...h({capture:G}),...g({findText:K}),...d({setViewport:vt}),...E(n),...ee({readTextAtPoint:q}),...D(n),...F(n),...O(n),...A(n),...M(),...N(n),...P(n),...k(n),...pe({capture:Tt,query:Tt}),...me({frames:q,memorySample:q,memorySnapshot:q,nativeCapture:q,profileReport:q}),ensureReady:G,bootTarget:G,bootTargetHeadless:yt,listApps:G,shutdownTarget:{available:!1,reason:`unsupported-provider-mode`,hint:`Limrun owns the target lifecycle for provider-owned devices.`},...X(n,!0)}})}function At(e,t){let n=Z(e,t);return Object.freeze({device:n.device,operations:{...n.operations,appLogInspect:J,appLogDoctor:J,appLogStart:J,appLogReattach:G,appLogCleanup:G,appState:J,networkDump:J,screenRecordingStart:J,screenRecordingReattach:J,screenRecordingCleanup:J,...p({capture:J,customActions:J,withoutActiveApp:J}),...h({capture:J}),...g({findText:J}),...d({setViewport:J}),...E(t,J),...D(t,J),...F(t,J),...O(t,J),...A(t,J),...M(),...N(t,J),...P(t,J),...k(t,J),ensureReady:J,bootTarget:J,bootTargetHeadless:J,listApps:J,deployApp:J,materializeAppSource:J,deployMaterializedApp:J,sendPushNotification:J,shutdownTarget:J,...X(t,!1)}})}function jt(t){let a=n(`limrun`,t.runtimeInstance),o=e=>i(e)&&t.ownsDevice(e),s=e=>o(e)&&t.hasLiveSession(e);return Object.freeze({owner:a,ownsDevice:o,inspectFacts:async e=>s(e)?Z(t,e):_e(e,a,{appLog:J,appState:J,appDeployment:J,network:J,screenshot:J,viewport:J,focus:J,gesture:J,scroll:J,typeText:J,touch:J,elementText:J,back:J,orientation:J,tvRemote:J,keyboard:J,clipboard:J,systemButton:J,fold:j,triggerAppEvent:J,settings:J,readAlert:J,awaitAlert:J,acceptAlert:J,dismissAlert:J,audioProbeCapture:J,audioProbeQuery:J,perf:J,readiness:J,shutdown:J,lifecycle:X(e,!1)}),bind:async n=>{if(n.intent.kind===`exact-owner`&&!r(n.intent.owner,a))throw new e(`UNSUPPORTED_OPERATION`,`Limrun app-log owner identity does not match`);if(!i(n.device))throw new e(`UNSUPPORTED_PLATFORM`,`Limrun app logs require an iOS simulator or Android emulator device identity`);let o=s(n.device);if(n.intent.kind!==`exact-owner`&&!o)throw new e(`UNSUPPORTED_OPERATION`,`Limrun provider session is no longer live for the selected device`,{reason:`provider-session-unavailable`});return Mt(t,a,n.device,n.scope.signal,!o)},shutdown:async()=>void 0})}function Mt(t,n,r,i,a){let o=a?At(t,r):Z(t,r),l=s(),u=xe({codec:I,reattach:async(e,n)=>{if(!$(e,r)||!x(t.host,n.sessionId,e))return{status:`unreattachable`,reason:`descriptor-invalid`,message:`Limrun app-log descriptor does not match the bound device or owning session`};let a=await t.reconnect(e,i);return a.status===`missing`?{status:`missing`}:a.status===`ownership-lost`?{status:`unreattachable`,reason:`ownership-fence-lost`}:{status:`active`,handle:await R({host:t.host,reader:a.reader,appBundleId:e.appBundleId,outputPath:e.outputPath})}},cleanup:async(e,n)=>$(e,r)&&x(t.host,n.sessionId,e)?{status:`cleaned`}:{status:`cleanup-pending`,reason:`ownership-fence-lost`,message:`Limrun app-log descriptor does not match the bound device or owning session`}}),d={appLogInspect:async()=>({backend:Q(r)}),appLogDoctor:async()=>({backend:Q(r),checks:{limrunSessionAvailable:await Nt(t,r,i)},notes:[]}),appLogStart:async a=>{we(t.host,a),i.throwIfAborted();let o=await t.openCurrent(r);if(!o)throw new e(`UNSUPPORTED_OPERATION`,`Limrun app logs require an active instance`);let s={transport:`limrun-log-poller`,platform:o.platform,leaseId:o.leaseId,instanceId:o.instanceId,ownership:o.ownership,appBundleId:a.appBundleId,outputPath:a.outputPath},c=!1;try{i.throwIfAborted();let e=Ye({sessionId:a.sessionId,device:r,owner:n,fence:a.fence,descriptor:s});c=!0;let l=await R({host:t.host,reader:o,appBundleId:a.appBundleId,outputPath:a.outputPath});return Se(l,e)}catch(e){throw c||await o[Symbol.asyncDispose](),e}},...u,networkDump:async e=>{let n=await t.host.appLogs.readRecent(e.sessionId,e.maxScanLines),i=Q(r),{dump:a}=Ce(n.text,{...e,path:n.path,exists:n.exists,lineNumberOffset:n.skippedLines,backend:i}),o=a.entries.length===0?[`No HTTP(s) entries were found in recent session app logs.`]:[];return Object.freeze({source:`app-log`,backend:i,dump:a,notes:o})},ensureReady:async()=>({...r,booted:!0}),bootTarget:async()=>({...r,booted:!0}),listApps:async e=>await t.listApps(e.device,e.filter,i),...r.platform===`android`?{appState:async()=>await t.getAppState(r,i)}:{},...c(at({device:r,signal:i,getInteractor:t.getInteractor,resolveAppReference:e=>t.resolveAppReference?.(r,e)??e,configurePortReverse:t.configurePortReverse}),o.operations),...qe({device:r,signal:i,getInteractor:t.getInteractor,presentIosAcquisition:t.host.snapshot.presentIosAcquisition}),...Oe({device:r,signal:i,resolveInteractor:e=>t.getInteractor(r,e),facts:o.operations}),...ft(Et(t),r,i,l),...gt({host:t.host,device:r,owner:n,signal:i,getDeviceSession:t.getDeviceSession})};return Object.freeze({device:r,owner:n,facts:o,operations:Object.freeze(a?{appLogReattach:u.appLogReattach,appLogCleanup:u.appLogCleanup}:d),[Symbol.asyncDispose]:async()=>await l[Symbol.asyncDispose]()})}async function Nt(e,t,n){n.throwIfAborted();let r=await e.openCurrent(t);if(!r)return!1;try{n.throwIfAborted()}finally{await r[Symbol.asyncDispose]()}return!0}function Q(e){return e.platform===`apple`?`ios-simulator`:`android`}function $(e,t){if(!i(t))return!1;let n=a(t.id);return n!==void 0&&n.leaseId===e.leaseId&&n.platform===e.platform&&(t.platform===`apple`?e.platform===`ios`:e.platform===`android`)}export{jt as createLimrunPlatformRuntimeOwner};
|
|
4
|
+
`)}async function nt(e){return(await Promise.allSettled(e.map(async e=>await e[Symbol.asyncDispose]()))).flatMap(e=>e.status===`rejected`?[e.reason]:[])}function rt(e){return e.platform===`ios`?`ios-simulator`:`android`}function it(e){let t=je({owner:`Limrun`,openTargetIdentity:`bundle-id`,closeBeforeRelaunch:!0,configureProviderPortReverse:async t=>await e.configurePortReverse(t),binding:Ae({device:e.device,signal:e.signal,resolveInteractor:t=>e.getInteractor(e.device,t)})}),n=e.resolveAppReference;return n?Object.freeze({...t,resolveOpenTarget:async e=>await t.resolveOpenTarget(at(e,n)),openApplication:async e=>await t.openApplication(ot(e,n)),closeApplication:async e=>await t.closeApplication(st(e,n))}):t}function at(e,t){return e.target===void 0?e:{...e,target:t(e.target)}}function ot(e,t){return{...e,target:z(e.target,t),positionals:R(e.positionals,t),appBundleId:z(e.appBundleId,t)}}function st(e,t){return{...e,positionals:R(e.positionals,t),appBundleId:z(e.appBundleId,t)}}function R(e,t){let n=e[0];return n===void 0?e:[t(n),...e.slice(1)]}function z(e,t){return e===void 0?void 0:t(e)}function ct(e){let t=a(e.id);return!t||e.target!==`mobile`?!1:t.platform===`ios`?e.platform===`apple`&&e.appleOs===`ios`&&e.kind===`simulator`&&e.iosPhysicalDeviceBackend===void 0:e.platform===`android`&&e.appleOs===void 0&&e.kind===`emulator`&&e.iosPhysicalDeviceBackend===void 0}const lt=Object.freeze({available:!0}),B=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`The Limrun provider session is no longer active for this device.`}),ut=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Push notifications are unavailable for Limrun provider-owned devices.`});function V(e,t){let n=ft(e,t);return Object.freeze({deployApp:n,materializeAppSource:n,deployMaterializedApp:n,sendPushNotification:H(e,t)?ut:B})}function dt(e,t,n,r){let i=e.deployApp,a=e.deployMaterializedApp;return!V(e,t).deployApp.available||!i||!a?Object.freeze({}):Object.freeze({deployApp:async e=>U(await i(t,e,n,r)),materializeAppSource:async r=>await pt(e.host,t,r,n),deployMaterializedApp:async e=>U(await a(t,e,n,r))})}function ft(e,t){return ct(t)&&H(e,t)&&e.deployApp&&e.deployMaterializedApp?lt:B}function H(e,t){return e.isSessionActive?.(t)??e.ownsDevice(t)}async function pt(e,t,n,r){return await(t.platform===`apple`?e.appleDeployment:e.androidDeployment).prepareArtifact(n,{signal:r})}function U(t){if(!t)throw new e(`UNSUPPORTED_OPERATION`,`The Limrun provider session is no longer active.`);return t}const mt=Object.freeze({medium:5,high:8});function ht(e){return Object.freeze({screenRecordingStart:async t=>await gt(e,t),screenRecordingReattach:async()=>Ne(`Limrun recordings cannot be reattached after daemon restart.`),screenRecordingCleanup:async()=>Me(`Limrun recordings cannot be cleaned after daemon restart; the instance disposes them when it terminates.`)})}async function gt(t,n){let r=t.getDeviceSession(t.device);if(!r)throw new e(`UNSUPPORTED_OPERATION`,`Limrun recording requires a live provider session for this device.`,{deviceId:t.device.id});return await Pe({host:t.host,device:t.device,owner:t.owner,input:n,signal:t.signal,transport:{backend:`limrun-recorder`,targetLabel:`Limrun recording`,start:async()=>{await r.startRecording({quality:mt[n.exportQuality??`medium`]})},stop:async()=>(await r.stopRecording()).downloadUrl,collect:async(e,t)=>{await r.downloadRecording({downloadUrl:e,outPath:t})}},support:{scopes:[`app`,`device`,`system`],fps:!1,exportQuality:!0,hideTouches:!1},unsupported:e=>`Limrun recordings do not support ${e.join(`, `)}`})}const W=Object.freeze({available:!0}),G=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Custom snapshot actions are available only for Limrun iOS simulator sessions.`}),_t=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun does not expose viewport resizing.`}),K=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun-owned devices read element text from the captured tree only.`}),vt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Headless boot is unavailable for provider-owned devices.`}),q=Object.freeze({available:!1,reason:`owner-capability-missing`,hint:`Limrun requires a matching live provider session for this device.`}),yt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Apple runner preparation is unavailable for Limrun-owned devices.`}),bt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun iOS appstate is session-owned; no sessionless provider foreground probe is exposed.`}),xt=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun open requires a Limrun-owned iOS simulator or Android emulator.`}),St=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun close requires a Limrun-owned iOS simulator or Android emulator.`}),J=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Runtime hints are not applied to provider-owned devices.`}),Ct=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun port reverse requires an active Android Limrun session.`}),Y=Object.freeze({available:!1,reason:`unsupported-provider-mode`,hint:`Limrun does not expose the audio probe.`});function wt(e){return{...e,isSessionActive:e.hasLiveSession}}function X(e,t){let n=Tt(e,t),r=Et(e,t),i=Dt(e,t);return l({resolveOpenTarget:n,prepareApplicationOpen:n,openApplication:n,applyRuntimeHints:J,clearRuntimeHints:J,closeApplication:r,finalizeApplicationClose:r,prepareAppleRunner:yt,configureProviderPortReverse:i})}function Tt(e,t){return i(e)?t?W:q:xt}function Et(e,t){return i(e)?t?W:q:St}function Dt(e,t){return t?e.platform===`android`?W:Ct:q}function Z(e,n){let r=V(wt(e),n),i=n.platform===`android`,a=t(n)&&n.kind===`simulator`?W:G;return Object.freeze({device:{family:n.platform,...n.appleOs===void 0?{}:{appleOs:n.appleOs},kind:n.kind,...n.target===void 0?{}:{target:n.target},...n.iosPhysicalDeviceBackend===void 0?{}:{iosPhysicalDeviceBackend:n.iosPhysicalDeviceBackend},providerMode:`provider-runtime`},operations:{appLogInspect:W,appLogDoctor:W,appLogStart:W,appLogReattach:W,appLogCleanup:W,...r,appState:i?W:bt,networkDump:W,screenRecordingStart:W,screenRecordingReattach:W,screenRecordingCleanup:W,...p({capture:W,customActions:a,withoutActiveApp:W}),...h({capture:W}),...g({findText:G}),...d({setViewport:_t}),...T(n),...ee({readTextAtPoint:K}),...E(n),...P(n),...D(),...k(n),...j(),...M(n),...N(n),...O(n),...me({capture:Y,query:Y}),...he({frames:K,memorySample:K,memorySnapshot:K,nativeCapture:K,profileReport:K}),ensureReady:W,bootTarget:W,bootTargetHeadless:vt,listApps:W,shutdownTarget:{available:!1,reason:`unsupported-provider-mode`,hint:`Limrun owns the target lifecycle for provider-owned devices.`},...X(n,!0)}})}function Ot(e,t){let n=Z(e,t);return Object.freeze({device:n.device,operations:{...n.operations,appLogInspect:q,appLogDoctor:q,appLogStart:q,appLogReattach:W,appLogCleanup:W,appState:q,networkDump:q,screenRecordingStart:q,screenRecordingReattach:q,screenRecordingCleanup:q,...p({capture:q,customActions:q,withoutActiveApp:q}),...h({capture:q}),...g({findText:q}),...d({setViewport:q}),...T(t,q),...E(t,q),...P(t,q),...D(q),...k(t,q),...j(),...M(t,q),...N(t,q),...O(t,q),ensureReady:q,bootTarget:q,bootTargetHeadless:q,listApps:q,deployApp:q,materializeAppSource:q,deployMaterializedApp:q,sendPushNotification:q,shutdownTarget:q,...X(t,!1)}})}function kt(t){let a=n(`limrun`,t.runtimeInstance),o=e=>i(e)&&t.ownsDevice(e),s=e=>o(e)&&t.hasLiveSession(e);return Object.freeze({owner:a,ownsDevice:o,inspectFacts:async e=>s(e)?Z(t,e):ve(e,a,{appLog:q,appState:q,appDeployment:q,network:q,screenshot:q,viewport:q,focus:q,gesture:q,scroll:q,typeText:q,touch:q,elementText:q,back:q,orientation:q,tvRemote:q,keyboard:q,clipboard:q,systemButton:q,fold:A,triggerAppEvent:q,settings:q,readAlert:q,awaitAlert:q,acceptAlert:q,dismissAlert:q,audioProbeCapture:q,audioProbeQuery:q,perf:q,readiness:q,shutdown:q,lifecycle:X(e,!1)}),bind:async n=>{if(n.intent.kind===`exact-owner`&&!r(n.intent.owner,a))throw new e(`UNSUPPORTED_OPERATION`,`Limrun app-log owner identity does not match`);if(!i(n.device))throw new e(`UNSUPPORTED_PLATFORM`,`Limrun app logs require an iOS simulator or Android emulator device identity`);let o=s(n.device);if(n.intent.kind!==`exact-owner`&&!o)throw new e(`UNSUPPORTED_OPERATION`,`Limrun provider session is no longer live for the selected device`,{reason:`provider-session-unavailable`});return At(t,a,n.device,n.scope.signal,!o)},shutdown:async()=>void 0})}function At(t,n,r,i,a){let o=a?Ot(t,r):Z(t,r),l=s(),u=Se({codec:F,reattach:async(e,n)=>{if(!$(e,r)||!b(t.host,n.sessionId,e))return{status:`unreattachable`,reason:`descriptor-invalid`,message:`Limrun app-log descriptor does not match the bound device or owning session`};let a=await t.reconnect(e,i);return a.status===`missing`?{status:`missing`}:a.status===`ownership-lost`?{status:`unreattachable`,reason:`ownership-fence-lost`}:{status:`active`,handle:await L({host:t.host,reader:a.reader,appBundleId:e.appBundleId,outputPath:e.outputPath})}},cleanup:async(e,n)=>$(e,r)&&b(t.host,n.sessionId,e)?{status:`cleaned`}:{status:`cleanup-pending`,reason:`ownership-fence-lost`,message:`Limrun app-log descriptor does not match the bound device or owning session`}}),d={appLogInspect:async()=>({backend:Q(r)}),appLogDoctor:async()=>({backend:Q(r),checks:{limrunSessionAvailable:await jt(t,r,i)},notes:[]}),appLogStart:async a=>{Te(t.host,a),i.throwIfAborted();let o=await t.openCurrent(r);if(!o)throw new e(`UNSUPPORTED_OPERATION`,`Limrun app logs require an active instance`);let s={transport:`limrun-log-poller`,platform:o.platform,leaseId:o.leaseId,instanceId:o.instanceId,ownership:o.ownership,appBundleId:a.appBundleId,outputPath:a.outputPath},c=!1;try{i.throwIfAborted();let e=Je({sessionId:a.sessionId,device:r,owner:n,fence:a.fence,descriptor:s});c=!0;let l=await L({host:t.host,reader:o,appBundleId:a.appBundleId,outputPath:a.outputPath});return Ce(l,e)}catch(e){throw c||await o[Symbol.asyncDispose](),e}},...u,networkDump:async e=>{let n=await t.host.appLogs.readRecent(e.sessionId,e.maxScanLines),i=Q(r),{dump:a}=we(n.text,{...e,path:n.path,exists:n.exists,lineNumberOffset:n.skippedLines,backend:i}),o=a.entries.length===0?[`No HTTP(s) entries were found in recent session app logs.`]:[];return Object.freeze({source:`app-log`,backend:i,dump:a,notes:o})},ensureReady:async()=>({...r,booted:!0}),bootTarget:async()=>({...r,booted:!0}),listApps:async e=>await t.listApps(e.device,e.filter,i),...r.platform===`android`?{appState:async()=>await t.getAppState(r,i)}:{},...c(it({device:r,signal:i,getInteractor:t.getInteractor,resolveAppReference:e=>t.resolveAppReference?.(r,e)??e,configurePortReverse:t.configurePortReverse}),o.operations),...Ke({device:r,signal:i,getInteractor:t.getInteractor,presentIosAcquisition:t.host.snapshot.presentIosAcquisition}),...ke({device:r,signal:i,resolveInteractor:e=>t.getInteractor(r,e),facts:o.operations}),...dt(wt(t),r,i,l),...ht({host:t.host,device:r,owner:n,signal:i,getDeviceSession:t.getDeviceSession})};return Object.freeze({device:r,owner:n,facts:o,operations:Object.freeze(a?{appLogReattach:u.appLogReattach,appLogCleanup:u.appLogCleanup}:d),[Symbol.asyncDispose]:async()=>await l[Symbol.asyncDispose]()})}async function jt(e,t,n){n.throwIfAborted();let r=await e.openCurrent(t);if(!r)return!1;try{n.throwIfAborted()}finally{await r[Symbol.asyncDispose]()}return!0}function Q(e){return e.platform===`apple`?`ios-simulator`:`android`}function $(e,t){if(!i(t))return!1;let n=a(t.id);return n!==void 0&&n.leaseId===e.leaseId&&n.platform===e.platform&&(t.platform===`apple`?e.platform===`ios`:e.platform===`android`)}export{kt as createLimrunPlatformRuntimeOwner};
|
package/dist/src/back-mode.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as e,t}from"./sdk-contracts.js";import{o as n}from"./capture.js";import{i as r}from"./sdk-device.js";import{t as i}from"./recording-scope.js";import{c as a}from"./sdk-remote-config.js";import{t as o}from"./session.js";import{c as s}from"./observability.js";const c=[{key:`keyframes`,names:[`--keyframes`],type:`string`,usageLabel:`--keyframes <json>`,usageDescription:`Fold: timed {atMs, angle} keyframes; final atMs is motion duration (up to 60000ms)`,projectConfig:!1,recorded:!0},{key:`count`,names:[`--count`],type:`int`,min:1,max:200,usageLabel:`--count <n>`,usageDescription:`Repeat count for press/swipe series`,projectConfig:!0,recorded:!0},{key:`pointerCount`,names:[`--pointer-count`],type:`int`,min:1,max:2,usageLabel:`--pointer-count <1|2>`,usageDescription:`Gesture pan: number of touch pointers (default 1)`,projectConfig:!0,recorded:!0},{key:`fps`,names:[`--fps`],type:`int`,min:1,max:120,usageLabel:`--fps <n>`,usageDescription:`Record: target frames per second (iOS physical device runner); also lowers the touch-overlay rate, which never exceeds 30`,projectConfig:!0,recorded:!0},{key:`quality`,names:[`--quality`],type:`string`,usageLabel:`--quality <medium|high>`,usageDescription:`Record: output quality preset; Android maps this to screenrecord bitrate, Limrun sessions map medium to recorder quality 5 and high to 8; Apple export always preserves the captured resolution, so it has no effect there. Legacy numeric values 5-7 map to medium; 8-10 map to high`,projectConfig:!0,recorded:!0},{key:`hideTouches`,names:[`--hide-touches`],type:`boolean`,usageLabel:`--hide-touches`,usageDescription:`Record: skip touch-overlay post-processing for faster raw benchmark videos`,projectConfig:!0,recorded:!0},{key:`recordingScope`,names:[`--scope`],type:`enum`,enumValues:i,usageLabel:`--scope <app|device|system>`,usageDescription:`Record: app requires an active app session; device/system records the whole screen`,projectConfig:!0,recorded:!1},{key:`intervalMs`,names:[`--interval-ms`],type:`int`,min:0,max:1e4,usageLabel:`--interval-ms <ms>`,usageDescription:`Delay between press iterations`,projectConfig:!0,recorded:!0},{key:`delayMs`,names:[`--delay-ms`],type:`int`,min:0,max:1e4,usageLabel:`--delay-ms <ms>`,usageDescription:`Delay between typed characters`,projectConfig:!0,recorded:!0},{key:`recordAs`,names:[`--record-as`],type:`string`,usageLabel:`--record-as <VAR>`,usageDescription:"Fill: send the live text but publish ${VAR} in an armed .ad recording",projectConfig:!0,recorded:!1},{key:`durationMs`,names:[`--duration-ms`],type:`int`,min:0,max:1e4,usageLabel:`--duration-ms <ms>`,usageDescription:`Scroll: pace the gesture over this duration when supported`,projectConfig:!0,recorded:!1},{key:`holdMs`,names:[`--hold-ms`],type:`int`,min:0,max:1e4,usageLabel:`--hold-ms <ms>`,usageDescription:`Press hold duration for each iteration`,projectConfig:!0,recorded:!0},{key:`jitterPx`,names:[`--jitter-px`],type:`int`,min:0,max:100,usageLabel:`--jitter-px <n>`,usageDescription:`Deterministic coordinate jitter radius for press`,projectConfig:!0,recorded:!0},{key:`pixels`,names:[`--pixels`],type:`int`,min:1,max:1e5,usageLabel:`--pixels <n>`,usageDescription:`Scroll: explicit gesture distance in pixels`,projectConfig:!0,recorded:!1},{key:`until`,names:[`--until`],type:`string`,usageLabel:`--until <selector>`,usageDescription:`Scroll: repeat passes until the selector is visible on screen`,projectConfig:!0,recorded:!0},{key:`doubleTap`,names:[`--double-tap`],type:`boolean`,usageLabel:`--double-tap`,usageDescription:`Use double-tap gesture per press iteration`,projectConfig:!0,recorded:!0},{key:`verify`,names:[`--verify`],type:`boolean`,usageLabel:`--verify`,usageDescription:`Capture cheap post-action evidence (AX digest, node counts, changedFromBefore) instead of a follow-up snapshot`,projectConfig:!0,recorded:!1},{key:`settle`,names:[`--settle`],type:`boolean`,usageLabel:`--settle`,usageDescription:`After the action, wait for the UI to go quiet and return the settled diff vs the pre-action tree in the same response (best-effort; never fails the action)`,projectConfig:!0,recorded:!1},{key:`settleQuietMs`,names:[`--settle-quiet`],type:`int`,min:0,usageLabel:`--settle-quiet <ms>`,usageDescription:`Settle: quiet window the UI must hold to count as settled (default 500ms)`,projectConfig:!0,recorded:!1},{key:`clickButton`,names:[`--button`],type:`enum`,enumValues:[`primary`,`secondary`,`middle`],usageLabel:`--button primary|secondary|middle`,usageDescription:`Click: choose mouse button (middle reserved for future macOS support)`,projectConfig:!0,recorded:!0},{key:`backMode`,names:[`--in-app`],type:`enum`,enumValues:[`in-app`,`system`],setValue:`in-app`,usageLabel:`--in-app`,usageDescription:`Back: use app-provided back UI when available`,projectConfig:!0,recorded:!1},{key:`backMode`,names:[`--system`],type:`enum`,enumValues:[`in-app`,`system`],setValue:`system`,usageLabel:`--system`,usageDescription:`Back: use system back input or gesture when available`,projectConfig:!0,recorded:!1},{key:`pauseMs`,names:[`--pause-ms`],type:`int`,min:0,max:1e4,usageLabel:`--pause-ms <ms>`,usageDescription:`Delay between swipe iterations`,projectConfig:!0,recorded:!0},{key:`pattern`,names:[`--pattern`],type:`enum`,enumValues:[`one-way`,`ping-pong`],usageLabel:`--pattern one-way|ping-pong`,usageDescription:`Swipe repeat pattern`,projectConfig:!0,recorded:!0},{key:`verbose`,names:[`--debug`,`--verbose`,`-v`],type:`boolean`,usageLabel:`--debug, --verbose, -v`,usageDescription:`Enable debug diagnostics; test --verbose prints per-test step timings without debug logs`,projectConfig:!0,recorded:!0},{key:`cost`,names:[`--cost`],type:`boolean`,usageLabel:`--cost`,usageDescription:`Include per-command wall-clock latency (cost.wallClockMs) in the response`,projectConfig:!0,recorded:!1},{key:`responseLevel`,names:[`--level`],type:`enum`,enumValues:e,usageLabel:`--level digest|default|full`,usageDescription:`Response detail level: digest (token-cheap), default (today), or full. Default keeps the wire shape unchanged.`,projectConfig:!0,recorded:!1},{key:`json`,names:[`--json`],type:`boolean`,usageLabel:`--json`,usageDescription:`JSON output`,projectConfig:!0,recorded:!1},{key:`help`,names:[`--help`,`-h`],type:`boolean`,usageLabel:`--help, -h`,usageDescription:`Print help and exit`,projectConfig:!1,recorded:!1},{key:`version`,names:[`--version`,`-V`],type:`boolean`,usageLabel:`--version, -V`,usageDescription:`Print version and exit`,projectConfig:!1,recorded:!1},{key:`snapshotDiff`,names:[`--diff`],type:`boolean`,usageLabel:`--diff`,usageDescription:`Snapshot: show structural diff against the previous session baseline`,projectConfig:!0,recorded:!1},{key:`saveScript`,names:[`--save-script`],type:`booleanOrString`,usageLabel:`--save-script [path]`,usageDescription:`Arm evidence capture on open, publish the armed recording on close; close --save-script alone (without an armed open) is rejected — start with open --save-script, or use session save-script mid-session. Optional custom output path.`,projectConfig:!1,recorded:!0},{key:`networkInclude`,names:[`--include`],type:`enum`,enumValues:[`summary`,`headers`,`body`,`all`],usageLabel:`--include summary|headers|body|all`,usageDescription:`Network: include headers, bodies, or both in output`,projectConfig:!0,recorded:!1},{key:`shutdown`,names:[`--shutdown`],type:`boolean`,usageLabel:`--shutdown`,usageDescription:`close: shutdown associated simulator/emulator after ending session`,projectConfig:!0,recorded:!1},{key:`relaunch`,names:[`--relaunch`],type:`boolean`,usageLabel:`--relaunch`,usageDescription:`open: terminate app process before launching it`,projectConfig:!0,recorded:!0},{key:`foreground`,names:[`--foreground`],type:`boolean`,usageLabel:`--foreground`,usageDescription:`open: keep normal app/device selection and return an initial snapshot; without an app, resolve the sole running app on the sole booted iOS simulator`,inputDescription:`Include an initial interactive snapshot in a fresh open response. With no app argument, discover the sole running app on the sole booted iOS simulator; ambiguous environments fail closed.`,projectConfig:!1,recorded:!1},{key:`restart`,names:[`--restart`],type:`boolean`,usageLabel:`--restart`,usageDescription:`logs clear: stop active stream, clear logs, then start streaming again`,projectConfig:!0,recorded:!1},{key:`retainPaths`,names:[`--retain-paths`],type:`boolean`,usageLabel:`--retain-paths`,usageDescription:`install-from-source: keep materialized artifact paths after install`,projectConfig:!0,recorded:!1},{key:`retentionMs`,names:[`--retention-ms`],type:`int`,min:1,usageLabel:`--retention-ms <ms>`,usageDescription:`install-from-source: retention TTL for materialized artifact paths`,projectConfig:!0,recorded:!1},{key:`noRecord`,names:[`--no-record`],type:`boolean`,usageLabel:`--no-record`,usageDescription:`Do not record this action`,projectConfig:!0,recorded:!0},{key:`record`,names:[`--record`],type:`boolean`,usageLabel:`--record`,usageHidden:!0,usageDescription:`Force-record this action even though its command is observation-only and would otherwise be excluded from a repair-armed heal by default (mutually exclusive with --no-record)`,projectConfig:!0,recorded:!0}],l=[{key:`config`,names:[`--config`],type:`string`,usageLabel:`--config <path>`,usageDescription:`Load CLI defaults from a specific config file (required for connection/provider defaults outside user config)`,projectConfig:!1,recorded:!1},{key:`remoteConfig`,names:[`--remote-config`],type:`string`,usageLabel:`--remote-config <path>`,usageDescription:`Load remote host + Metro workflow settings from a specific profile file`,projectConfig:!1,recorded:!1},{key:`stateDir`,names:[`--state-dir`],type:`string`,usageLabel:`--state-dir <path>`,usageDescription:`Daemon state directory (defaults to ~/.agent-device for packages, or a worktree-scoped dev dir from source)`,projectConfig:!1,recorded:!1},{key:`daemonBaseUrl`,names:[`--daemon-base-url`],type:`string`,usageLabel:`--daemon-base-url <url>`,usageDescription:`Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)`,projectConfig:!1,recorded:!1},{key:`daemonAuthToken`,names:[`--daemon-auth-token`],type:`string`,usageLabel:`--daemon-auth-token <token>`,usageDescription:`Remote HTTP daemon or proxy auth token (sent as request token and bearer header)`,projectConfig:!1,recorded:!1},{key:`daemonTransport`,names:[`--daemon-transport`],type:`enum`,enumValues:[`auto`,`socket`,`http`],usageLabel:`--daemon-transport auto|socket|http`,usageDescription:`Daemon client transport preference`,projectConfig:!1,recorded:!1},{key:`daemonServerMode`,names:[`--daemon-server-mode`],type:`enum`,enumValues:[`socket`,`http`,`dual`],usageLabel:`--daemon-server-mode socket|http|dual`,usageDescription:`Daemon server mode used when spawning daemon`,projectConfig:!1,recorded:!1},{key:`proxyHost`,names:[`--host`],type:`string`,usageLabel:`--host <host>`,usageDescription:`Proxy: host interface to bind (default: 127.0.0.1)`,projectConfig:!1,recorded:!1},{key:`proxyPort`,names:[`--port`],type:`int`,min:1,max:65535,usageLabel:`--port <port>`,usageDescription:`Proxy: TCP port to bind (default: 0, choose a free port)`,projectConfig:!1,recorded:!1},{key:`tenant`,names:[`--tenant`],type:`string`,usageLabel:`--tenant <id>`,usageDescription:`Tenant scope identifier for isolated daemon sessions`,projectConfig:!1,recorded:!1},{key:`sessionIsolation`,names:[`--session-isolation`],type:`enum`,enumValues:[`none`,`tenant`],usageLabel:`--session-isolation none|tenant`,usageDescription:`Session isolation strategy (tenant prefixes session namespace)`,projectConfig:!1,recorded:!1},{key:`runId`,names:[`--run-id`],type:`string`,usageLabel:`--run-id <id>`,usageDescription:`Run identifier used for tenant lease admission checks`,projectConfig:!1,recorded:!1},{key:`leaseId`,names:[`--lease-id`],type:`string`,usageLabel:`--lease-id <id>`,usageDescription:`Lease identifier bound to tenant/run admission scope`,projectConfig:!1,recorded:!1},{key:`leaseBackend`,names:[`--lease-backend`],type:`enum`,enumValues:t,usageLabel:`--lease-backend ${t.join(`|`)}`,usageDescription:`Lease backend for remote tenant connection admission`,projectConfig:!1,recorded:!1},{key:`provider`,names:[`--provider`],type:`string`,usageLabel:`--provider <name>`,usageDescription:`Cloud provider name for provider-scoped commands`,projectConfig:!1,recorded:!1},{key:`providerSessionId`,names:[`--provider-session`],type:`string`,usageLabel:`--provider-session <id>`,usageDescription:`Cloud provider session id or ARN`,projectConfig:!1,recorded:!1},{key:`providerApp`,names:[`--provider-app`],type:`string`,usageLabel:`--provider-app <ref-or-path>`,usageDescription:`Cloud provider app reference or local app path used when creating hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`providerOsVersion`,names:[`--provider-os-version`,`--os-version`],type:`string`,usageLabel:`--provider-os-version <version>`,usageDescription:`Hosted cloud provider OS version, for example 17 or 14.0`,projectConfig:!1,recorded:!1},{key:`providerProject`,names:[`--provider-project`],type:`string`,usageLabel:`--provider-project <name>`,usageDescription:`Hosted cloud provider project label`,projectConfig:!1,recorded:!1},{key:`providerBuild`,names:[`--provider-build`],type:`string`,usageLabel:`--provider-build <name>`,usageDescription:`Hosted cloud provider build label`,projectConfig:!1,recorded:!1},{key:`providerSessionName`,names:[`--provider-session-name`],type:`string`,usageLabel:`--provider-session-name <name>`,usageDescription:`Hosted cloud provider session label`,projectConfig:!1,recorded:!1},{key:`providerDeviceOrientation`,names:[`--provider-device-orientation`,`--device-orientation`],type:`enum`,enumValues:a,usageLabel:`--provider-device-orientation portrait|landscape`,usageDescription:`Screen orientation a hosted cloud provider session starts in. Set this rather than rotating after launch: a session that boots landscape renders login webviews landscape`,projectConfig:!1,recorded:!1},{key:`providerGeoLocation`,names:[`--provider-geo-location`,`--geo-location`],type:`string`,usageLabel:`--provider-geo-location <country>`,usageDescription:`Hosted cloud provider IP geolocation country code, for example US`,projectConfig:!1,recorded:!1},{key:`providerTimezone`,names:[`--provider-timezone`,`--timezone`],type:`string`,usageLabel:`--provider-timezone <zone>`,usageDescription:`Hosted cloud provider device time zone, for example New_York`,projectConfig:!1,recorded:!1},{key:`providerAppiumVersion`,names:[`--provider-appium-version`,`--appium-version`],type:`string`,usageLabel:`--provider-appium-version <version>`,usageDescription:`Hosted cloud provider Appium server version, for example 3.2.0. Without it BrowserStack falls back to its default (Appium 1.x)`,projectConfig:!1,recorded:!1},{key:`providerLanguage`,names:[`--provider-language`,`--language`],type:`string`,usageLabel:`--provider-language <language>`,usageDescription:`Hosted cloud provider app language, for example Fr`,projectConfig:!1,recorded:!1},{key:`providerLocale`,names:[`--provider-locale`,`--locale`],type:`string`,usageLabel:`--provider-locale <locale>`,usageDescription:`Hosted cloud provider device locale, for example Fr`,projectConfig:!1,recorded:!1},{key:`providerNetworkProfile`,names:[`--provider-network-profile`,`--network-profile`],type:`string`,usageLabel:`--provider-network-profile <profile>`,usageDescription:`Hosted cloud provider named network condition profile, for example 4g-lte-advanced-good. Mutually exclusive with --provider-custom-network`,projectConfig:!1,recorded:!1},{key:`providerCustomNetwork`,names:[`--provider-custom-network`,`--custom-network`],type:`string`,usageLabel:`--provider-custom-network <shape>`,usageDescription:`Hosted cloud provider custom network shape. Mutually exclusive with --provider-network-profile`,projectConfig:!1,recorded:!1},{key:`providerNoResignApp`,names:[`--provider-no-resign-app`],type:`boolean`,usageLabel:`--provider-no-resign-app`,usageDescription:`iOS only: keep an Enterprise-signed app as uploaded instead of letting the provider re-sign it, which strips entitlements such as push notifications`,projectConfig:!1,recorded:!1},{key:`awsProjectArn`,names:[`--aws-project-arn`],type:`string`,usageLabel:`--aws-project-arn <arn>`,usageDescription:`AWS Device Farm project ARN for hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`awsDeviceArn`,names:[`--aws-device-arn`],type:`string`,usageLabel:`--aws-device-arn <arn>`,usageDescription:`AWS Device Farm device ARN for hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`awsAppArn`,names:[`--aws-app-arn`],type:`string`,usageLabel:`--aws-app-arn <arn>`,usageDescription:`AWS Device Farm app ARN attached to hosted remote access sessions`,projectConfig:!1,recorded:!1},{key:`awsRegion`,names:[`--aws-region`],type:`string`,usageLabel:`--aws-region <region>`,usageDescription:`AWS region for Device Farm API calls`,projectConfig:!1,recorded:!1},{key:`awsInteractionMode`,names:[`--aws-interaction-mode`],type:`enum`,enumValues:[`INTERACTIVE`,`NO_VIDEO`,`VIDEO_ONLY`],usageLabel:`--aws-interaction-mode INTERACTIVE|NO_VIDEO|VIDEO_ONLY`,usageDescription:`AWS Device Farm remote access interaction mode`,projectConfig:!1,recorded:!1},{key:`force`,names:[`--force`,`--overwrite`],type:`boolean`,usageLabel:`--force, --overwrite`,usageDescription:`Force replacement of existing state (connect: replace an active connection; --save-script: overwrite an existing target instead of refusing)`,projectConfig:!0,recorded:!0},{key:`clean`,names:[`--clean`],type:`boolean`,usageLabel:`--clean`,usageDescription:`Daemon stop: remove retained runner processes and leases after stopping`,projectConfig:!0,recorded:!1},{key:`noLogin`,names:[`--no-login`],type:`boolean`,usageLabel:`--no-login`,usageDescription:`Connect: fail instead of starting implicit cloud login`,projectConfig:!0,recorded:!1},{key:`sessionLock`,names:[`--session-lock`],type:`enum`,enumValues:[`reject`,`strip`],usageLabel:`--session-lock reject|strip`,usageDescription:`Lock bound-session device routing for this CLI invocation and nested batch steps; strip drops conflicting platform/scope selectors only, and a selector naming a different device always fails`,projectConfig:!0,recorded:!1}],u=[{key:`platform`,names:[`--platform`],type:`enum`,enumValues:r,usageLabel:`--platform ${r.join(`|`)}`,usageDescription:"Platform to target (`apple` aliases the Apple automation backend)",projectConfig:!0,recorded:!0},{key:`target`,names:[`--target`],type:`enum`,enumValues:[`mobile`,`tv`,`desktop`],usageLabel:`--target mobile|tv|desktop`,usageDescription:`Device target class to match`,projectConfig:!0,recorded:!1},{key:`device`,names:[`--device`],type:`string`,usageLabel:`--device <name>`,usageDescription:`Device name to target (a UDID belongs in --udid, a serial in --serial)`,projectConfig:!0,recorded:!0},{key:`udid`,names:[`--udid`],type:`string`,usageLabel:`--udid <udid>`,usageDescription:`Apple device or simulator UDID; the only selector that pins one device when several share a --device name`,projectConfig:!0,recorded:!0},{key:`serial`,names:[`--serial`],type:`string`,usageLabel:`--serial <serial>`,usageDescription:`Android, HarmonyOS, or Vega VVD serial`,projectConfig:!0,recorded:!0},{key:`stale`,names:[`--stale`],type:`boolean`,usageLabel:`--stale`,usageDescription:`Device status: show only claims with a provably stale owner`,projectConfig:!0,recorded:!1},{key:`surface`,names:[`--surface`],type:`enum`,enumValues:o,usageLabel:`--surface app|frontmost-app|desktop|menubar`,usageDescription:`macOS session surface for open (defaults to app)`,projectConfig:!0,recorded:!1},{key:`headless`,names:[`--headless`],type:`boolean`,usageLabel:`--headless`,usageDescription:`Boot: launch Android emulator without a GUI window`,projectConfig:!0,recorded:!1},{key:`targetApp`,names:[`--app`,`--target-app`],type:`string`,usageLabel:`--app <id-or-name>`,usageDescription:`Target an app without opening it: doctor verifies an installed app by id or name; settings applies an app-scoped change (permission, iOS location) to a bundle id or package`,projectConfig:!1,recorded:!1},{key:`metroHost`,names:[`--metro-host`],type:`string`,usageLabel:`--metro-host <host>`,usageDescription:`Session-scoped Metro/debug host hint`,projectConfig:!1,recorded:!0},{key:`metroPort`,names:[`--metro-port`],type:`int`,min:1,max:65535,usageLabel:`--metro-port <port>`,usageDescription:`Session-scoped Metro/debug port hint; on an emulator/simulator the host defaults to the loopback alias, physical devices still need --metro-host`,projectConfig:!1,recorded:!0},{key:`metroProjectRoot`,names:[`--project-root`],type:`string`,usageLabel:`--project-root <path>`,usageDescription:`metro prepare: React Native project root (default: cwd)`,projectConfig:!1,recorded:!1},{key:`kind`,names:[`--kind`],type:`enum`,enumValues:[`auto`,`react-native`,`expo`,`repack`,...s],usageLabel:`--kind <kind>`,usageDescription:`Kind selector for commands that support it, such as metro prepare or perf artifact collectors`,projectConfig:!0,recorded:!1},{key:`perfTemplate`,names:[`--template`],type:`string`,usageLabel:`--template <name>`,usageDescription:`Perf xctrace template name, for example Time Profiler`,projectConfig:!0,recorded:!1},{key:`metroKind`,names:[`--metro-kind`],type:`enum`,enumValues:[`auto`,`react-native`,`expo`,`repack`],usageLabel:`--metro-kind auto|react-native|expo|repack`,usageDescription:`metro prepare: detect or force the React Native dev-server launcher kind`,projectConfig:!1,recorded:!1},{key:`metroPublicBaseUrl`,names:[`--public-base-url`],type:`string`,usageLabel:`--public-base-url <url>`,usageDescription:`metro prepare: public base URL used for direct dev-server bundle hints`,projectConfig:!1,recorded:!1},{key:`metroProxyBaseUrl`,names:[`--proxy-base-url`],type:`string`,usageLabel:`--proxy-base-url <url>`,usageDescription:`metro prepare: optional bridge origin for remote dev-server access`,projectConfig:!1,recorded:!1},{key:`metroBearerToken`,names:[`--bearer-token`],type:`string`,usageLabel:`--bearer-token <token>`,usageDescription:`metro prepare: host bridge bearer token (or AGENT_DEVICE_METRO_BEARER_TOKEN; falls back to AGENT_DEVICE_DAEMON_AUTH_TOKEN)`,projectConfig:!1,recorded:!1},{key:`metroPreparePort`,names:[`--port`],type:`int`,min:1,max:65535,usageLabel:`--port <port>`,usageDescription:`metro prepare: local dev-server port (default: 8081)`,projectConfig:!1,recorded:!1},{key:`metroListenHost`,names:[`--listen-host`],type:`string`,usageLabel:`--listen-host <host>`,usageDescription:`metro prepare: host dev server listens on (default: 0.0.0.0)`,projectConfig:!1,recorded:!1},{key:`metroStatusHost`,names:[`--status-host`],type:`string`,usageLabel:`--status-host <host>`,usageDescription:`metro prepare: host used for local dev-server /status polling (default: 127.0.0.1)`,projectConfig:!1,recorded:!1},{key:`metroStartupTimeoutMs`,names:[`--startup-timeout-ms`],type:`int`,min:1,usageLabel:`--startup-timeout-ms <ms>`,usageDescription:`metro prepare: timeout while waiting for the dev server to become ready`,projectConfig:!1,recorded:!1},{key:`metroProbeTimeoutMs`,names:[`--probe-timeout-ms`],type:`int`,min:1,usageLabel:`--probe-timeout-ms <ms>`,usageDescription:`metro prepare: timeout for /status and proxy bridge calls`,projectConfig:!1,recorded:!1},{key:`metroRuntimeFile`,names:[`--runtime-file`],type:`string`,usageLabel:`--runtime-file <path>`,usageDescription:`metro prepare: optional file path to persist the JSON result`,projectConfig:!1,recorded:!1},{key:`metroNoReuseExisting`,names:[`--no-reuse-existing`],type:`boolean`,usageLabel:`--no-reuse-existing`,usageDescription:`metro prepare: always start a fresh Metro process`,projectConfig:!1,recorded:!1},{key:`metroNoInstallDeps`,names:[`--no-install-deps`],type:`boolean`,usageLabel:`--no-install-deps`,usageDescription:`metro prepare: skip package-manager install when node_modules is missing`,projectConfig:!1,recorded:!1},{key:`bundleUrl`,names:[`--bundle-url`],type:`string`,usageLabel:`--bundle-url <url>`,usageDescription:`Session-scoped bundle URL hint`,projectConfig:!1,recorded:!0},{key:`launchUrl`,names:[`--launch-url`],type:`string`,usageLabel:`--launch-url <url>`,usageDescription:`Session-scoped deep link / launch URL hint`,projectConfig:!0,recorded:!0},{key:`iosSimulatorDeviceSet`,names:[`--ios-simulator-device-set`],type:`string`,usageLabel:`--ios-simulator-device-set <path>`,usageDescription:`Scope iOS simulator discovery/commands to this simulator device set`,projectConfig:!1,recorded:!1},{key:`iosXctestrunFile`,names:[`--ios-xctestrun-file`],type:`string`,usageLabel:`--ios-xctestrun-file <path>`,usageDescription:`Use an externally built iOS XCTest runner .xctestrun artifact`,projectConfig:!1,recorded:!1},{key:`iosXctestDerivedDataPath`,names:[`--ios-xctest-derived-data-path`],type:`string`,usageLabel:`--ios-xctest-derived-data-path <path>`,usageDescription:`Derived data path for external iOS XCTest runner execution`,projectConfig:!1,recorded:!1},{key:`iosXctestEnvDir`,names:[`--ios-xctest-env-dir`],type:`string`,usageLabel:`--ios-xctest-env-dir <path>`,usageDescription:`Writable directory for per-session iOS XCTest runner env overlays`,projectConfig:!1,recorded:!1},{key:`testIme`,names:[`--test-ime`],type:`boolean`,usageLabel:`--test-ime`,usageDescription:`open/test/replay: activate the headless Android test IME for deterministic Unicode text entry (default on for emulators; opt-in on real devices; on test/replay it applies to the sessions the flow opens)`,projectConfig:!0,recorded:!1},{key:`testIme`,names:[`--no-test-ime`],type:`boolean`,setValue:!1,usageLabel:`--no-test-ime`,usageDescription:`open/test/replay: keep the real Android keyboard even on emulators (opt out of the headless test IME; on test/replay it applies to the sessions the flow opens)`,projectConfig:!0,recorded:!1},{key:`androidDeviceAllowlist`,names:[`--android-device-allowlist`],type:`string`,usageLabel:`--android-device-allowlist <serials>`,usageDescription:`Comma/space separated Android serial allowlist for discovery/selection`,projectConfig:!1,recorded:!1},{key:`remote`,names:[`--remote`],type:`boolean`,usageLabel:`--remote`,usageDescription:`Doctor: check remote connection setup instead of local device inventory`,projectConfig:!0,recorded:!1},{key:`activity`,names:[`--activity`],type:`string`,usageLabel:`--activity <component>`,usageDescription:`Android app launch activity (package/Activity); not for URL opens`,projectConfig:!0,recorded:!1},{key:`launchConsole`,names:[`--launch-console`],type:`string`,usageLabel:`--launch-console <path>`,usageDescription:`open: capture the initial iOS simulator launch console window to a file`,projectConfig:!1,recorded:!1},{key:`launchArgs`,names:[`--launch-args`],type:`string`,multiple:!0,usageLabel:`--launch-args <arg>`,usageDescription:`open: repeatable launch argument forwarded verbatim to the platform launch command (iOS app process args; Android adb shell am start args). Linux and macOS reject the flag.`,projectConfig:!0,recorded:!1},{key:`header`,names:[`--header`],type:`string`,multiple:!0,usageLabel:`--header <name:value>`,usageDescription:`install-from-source: repeatable HTTP header for URL downloads`,projectConfig:!1,recorded:!1},{key:`githubActionsArtifact`,names:[`--github-actions-artifact`],type:`string`,usageLabel:`--github-actions-artifact <owner/repo:artifact>`,usageDescription:`install-from-source: GitHub Actions artifact resolved by a remote daemon`,projectConfig:!1,recorded:!1},{key:`installSource`,names:[],type:`string`,projectConfig:!1,recorded:!1},{key:`session`,names:[`--session`],type:`string`,usageLabel:`--session <name>`,usageDescription:`Named session (implicit default is scoped to this workspace + platform)`,projectConfig:!0,recorded:!1}],d=[{key:`replayUpdate`,names:[`--update`,`-u`],type:`boolean`,usageLabel:`--update, -u`,usageDescription:`Replay: retired as a rewrite (ADR 0012) — never edits the .ad file; every divergence already carries ranked selector suggestions, --update or not`,projectConfig:!0,recorded:!1},{key:`replayFrom`,names:[`--from`],type:`int`,min:1,usageLabel:`--from <n>`,usageDescription:`Replay: resume at 1-based plan step n, skipping 1..n-1 without executing them (requires --plan-digest; see a divergence report's resume field). replay only, not test`,projectConfig:!0,recorded:!1},{key:`replayPlanDigest`,names:[`--plan-digest`],type:`string`,usageLabel:`--plan-digest <sha256>`,usageDescription:`Replay: the plan digest a --from resume must match (from a prior divergence report); mismatch, edits, or include/platform-expansion changes fail INVALID_ARGS before any action`,projectConfig:!0,recorded:!1},{key:`replayKeepSession`,names:[`--keep-session`],type:`boolean`,usageLabel:`--keep-session`,usageDescription:`Replay: leave the session active by suppressing exactly an authored terminal close in a native .ad script; replay only, not test or Maestro YAML`,projectConfig:!0,recorded:!1},{key:`replayMaestro`,names:[`--maestro`],type:`boolean`,usageLabel:`--maestro`,usageDescription:`Replay: treat input as a supported Maestro YAML subset; unsupported syntax fails loudly. See agent-device help maestro for commands and boundaries`,projectConfig:!0,recorded:!1},{key:`replayEnv`,names:[`-e`,`--env`],type:`string`,multiple:!0,usageLabel:`-e KEY=VALUE, --env KEY=VALUE`,usageDescription:"Replay/Test: inject or override a ${KEY} variable for the script (repeatable)",projectConfig:!1,recorded:!1},{key:`failFast`,names:[`--fail-fast`],type:`boolean`,usageLabel:`--fail-fast`,usageDescription:`Test: stop the suite after the first failing script; with sharding, each shard stops independently`,projectConfig:!0,recorded:!1},{key:`timeoutMs`,names:[`--timeout`],type:`int`,min:1,usageLabel:`--timeout <ms>`,usageDescription:`Boot/Open/Prepare: startup budget covering the device boot (and runner preparation for prepare). Replay/Snapshot/Test: maximum wall-clock time for the command or attempt. With --settle: the settle-wait deadline (default 10s)`,projectConfig:!0,recorded:!1},{key:`waitMs`,names:[`--wait`],type:`int`,min:100,max:12e4,usageLabel:`--wait <ms>`,usageDescription:`Open: wait up to n ms for a device another session is holding before failing with DEVICE_IN_USE`,inputDescription:`Block this open for up to n milliseconds (100-120000) while another session holds the device, then fail with DEVICE_IN_USE naming that session. Only session contention is waited for: a device claim held by another workspace is refused at once with its recovery command. A device that never frees, or is taken again while this open waits, costs the full budget, which extends this command's timeout envelope rather than eating into it.`,projectConfig:!1,recorded:!1},{key:`retries`,names:[`--retries`],type:`int`,min:0,max:3,usageLabel:`--retries <n>`,usageDescription:`Test: retry each failed script up to n additional times`,projectConfig:!0,recorded:!1},{key:`recordVideo`,names:[`--record-video`],type:`boolean`,usageLabel:`--record-video`,usageDescription:`Test: record each replay attempt to recording.mp4 in its attempt artifacts`,projectConfig:!0,recorded:!1},{key:`artifactsDir`,names:[`--artifacts-dir`],type:`string`,usageLabel:`--artifacts-dir <path>`,usageDescription:`Test: root directory for suite artifacts`,projectConfig:!1,recorded:!1},{key:`reporter`,names:[`--reporter`],type:`string`,multiple:!0,usageLabel:`--reporter <name-or-path>`,usageDescription:`Test: add a replay suite reporter; use default, junit:<path>, or a custom reporter path (repeatable)`,projectConfig:!1,recorded:!1},{key:`reportJunit`,names:[`--report-junit`],type:`string`,usageLabel:`--report-junit <path>`,usageDescription:`Test: compatibility alias for --reporter junit:<path>`,projectConfig:!1,recorded:!1},{key:`shardAll`,names:[`--shard-all`],type:`int`,min:1,usageLabel:`--shard-all <n>`,usageDescription:`Test: run the full suite on each of n devices; combine with --device id1,id2 for explicit connected devices; AD_SHARD_INDEX is zero-based`,projectConfig:!0,recorded:!1},{key:`shardSplit`,names:[`--shard-split`],type:`int`,min:1,usageLabel:`--shard-split <n>`,usageDescription:`Test: split runnable suite entries across n devices; AD_SHARD_INDEX is zero-based`,projectConfig:!0,recorded:!1},{key:`steps`,names:[`--steps`],type:`string`,usageLabel:`--steps <json>`,usageDescription:`Batch: JSON array of {"command","input"} steps`,projectConfig:!1,recorded:!1},{key:`stepsFile`,names:[`--steps-file`],type:`string`,usageLabel:`--steps-file <path>`,usageDescription:`Batch: read steps JSON from file`,projectConfig:!1,recorded:!1},{key:`batchOnError`,names:[`--on-error`],type:`enum`,enumValues:[`stop`],usageLabel:`--on-error stop`,usageDescription:`Batch: stop when a step fails`,projectConfig:!0,recorded:!1},{key:`batchMaxSteps`,names:[`--max-steps`],type:`int`,min:1,max:1e3,usageLabel:`--max-steps <n>`,usageDescription:`Batch: maximum number of allowed steps`,projectConfig:!0,recorded:!1},{key:`appsFilter`,names:[`--all`],type:`enum`,enumValues:[`user-installed`,`all`],setValue:`all`,usageLabel:`--all`,usageDescription:`Apps: include system/OEM apps`,projectConfig:!0,recorded:!1},{key:`snapshotInteractiveOnly`,names:[`-i`],type:`boolean`,usageLabel:`-i`,usageDescription:`Snapshot: interactive elements only`,projectConfig:!0,recorded:!0},{key:`snapshotDepth`,names:[`--depth`,`-d`],type:`int`,min:0,usageLabel:`--depth, -d <depth>`,usageDescription:`Snapshot: limit snapshot depth`,projectConfig:!0,recorded:!0},{key:`snapshotScope`,names:[`--scope`,`-s`],type:`string`,usageLabel:`--scope, -s <scope>`,usageDescription:`Snapshot: scope snapshot to label/identifier`,projectConfig:!0,recorded:!0},{key:`snapshotRaw`,names:[`--raw`],type:`boolean`,usageLabel:`--raw`,usageDescription:`Snapshot: raw node output`,projectConfig:!0,recorded:!0},{key:`snapshotCustomActions`,names:[`--actions`],type:`boolean`,usageLabel:`--actions`,usageDescription:`Snapshot: name the affordances merged inside an element (iOS sim); not directly invokable — reach them via the detail screen, labeled children, or coordinates`,inputDescription:`Name the affordances an element merged away (iOS UIAccessibilityCustomAction, React Native accessibilityActions) — a card whose reply/options controls are not separate elements still lists them here. The names are for PLANNING, not invocation: there is no API to trigger them, so reach the affordance through the element detail screen, through the same control exposed as a labeled element elsewhere, or by coordinates from its rect. iOS simulator only; costs one accessibility round trip per merged element.`,projectConfig:!0,recorded:!0},{key:`snapshotForceFull`,names:[`--force-full`],type:`boolean`,usageLabel:`--force-full`,usageDescription:`Snapshot: re-emit the full tree even when unchanged`,projectConfig:!0,recorded:!1},{key:`findFirst`,names:[`--first`],type:`boolean`,usageLabel:`--first`,usageDescription:`Find: pick the first match when ambiguous`,projectConfig:!0,recorded:!1},{key:`findLast`,names:[`--last`],type:`boolean`,usageLabel:`--last`,usageDescription:`Find: pick the last match when ambiguous`,projectConfig:!0,recorded:!1},{key:`out`,names:[`--out`],type:`string`,usageLabel:`--out <path>`,usageDescription:`Output path`,projectConfig:!1,recorded:!0},{key:`artifact`,names:[`--artifact`],type:`string`,usageLabel:`--artifact <path>`,usageDescription:`Debug symbols: Apple crash artifact path (.ips, .crash, or .log)`,projectConfig:!1,recorded:!1},{key:`dsym`,names:[`--dsym`],type:`string`,usageLabel:`--dsym <path>`,usageDescription:`Debug symbols: matching .dSYM bundle path`,projectConfig:!1,recorded:!1},{key:`searchPath`,names:[`--search-path`],type:`string`,usageLabel:`--search-path <dir>`,usageDescription:`Debug symbols: directory to scan for matching .dSYM bundles`,projectConfig:!1,recorded:!1},{key:`overlayRefs`,names:[`--overlay-refs`],type:`boolean`,usageLabel:`--overlay-refs`,usageDescription:`Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide`,projectConfig:!0,recorded:!1},...n,{key:`baseline`,names:[`--baseline`,`-b`],type:`string`,usageLabel:`--baseline, -b <path>`,usageDescription:`Diff screenshot: path to baseline image file`,projectConfig:!0,recorded:!1},{key:`threshold`,names:[`--threshold`],type:`string`,usageLabel:`--threshold <0-1>`,usageDescription:`Diff screenshot: color distance threshold (default 0.1)`,projectConfig:!0,recorded:!1}],f=[...l,...u,...c,...d],p=new Map;for(let e of f)for(let t of e.names)p.set(t,e);function m(e){return p.get(e)}function h(){return f}function g(e){return f.filter(t=>t.key===e)}function _(){return new Set(f.filter(e=>e.projectConfig).map(e=>e.key))}function v(){return new Set(f.filter(e=>e.recorded).map(e=>e.key))}const y=[`in-app`,`system`];export{_ as a,g as i,m as n,v as o,h as r,y as t};
|
|
1
|
+
import{i as e,t}from"./sdk-contracts.js";import{o as n}from"./capture.js";import{i as r}from"./sdk-device.js";import{t as i}from"./recording-scope.js";import{c as a}from"./sdk-remote-config.js";import{t as o}from"./session.js";import{c as s}from"./observability.js";const c=[{key:`keyframes`,names:[`--keyframes`],type:`string`,usageLabel:`--keyframes <json>`,usageDescription:`Fold: timed {atMs, angle} keyframes; final atMs is motion duration (up to 60000ms)`,projectConfig:!1,recorded:!0},{key:`count`,names:[`--count`],type:`int`,min:1,max:200,usageLabel:`--count <n>`,usageDescription:`Repeat count for press/swipe series`,projectConfig:!0,recorded:!0},{key:`pointerCount`,names:[`--pointer-count`],type:`int`,min:1,max:2,usageLabel:`--pointer-count <1|2>`,usageDescription:`Gesture pan: number of touch pointers (default 1)`,projectConfig:!0,recorded:!0},{key:`fps`,names:[`--fps`],type:`int`,min:1,max:120,usageLabel:`--fps <n>`,usageDescription:`Record: target frames per second (iOS physical device runner); also lowers the touch-overlay rate, which never exceeds 30`,projectConfig:!0,recorded:!0},{key:`quality`,names:[`--quality`],type:`string`,usageLabel:`--quality <medium|high>`,usageDescription:`Record: output quality preset; Android maps this to screenrecord bitrate, Limrun sessions map medium to recorder quality 5 and high to 8; Apple export always preserves the captured resolution, so it has no effect there. Legacy numeric values 5-7 map to medium; 8-10 map to high`,projectConfig:!0,recorded:!0},{key:`hideTouches`,names:[`--hide-touches`],type:`boolean`,usageLabel:`--hide-touches`,usageDescription:`Record: skip touch-overlay post-processing for faster raw benchmark videos`,projectConfig:!0,recorded:!0},{key:`recordingScope`,names:[`--scope`],type:`enum`,enumValues:i,usageLabel:`--scope <app|device|system>`,usageDescription:`Record: app requires an active app session; device/system records the whole screen`,projectConfig:!0,recorded:!1},{key:`intervalMs`,names:[`--interval-ms`],type:`int`,min:0,max:1e4,usageLabel:`--interval-ms <ms>`,usageDescription:`Delay between press iterations`,projectConfig:!0,recorded:!0},{key:`delayMs`,names:[`--delay-ms`],type:`int`,min:0,max:1e4,usageLabel:`--delay-ms <ms>`,usageDescription:`Delay between typed characters`,projectConfig:!0,recorded:!0},{key:`recordAs`,names:[`--record-as`],type:`string`,usageLabel:`--record-as <VAR>`,usageDescription:"Fill: send the live text but publish ${VAR} in an armed .ad recording",projectConfig:!0,recorded:!1},{key:`durationMs`,names:[`--duration-ms`],type:`int`,min:0,max:1e4,usageLabel:`--duration-ms <ms>`,usageDescription:`Scroll: pace the gesture over this duration when supported`,projectConfig:!0,recorded:!1},{key:`holdMs`,names:[`--hold-ms`],type:`int`,min:0,max:1e4,usageLabel:`--hold-ms <ms>`,usageDescription:`Press hold duration for each iteration`,projectConfig:!0,recorded:!0},{key:`jitterPx`,names:[`--jitter-px`],type:`int`,min:0,max:100,usageLabel:`--jitter-px <n>`,usageDescription:`Deterministic coordinate jitter radius for press`,projectConfig:!0,recorded:!0},{key:`pixels`,names:[`--pixels`],type:`int`,min:1,max:1e5,usageLabel:`--pixels <n>`,usageDescription:`Scroll: explicit gesture distance in pixels`,projectConfig:!0,recorded:!1},{key:`until`,names:[`--until`],type:`string`,usageLabel:`--until <selector>`,usageDescription:`Scroll: repeat passes until the selector is visible on screen`,projectConfig:!0,recorded:!0},{key:`doubleTap`,names:[`--double-tap`],type:`boolean`,usageLabel:`--double-tap`,usageDescription:`Use double-tap gesture per press iteration`,projectConfig:!0,recorded:!0},{key:`verify`,names:[`--verify`],type:`boolean`,usageLabel:`--verify`,usageDescription:`Capture cheap post-action evidence (AX digest, node counts, changedFromBefore) instead of a follow-up snapshot`,projectConfig:!0,recorded:!1},{key:`settle`,names:[`--settle`],type:`boolean`,usageLabel:`--settle`,usageDescription:`After the action, wait for the UI to go quiet and return the settled diff vs the pre-action tree in the same response (best-effort; never fails the action)`,projectConfig:!0,recorded:!1},{key:`settleQuietMs`,names:[`--settle-quiet`],type:`int`,min:0,usageLabel:`--settle-quiet <ms>`,usageDescription:`Settle: quiet window the UI must hold to count as settled (default 500ms)`,projectConfig:!0,recorded:!1},{key:`clickButton`,names:[`--button`],type:`enum`,enumValues:[`primary`,`secondary`,`middle`],usageLabel:`--button primary|secondary|middle`,usageDescription:`Click: choose mouse button (middle reserved for future macOS support)`,projectConfig:!0,recorded:!0},{key:`backMode`,names:[`--in-app`],type:`enum`,enumValues:[`in-app`,`system`],setValue:`in-app`,usageLabel:`--in-app`,usageDescription:`Back: use app-provided back UI when available`,projectConfig:!0,recorded:!1},{key:`backMode`,names:[`--system`],type:`enum`,enumValues:[`in-app`,`system`],setValue:`system`,usageLabel:`--system`,usageDescription:`Back: use system back input or gesture when available`,projectConfig:!0,recorded:!1},{key:`pauseMs`,names:[`--pause-ms`],type:`int`,min:0,max:1e4,usageLabel:`--pause-ms <ms>`,usageDescription:`Delay between swipe iterations`,projectConfig:!0,recorded:!0},{key:`pattern`,names:[`--pattern`],type:`enum`,enumValues:[`one-way`,`ping-pong`],usageLabel:`--pattern one-way|ping-pong`,usageDescription:`Swipe repeat pattern`,projectConfig:!0,recorded:!0},{key:`verbose`,names:[`--debug`,`--verbose`,`-v`],type:`boolean`,usageLabel:`--debug, --verbose, -v`,usageDescription:`Enable debug diagnostics; test --verbose prints per-test step timings without debug logs`,projectConfig:!0,recorded:!0},{key:`cost`,names:[`--cost`],type:`boolean`,usageLabel:`--cost`,usageDescription:`Include per-command wall-clock latency (cost.wallClockMs) in the response`,projectConfig:!0,recorded:!1},{key:`responseLevel`,names:[`--level`],type:`enum`,enumValues:e,usageLabel:`--level digest|default|full`,usageDescription:`Response detail level: digest (token-cheap), default (today), or full. Default keeps the wire shape unchanged.`,projectConfig:!0,recorded:!1},{key:`json`,names:[`--json`],type:`boolean`,usageLabel:`--json`,usageDescription:`JSON output`,projectConfig:!0,recorded:!1},{key:`help`,names:[`--help`,`-h`],type:`boolean`,usageLabel:`--help, -h`,usageDescription:`Print help and exit`,projectConfig:!1,recorded:!1},{key:`version`,names:[`--version`,`-V`],type:`boolean`,usageLabel:`--version, -V`,usageDescription:`Print version and exit`,projectConfig:!1,recorded:!1},{key:`snapshotDiff`,names:[`--diff`],type:`boolean`,usageLabel:`--diff`,usageDescription:`Snapshot: show structural diff against the previous session baseline`,projectConfig:!0,recorded:!1},{key:`saveScript`,names:[`--save-script`],type:`booleanOrString`,usageLabel:`--save-script [path]`,usageDescription:`Arm evidence capture on open, publish the armed recording on close; close --save-script alone (without an armed open) is rejected — start with open --save-script, or use session save-script mid-session. Optional custom output path.`,projectConfig:!1,recorded:!0},{key:`networkInclude`,names:[`--include`],type:`enum`,enumValues:[`summary`,`headers`,`body`,`all`],usageLabel:`--include summary|headers|body|all`,usageDescription:`Network: include headers, bodies, or both in output`,projectConfig:!0,recorded:!1},{key:`shutdown`,names:[`--shutdown`],type:`boolean`,usageLabel:`--shutdown`,usageDescription:`close: shutdown associated simulator/emulator after ending session`,projectConfig:!0,recorded:!1},{key:`relaunch`,names:[`--relaunch`],type:`boolean`,usageLabel:`--relaunch`,usageDescription:`open: terminate app process before launching it`,projectConfig:!0,recorded:!0},{key:`foreground`,names:[`--foreground`],type:`boolean`,usageLabel:`--foreground`,usageDescription:`open: keep normal app/device selection and return an initial snapshot; without an app, resolve the sole running app on the sole booted iOS simulator`,inputDescription:`Include an initial interactive snapshot in a fresh open response. With no app argument, discover the sole running app on the sole booted iOS simulator; ambiguous environments fail closed.`,projectConfig:!1,recorded:!1},{key:`restart`,names:[`--restart`],type:`boolean`,usageLabel:`--restart`,usageDescription:`logs clear: stop active stream, clear logs, then start streaming again`,projectConfig:!0,recorded:!1},{key:`retainPaths`,names:[`--retain-paths`],type:`boolean`,usageLabel:`--retain-paths`,usageDescription:`install-from-source: keep materialized artifact paths after install`,projectConfig:!0,recorded:!1},{key:`retentionMs`,names:[`--retention-ms`],type:`int`,min:1,usageLabel:`--retention-ms <ms>`,usageDescription:`install-from-source: retention TTL for materialized artifact paths`,projectConfig:!0,recorded:!1},{key:`noRecord`,names:[`--no-record`],type:`boolean`,usageLabel:`--no-record`,usageDescription:`Do not record this action`,projectConfig:!0,recorded:!0},{key:`record`,names:[`--record`],type:`boolean`,usageLabel:`--record`,usageHidden:!0,usageDescription:`Force-record this action even though its command is observation-only and would otherwise be excluded from a repair-armed heal by default (mutually exclusive with --no-record)`,projectConfig:!0,recorded:!0}],l=[{key:`config`,names:[`--config`],type:`string`,usageLabel:`--config <path>`,usageDescription:`Load CLI defaults from a specific config file (required for connection/provider defaults outside user config)`,projectConfig:!1,recorded:!1},{key:`remoteConfig`,names:[`--remote-config`],type:`string`,usageLabel:`--remote-config <path>`,usageDescription:`Load remote host + Metro workflow settings from a specific profile file`,projectConfig:!1,recorded:!1},{key:`stateDir`,names:[`--state-dir`],type:`string`,usageLabel:`--state-dir <path>`,usageDescription:`Daemon state directory (defaults to ~/.agent-device for packages, or a worktree-scoped dev dir from source)`,projectConfig:!1,recorded:!1},{key:`daemonBaseUrl`,names:[`--daemon-base-url`],type:`string`,usageLabel:`--daemon-base-url <url>`,usageDescription:`Explicit remote HTTP daemon base URL (skip local daemon discovery/startup)`,projectConfig:!1,recorded:!1},{key:`daemonAuthToken`,names:[`--daemon-auth-token`],type:`string`,usageLabel:`--daemon-auth-token <token>`,usageDescription:`Remote HTTP daemon or proxy auth token (sent as request token and bearer header)`,projectConfig:!1,recorded:!1},{key:`daemonTransport`,names:[`--daemon-transport`],type:`enum`,enumValues:[`auto`,`socket`,`http`],usageLabel:`--daemon-transport auto|socket|http`,usageDescription:`Daemon client transport preference`,projectConfig:!1,recorded:!1},{key:`daemonServerMode`,names:[`--daemon-server-mode`],type:`enum`,enumValues:[`socket`,`http`,`dual`],usageLabel:`--daemon-server-mode socket|http|dual`,usageDescription:`Daemon server mode used when spawning daemon`,projectConfig:!1,recorded:!1},{key:`proxyHost`,names:[`--host`],type:`string`,usageLabel:`--host <host>`,usageDescription:`Proxy: host interface to bind (default: 127.0.0.1)`,projectConfig:!1,recorded:!1},{key:`proxyPort`,names:[`--port`],type:`int`,min:1,max:65535,usageLabel:`--port <port>`,usageDescription:`Proxy: TCP port to bind (default: 0, choose a free port)`,projectConfig:!1,recorded:!1},{key:`tenant`,names:[`--tenant`],type:`string`,usageLabel:`--tenant <id>`,usageDescription:`Tenant scope identifier for isolated daemon sessions`,projectConfig:!1,recorded:!1},{key:`sessionIsolation`,names:[`--session-isolation`],type:`enum`,enumValues:[`none`,`tenant`],usageLabel:`--session-isolation none|tenant`,usageDescription:`Session isolation strategy (tenant prefixes session namespace)`,projectConfig:!1,recorded:!1},{key:`runId`,names:[`--run-id`],type:`string`,usageLabel:`--run-id <id>`,usageDescription:`Run identifier used for tenant lease admission checks`,projectConfig:!1,recorded:!1},{key:`leaseId`,names:[`--lease-id`],type:`string`,usageLabel:`--lease-id <id>`,usageDescription:`Lease identifier bound to tenant/run admission scope`,projectConfig:!1,recorded:!1},{key:`leaseBackend`,names:[`--lease-backend`],type:`enum`,enumValues:t,usageLabel:`--lease-backend ${t.join(`|`)}`,usageDescription:`Lease backend for remote tenant connection admission`,projectConfig:!1,recorded:!1},{key:`provider`,names:[`--provider`],type:`string`,usageLabel:`--provider <name>`,usageDescription:`Cloud provider name for provider-scoped commands`,projectConfig:!1,recorded:!1},{key:`providerSessionId`,names:[`--provider-session`],type:`string`,usageLabel:`--provider-session <id>`,usageDescription:`Cloud provider session id or ARN`,projectConfig:!1,recorded:!1},{key:`providerApp`,names:[`--provider-app`],type:`string`,usageLabel:`--provider-app <ref-or-path>`,usageDescription:`Cloud provider app reference or local app path used when creating hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`providerOsVersion`,names:[`--provider-os-version`,`--os-version`],type:`string`,usageLabel:`--provider-os-version <version>`,usageDescription:`Hosted cloud provider OS version, for example 17 or 14.0`,projectConfig:!1,recorded:!1},{key:`providerProject`,names:[`--provider-project`],type:`string`,usageLabel:`--provider-project <name>`,usageDescription:`Hosted cloud provider project label`,projectConfig:!1,recorded:!1},{key:`providerBuild`,names:[`--provider-build`],type:`string`,usageLabel:`--provider-build <name>`,usageDescription:`Hosted cloud provider build label`,projectConfig:!1,recorded:!1},{key:`providerSessionName`,names:[`--provider-session-name`],type:`string`,usageLabel:`--provider-session-name <name>`,usageDescription:`Hosted cloud provider session label`,projectConfig:!1,recorded:!1},{key:`providerDeviceOrientation`,names:[`--provider-device-orientation`,`--device-orientation`],type:`enum`,enumValues:a,usageLabel:`--provider-device-orientation portrait|landscape`,usageDescription:`Screen orientation a hosted cloud provider session starts in. Set this rather than rotating after launch: a session that boots landscape renders login webviews landscape`,projectConfig:!1,recorded:!1},{key:`providerGeoLocation`,names:[`--provider-geo-location`,`--geo-location`],type:`string`,usageLabel:`--provider-geo-location <country>`,usageDescription:`Hosted cloud provider IP geolocation country code, for example US`,projectConfig:!1,recorded:!1},{key:`providerTimezone`,names:[`--provider-timezone`,`--timezone`],type:`string`,usageLabel:`--provider-timezone <zone>`,usageDescription:`Hosted cloud provider device time zone, for example New_York`,projectConfig:!1,recorded:!1},{key:`providerAppiumVersion`,names:[`--provider-appium-version`,`--appium-version`],type:`string`,usageLabel:`--provider-appium-version <version>`,usageDescription:`Hosted cloud provider Appium server version, for example 3.2.0. Without it BrowserStack falls back to its default (Appium 1.x)`,projectConfig:!1,recorded:!1},{key:`providerLanguage`,names:[`--provider-language`,`--language`],type:`string`,usageLabel:`--provider-language <language>`,usageDescription:`Hosted cloud provider app language, for example Fr`,projectConfig:!1,recorded:!1},{key:`providerLocale`,names:[`--provider-locale`,`--locale`],type:`string`,usageLabel:`--provider-locale <locale>`,usageDescription:`Hosted cloud provider device locale, for example Fr`,projectConfig:!1,recorded:!1},{key:`providerNetworkProfile`,names:[`--provider-network-profile`,`--network-profile`],type:`string`,usageLabel:`--provider-network-profile <profile>`,usageDescription:`Hosted cloud provider named network condition profile, for example 4g-lte-advanced-good. Mutually exclusive with --provider-custom-network`,projectConfig:!1,recorded:!1},{key:`providerCustomNetwork`,names:[`--provider-custom-network`,`--custom-network`],type:`string`,usageLabel:`--provider-custom-network <shape>`,usageDescription:`Hosted cloud provider custom network shape. Mutually exclusive with --provider-network-profile`,projectConfig:!1,recorded:!1},{key:`providerNoResignApp`,names:[`--provider-no-resign-app`],type:`boolean`,usageLabel:`--provider-no-resign-app`,usageDescription:`iOS only: keep an Enterprise-signed app as uploaded instead of letting the provider re-sign it, which strips entitlements such as push notifications`,projectConfig:!1,recorded:!1},{key:`awsProjectArn`,names:[`--aws-project-arn`],type:`string`,usageLabel:`--aws-project-arn <arn>`,usageDescription:`AWS Device Farm project ARN for hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`awsDeviceArn`,names:[`--aws-device-arn`],type:`string`,usageLabel:`--aws-device-arn <arn>`,usageDescription:`AWS Device Farm device ARN for hosted WebDriver sessions`,projectConfig:!1,recorded:!1},{key:`awsAppArn`,names:[`--aws-app-arn`],type:`string`,usageLabel:`--aws-app-arn <arn>`,usageDescription:`AWS Device Farm app ARN attached to hosted remote access sessions`,projectConfig:!1,recorded:!1},{key:`awsRegion`,names:[`--aws-region`],type:`string`,usageLabel:`--aws-region <region>`,usageDescription:`AWS region for Device Farm API calls`,projectConfig:!1,recorded:!1},{key:`awsInteractionMode`,names:[`--aws-interaction-mode`],type:`enum`,enumValues:[`INTERACTIVE`,`NO_VIDEO`,`VIDEO_ONLY`],usageLabel:`--aws-interaction-mode INTERACTIVE|NO_VIDEO|VIDEO_ONLY`,usageDescription:`AWS Device Farm remote access interaction mode`,projectConfig:!1,recorded:!1},{key:`force`,names:[`--force`,`--overwrite`],type:`boolean`,usageLabel:`--force, --overwrite`,usageDescription:`Force replacement of existing state (connect: replace an active connection; --save-script: overwrite an existing target instead of refusing)`,projectConfig:!0,recorded:!0},{key:`clean`,names:[`--clean`],type:`boolean`,usageLabel:`--clean`,usageDescription:`Daemon stop: remove retained runner processes and leases after stopping`,projectConfig:!0,recorded:!1},{key:`noLogin`,names:[`--no-login`],type:`boolean`,usageLabel:`--no-login`,usageDescription:`Connect: fail instead of starting implicit cloud login`,projectConfig:!0,recorded:!1},{key:`sessionLock`,names:[`--session-lock`],type:`enum`,enumValues:[`reject`,`strip`],usageLabel:`--session-lock reject|strip`,usageDescription:`Lock bound-session device routing for this CLI invocation and nested batch steps; strip drops conflicting platform/scope selectors only, and a selector naming a different device always fails`,projectConfig:!0,recorded:!1}],u=[{key:`platform`,names:[`--platform`],type:`enum`,enumValues:r,usageLabel:`--platform ${r.join(`|`)}`,usageDescription:"Platform to target (`apple` aliases the Apple automation backend)",projectConfig:!0,recorded:!0},{key:`target`,names:[`--target`],type:`enum`,enumValues:[`mobile`,`tv`,`desktop`],usageLabel:`--target mobile|tv|desktop`,usageDescription:`Device target class to match`,projectConfig:!0,recorded:!1},{key:`device`,names:[`--device`],type:`string`,usageLabel:`--device <name>`,usageDescription:`Device name to target (a UDID belongs in --udid, a serial in --serial)`,projectConfig:!0,recorded:!0},{key:`udid`,names:[`--udid`],type:`string`,usageLabel:`--udid <udid>`,usageDescription:`Apple device or simulator UDID; the only selector that pins one device when several share a --device name`,projectConfig:!0,recorded:!0},{key:`serial`,names:[`--serial`],type:`string`,usageLabel:`--serial <serial>`,usageDescription:`Android, HarmonyOS, or Vega VVD serial`,projectConfig:!0,recorded:!0},{key:`stale`,names:[`--stale`],type:`boolean`,usageLabel:`--stale`,usageDescription:`Device status: show only claims with a provably stale owner`,projectConfig:!0,recorded:!1},{key:`surface`,names:[`--surface`],type:`enum`,enumValues:o,usageLabel:`--surface app|frontmost-app|desktop|menubar`,usageDescription:`macOS session surface for open (defaults to app)`,projectConfig:!0,recorded:!0},{key:`headless`,names:[`--headless`],type:`boolean`,usageLabel:`--headless`,usageDescription:`Boot: launch Android emulator without a GUI window`,projectConfig:!0,recorded:!1},{key:`targetApp`,names:[`--app`,`--target-app`],type:`string`,usageLabel:`--app <id-or-name>`,usageDescription:`Target an app without opening it: doctor verifies an installed app by id or name; settings applies an app-scoped change (permission, iOS location) to a bundle id or package`,projectConfig:!1,recorded:!1},{key:`metroHost`,names:[`--metro-host`],type:`string`,usageLabel:`--metro-host <host>`,usageDescription:`Session-scoped Metro/debug host hint`,projectConfig:!1,recorded:!0},{key:`metroPort`,names:[`--metro-port`],type:`int`,min:1,max:65535,usageLabel:`--metro-port <port>`,usageDescription:`Session-scoped Metro/debug port hint; on an emulator/simulator the host defaults to the loopback alias, physical devices still need --metro-host`,projectConfig:!1,recorded:!0},{key:`metroProjectRoot`,names:[`--project-root`],type:`string`,usageLabel:`--project-root <path>`,usageDescription:`metro prepare: React Native project root (default: cwd)`,projectConfig:!1,recorded:!1},{key:`kind`,names:[`--kind`],type:`enum`,enumValues:[`auto`,`react-native`,`expo`,`repack`,...s],usageLabel:`--kind <kind>`,usageDescription:`Kind selector for commands that support it, such as metro prepare or perf artifact collectors`,projectConfig:!0,recorded:!1},{key:`perfTemplate`,names:[`--template`],type:`string`,usageLabel:`--template <name>`,usageDescription:`Perf xctrace template name, for example Time Profiler`,projectConfig:!0,recorded:!1},{key:`metroKind`,names:[`--metro-kind`],type:`enum`,enumValues:[`auto`,`react-native`,`expo`,`repack`],usageLabel:`--metro-kind auto|react-native|expo|repack`,usageDescription:`metro prepare: detect or force the React Native dev-server launcher kind`,projectConfig:!1,recorded:!1},{key:`metroPublicBaseUrl`,names:[`--public-base-url`],type:`string`,usageLabel:`--public-base-url <url>`,usageDescription:`metro prepare: public base URL used for direct dev-server bundle hints`,projectConfig:!1,recorded:!1},{key:`metroProxyBaseUrl`,names:[`--proxy-base-url`],type:`string`,usageLabel:`--proxy-base-url <url>`,usageDescription:`metro prepare: optional bridge origin for remote dev-server access`,projectConfig:!1,recorded:!1},{key:`metroBearerToken`,names:[`--bearer-token`],type:`string`,usageLabel:`--bearer-token <token>`,usageDescription:`metro prepare: host bridge bearer token (or AGENT_DEVICE_METRO_BEARER_TOKEN; falls back to AGENT_DEVICE_DAEMON_AUTH_TOKEN)`,projectConfig:!1,recorded:!1},{key:`metroPreparePort`,names:[`--port`],type:`int`,min:1,max:65535,usageLabel:`--port <port>`,usageDescription:`metro prepare: local dev-server port (default: 8081)`,projectConfig:!1,recorded:!1},{key:`metroListenHost`,names:[`--listen-host`],type:`string`,usageLabel:`--listen-host <host>`,usageDescription:`metro prepare: host dev server listens on (default: 0.0.0.0)`,projectConfig:!1,recorded:!1},{key:`metroStatusHost`,names:[`--status-host`],type:`string`,usageLabel:`--status-host <host>`,usageDescription:`metro prepare: host used for local dev-server /status polling (default: 127.0.0.1)`,projectConfig:!1,recorded:!1},{key:`metroStartupTimeoutMs`,names:[`--startup-timeout-ms`],type:`int`,min:1,usageLabel:`--startup-timeout-ms <ms>`,usageDescription:`metro prepare: timeout while waiting for the dev server to become ready`,projectConfig:!1,recorded:!1},{key:`metroProbeTimeoutMs`,names:[`--probe-timeout-ms`],type:`int`,min:1,usageLabel:`--probe-timeout-ms <ms>`,usageDescription:`metro prepare: timeout for /status and proxy bridge calls`,projectConfig:!1,recorded:!1},{key:`metroRuntimeFile`,names:[`--runtime-file`],type:`string`,usageLabel:`--runtime-file <path>`,usageDescription:`metro prepare: optional file path to persist the JSON result`,projectConfig:!1,recorded:!1},{key:`metroNoReuseExisting`,names:[`--no-reuse-existing`],type:`boolean`,usageLabel:`--no-reuse-existing`,usageDescription:`metro prepare: always start a fresh Metro process`,projectConfig:!1,recorded:!1},{key:`metroNoInstallDeps`,names:[`--no-install-deps`],type:`boolean`,usageLabel:`--no-install-deps`,usageDescription:`metro prepare: skip package-manager install when node_modules is missing`,projectConfig:!1,recorded:!1},{key:`bundleUrl`,names:[`--bundle-url`],type:`string`,usageLabel:`--bundle-url <url>`,usageDescription:`Session-scoped bundle URL hint`,projectConfig:!1,recorded:!0},{key:`launchUrl`,names:[`--launch-url`],type:`string`,usageLabel:`--launch-url <url>`,usageDescription:`Session-scoped deep link / launch URL hint`,projectConfig:!0,recorded:!0},{key:`iosSimulatorDeviceSet`,names:[`--ios-simulator-device-set`],type:`string`,usageLabel:`--ios-simulator-device-set <path>`,usageDescription:`Scope iOS simulator discovery/commands to this simulator device set`,projectConfig:!1,recorded:!1},{key:`iosXctestrunFile`,names:[`--ios-xctestrun-file`],type:`string`,usageLabel:`--ios-xctestrun-file <path>`,usageDescription:`Use an externally built iOS XCTest runner .xctestrun artifact`,projectConfig:!1,recorded:!1},{key:`iosXctestDerivedDataPath`,names:[`--ios-xctest-derived-data-path`],type:`string`,usageLabel:`--ios-xctest-derived-data-path <path>`,usageDescription:`Derived data path for external iOS XCTest runner execution`,projectConfig:!1,recorded:!1},{key:`iosXctestEnvDir`,names:[`--ios-xctest-env-dir`],type:`string`,usageLabel:`--ios-xctest-env-dir <path>`,usageDescription:`Writable directory for per-session iOS XCTest runner env overlays`,projectConfig:!1,recorded:!1},{key:`testIme`,names:[`--test-ime`],type:`boolean`,usageLabel:`--test-ime`,usageDescription:`open/test/replay: activate the headless Android test IME for deterministic Unicode text entry (default on for emulators; opt-in on real devices; on test/replay it applies to the sessions the flow opens)`,projectConfig:!0,recorded:!1},{key:`testIme`,names:[`--no-test-ime`],type:`boolean`,setValue:!1,usageLabel:`--no-test-ime`,usageDescription:`open/test/replay: keep the real Android keyboard even on emulators (opt out of the headless test IME; on test/replay it applies to the sessions the flow opens)`,projectConfig:!0,recorded:!1},{key:`androidDeviceAllowlist`,names:[`--android-device-allowlist`],type:`string`,usageLabel:`--android-device-allowlist <serials>`,usageDescription:`Comma/space separated Android serial allowlist for discovery/selection`,projectConfig:!1,recorded:!1},{key:`remote`,names:[`--remote`],type:`boolean`,usageLabel:`--remote`,usageDescription:`Doctor: check remote connection setup instead of local device inventory`,projectConfig:!0,recorded:!1},{key:`activity`,names:[`--activity`],type:`string`,usageLabel:`--activity <component>`,usageDescription:`Android app launch activity (package/Activity); not for URL opens`,projectConfig:!0,recorded:!1},{key:`launchConsole`,names:[`--launch-console`],type:`string`,usageLabel:`--launch-console <path>`,usageDescription:`open: capture the initial iOS simulator launch console window to a file`,projectConfig:!1,recorded:!1},{key:`launchArgs`,names:[`--launch-args`],type:`string`,multiple:!0,usageLabel:`--launch-args <arg>`,usageDescription:`open: repeatable launch argument forwarded verbatim to the platform launch command (iOS app process args; Android adb shell am start args). Linux and macOS reject the flag.`,projectConfig:!0,recorded:!1},{key:`header`,names:[`--header`],type:`string`,multiple:!0,usageLabel:`--header <name:value>`,usageDescription:`install-from-source: repeatable HTTP header for URL downloads`,projectConfig:!1,recorded:!1},{key:`githubActionsArtifact`,names:[`--github-actions-artifact`],type:`string`,usageLabel:`--github-actions-artifact <owner/repo:artifact>`,usageDescription:`install-from-source: GitHub Actions artifact resolved by a remote daemon`,projectConfig:!1,recorded:!1},{key:`installSource`,names:[],type:`string`,projectConfig:!1,recorded:!1},{key:`session`,names:[`--session`],type:`string`,usageLabel:`--session <name>`,usageDescription:`Named session (implicit default is scoped to this workspace + platform)`,projectConfig:!0,recorded:!1}],d=[{key:`replayUpdate`,names:[`--update`,`-u`],type:`boolean`,usageLabel:`--update, -u`,usageDescription:`Replay: retired as a rewrite (ADR 0012) — never edits the .ad file; every divergence already carries ranked selector suggestions, --update or not`,projectConfig:!0,recorded:!1},{key:`replayFrom`,names:[`--from`],type:`int`,min:1,usageLabel:`--from <n>`,usageDescription:`Replay: resume at 1-based plan step n, skipping 1..n-1 without executing them (requires --plan-digest; see a divergence report's resume field). replay only, not test`,projectConfig:!0,recorded:!1},{key:`replayPlanDigest`,names:[`--plan-digest`],type:`string`,usageLabel:`--plan-digest <sha256>`,usageDescription:`Replay: the plan digest a --from resume must match (from a prior divergence report); mismatch, edits, or include/platform-expansion changes fail INVALID_ARGS before any action`,projectConfig:!0,recorded:!1},{key:`replayKeepSession`,names:[`--keep-session`],type:`boolean`,usageLabel:`--keep-session`,usageDescription:`Replay: leave the session active by suppressing exactly an authored terminal close in a native .ad script; replay only, not test or Maestro YAML`,projectConfig:!0,recorded:!1},{key:`replayMaestro`,names:[`--maestro`],type:`boolean`,usageLabel:`--maestro`,usageDescription:`Replay: treat input as a supported Maestro YAML subset; unsupported syntax fails loudly. See agent-device help maestro for commands and boundaries`,projectConfig:!0,recorded:!1},{key:`replayEnv`,names:[`-e`,`--env`],type:`string`,multiple:!0,usageLabel:`-e KEY=VALUE, --env KEY=VALUE`,usageDescription:"Replay/Test: inject or override a ${KEY} variable for the script (repeatable)",projectConfig:!1,recorded:!1},{key:`failFast`,names:[`--fail-fast`],type:`boolean`,usageLabel:`--fail-fast`,usageDescription:`Test: stop the suite after the first failing script; with sharding, each shard stops independently`,projectConfig:!0,recorded:!1},{key:`timeoutMs`,names:[`--timeout`],type:`int`,min:1,usageLabel:`--timeout <ms>`,usageDescription:`Boot/Open/Prepare: startup budget covering the device boot (and runner preparation for prepare). Replay/Snapshot/Test: maximum wall-clock time for the command or attempt. With --settle: the settle-wait deadline (default 10s)`,projectConfig:!0,recorded:!1},{key:`waitMs`,names:[`--wait`],type:`int`,min:100,max:12e4,usageLabel:`--wait <ms>`,usageDescription:`Open: wait up to n ms for a device another session is holding before failing with DEVICE_IN_USE`,inputDescription:`Block this open for up to n milliseconds (100-120000) while another session holds the device, then fail with DEVICE_IN_USE naming that session. Only session contention is waited for: a device claim held by another workspace is refused at once with its recovery command. A device that never frees, or is taken again while this open waits, costs the full budget, which extends this command's timeout envelope rather than eating into it.`,projectConfig:!1,recorded:!1},{key:`retries`,names:[`--retries`],type:`int`,min:0,max:3,usageLabel:`--retries <n>`,usageDescription:`Test: retry each failed script up to n additional times`,projectConfig:!0,recorded:!1},{key:`recordVideo`,names:[`--record-video`],type:`boolean`,usageLabel:`--record-video`,usageDescription:`Test: record each replay attempt to recording.mp4 in its attempt artifacts`,projectConfig:!0,recorded:!1},{key:`artifactsDir`,names:[`--artifacts-dir`],type:`string`,usageLabel:`--artifacts-dir <path>`,usageDescription:`Test: root directory for suite artifacts`,projectConfig:!1,recorded:!1},{key:`reporter`,names:[`--reporter`],type:`string`,multiple:!0,usageLabel:`--reporter <name-or-path>`,usageDescription:`Test: add a replay suite reporter; use default, junit:<path>, or a custom reporter path (repeatable)`,projectConfig:!1,recorded:!1},{key:`reportJunit`,names:[`--report-junit`],type:`string`,usageLabel:`--report-junit <path>`,usageDescription:`Test: compatibility alias for --reporter junit:<path>`,projectConfig:!1,recorded:!1},{key:`shardAll`,names:[`--shard-all`],type:`int`,min:1,usageLabel:`--shard-all <n>`,usageDescription:`Test: run the full suite on each of n devices; combine with --device id1,id2 for explicit connected devices; AD_SHARD_INDEX is zero-based`,projectConfig:!0,recorded:!1},{key:`shardSplit`,names:[`--shard-split`],type:`int`,min:1,usageLabel:`--shard-split <n>`,usageDescription:`Test: split runnable suite entries across n devices; AD_SHARD_INDEX is zero-based`,projectConfig:!0,recorded:!1},{key:`steps`,names:[`--steps`],type:`string`,usageLabel:`--steps <json>`,usageDescription:`Batch: JSON array of {"command","input"} steps`,projectConfig:!1,recorded:!1},{key:`stepsFile`,names:[`--steps-file`],type:`string`,usageLabel:`--steps-file <path>`,usageDescription:`Batch: read steps JSON from file`,projectConfig:!1,recorded:!1},{key:`batchOnError`,names:[`--on-error`],type:`enum`,enumValues:[`stop`],usageLabel:`--on-error stop`,usageDescription:`Batch: stop when a step fails`,projectConfig:!0,recorded:!1},{key:`batchMaxSteps`,names:[`--max-steps`],type:`int`,min:1,max:1e3,usageLabel:`--max-steps <n>`,usageDescription:`Batch: maximum number of allowed steps`,projectConfig:!0,recorded:!1},{key:`appsFilter`,names:[`--all`],type:`enum`,enumValues:[`user-installed`,`all`],setValue:`all`,usageLabel:`--all`,usageDescription:`Apps: include system/OEM apps`,projectConfig:!0,recorded:!1},{key:`snapshotInteractiveOnly`,names:[`-i`],type:`boolean`,usageLabel:`-i`,usageDescription:`Snapshot: interactive elements only`,projectConfig:!0,recorded:!0},{key:`snapshotDepth`,names:[`--depth`,`-d`],type:`int`,min:0,usageLabel:`--depth, -d <depth>`,usageDescription:`Snapshot: limit snapshot depth`,projectConfig:!0,recorded:!0},{key:`snapshotScope`,names:[`--scope`,`-s`],type:`string`,usageLabel:`--scope, -s <scope>`,usageDescription:`Snapshot: scope snapshot to label/identifier`,projectConfig:!0,recorded:!0},{key:`snapshotRaw`,names:[`--raw`],type:`boolean`,usageLabel:`--raw`,usageDescription:`Snapshot: raw node output`,projectConfig:!0,recorded:!0},{key:`snapshotCustomActions`,names:[`--actions`],type:`boolean`,usageLabel:`--actions`,usageDescription:`Snapshot: name the affordances merged inside an element (iOS sim); not directly invokable — reach them via the detail screen, labeled children, or coordinates`,inputDescription:`Name the affordances an element merged away (iOS UIAccessibilityCustomAction, React Native accessibilityActions) — a card whose reply/options controls are not separate elements still lists them here. The names are for PLANNING, not invocation: there is no API to trigger them, so reach the affordance through the element detail screen, through the same control exposed as a labeled element elsewhere, or by coordinates from its rect. iOS simulator only; costs one accessibility round trip per merged element.`,projectConfig:!0,recorded:!0},{key:`snapshotForceFull`,names:[`--force-full`],type:`boolean`,usageLabel:`--force-full`,usageDescription:`Snapshot: re-emit the full tree even when unchanged`,projectConfig:!0,recorded:!1},{key:`findFirst`,names:[`--first`],type:`boolean`,usageLabel:`--first`,usageDescription:`Find: pick the first match when ambiguous`,projectConfig:!0,recorded:!1},{key:`findLast`,names:[`--last`],type:`boolean`,usageLabel:`--last`,usageDescription:`Find: pick the last match when ambiguous`,projectConfig:!0,recorded:!1},{key:`out`,names:[`--out`],type:`string`,usageLabel:`--out <path>`,usageDescription:`Output path`,projectConfig:!1,recorded:!0},{key:`artifact`,names:[`--artifact`],type:`string`,usageLabel:`--artifact <path>`,usageDescription:`Debug symbols: Apple crash artifact path (.ips, .crash, or .log)`,projectConfig:!1,recorded:!1},{key:`dsym`,names:[`--dsym`],type:`string`,usageLabel:`--dsym <path>`,usageDescription:`Debug symbols: matching .dSYM bundle path`,projectConfig:!1,recorded:!1},{key:`searchPath`,names:[`--search-path`],type:`string`,usageLabel:`--search-path <dir>`,usageDescription:`Debug symbols: directory to scan for matching .dSYM bundles`,projectConfig:!1,recorded:!1},{key:`overlayRefs`,names:[`--overlay-refs`],type:`boolean`,usageLabel:`--overlay-refs`,usageDescription:`Screenshot: draw current snapshot refs and target rectangles onto the saved PNG; diff screenshot: also write a separate current-screen overlay guide`,projectConfig:!0,recorded:!1},...n,{key:`baseline`,names:[`--baseline`,`-b`],type:`string`,usageLabel:`--baseline, -b <path>`,usageDescription:`Diff screenshot: path to baseline image file`,projectConfig:!0,recorded:!1},{key:`threshold`,names:[`--threshold`],type:`string`,usageLabel:`--threshold <0-1>`,usageDescription:`Diff screenshot: color distance threshold (default 0.1)`,projectConfig:!0,recorded:!1}],f=[...l,...u,...c,...d],p=new Map;for(let e of f)for(let t of e.names)p.set(t,e);function m(e){return p.get(e)}function h(){return f}function g(e){return f.filter(t=>t.key===e)}function _(){return new Set(f.filter(e=>e.projectConfig).map(e=>e.key))}function v(){return new Set(f.filter(e=>e.recorded).map(e=>e.key))}const y=[`in-app`,`system`];export{_ as a,g as i,m as n,v as o,h as r,y as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{O as e,S as t,m as n,w as r}from"./owner-identity.js";import{d as i}from"./exec.js";import"./command.js";import"./process.js";import{a,c as o,d as s,f as c,h as l,i as u,l as d,m as f,o as p,p as m,r as h,s as g,t as _,u as v}from"./base-url.js";import{createHash as y}from"node:crypto";import b from"node:fs";import x from"node:path";import{fileURLToPath as S}from"node:url";const C=`companion-tunnel`;function w(e){return y(`sha256`).update(e).digest(`hex`)}function T(e){return e?.trim()?e.trim():void 0}function E(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(typeof t.tenantId==`string`&&typeof t.runId==`string`&&typeof t.leaseId==`string`)return{tenantId:t.tenantId,runId:t.runId,leaseId:t.leaseId}}function D(e,t){return e.tenantId===t.tenantId&&e.runId===t.runId&&e.leaseId===t.leaseId}function O(e,t,n,r){let i=r??x.join(e,`.agent-device`);if(!n)return{statePath:x.join(i,`${t.slug}.json`),logPath:x.join(i,`${t.slug}.log`)};let a=w(n).slice(0,12),o=x.join(i,t.slug);return{statePath:x.join(o,`${t.slug}-${a}.json`),logPath:x.join(o,`${t.slug}-${a}.log`)}}function k(e){try{let t=JSON.parse(b.readFileSync(e,`utf8`));if(!Number.isInteger(t.pid)||Number(t.pid)<=0||typeof t.serverBaseUrl!=`string`||typeof t.localBaseUrl!=`string`||typeof t.tokenHash!=`string`||t.tokenHash.length===0)return null;let n=Array.isArray(t.consumers)?t.consumers.filter(e=>typeof e==`string`&&e.length>0):[];return{pid:Number(t.pid),startTime:typeof t.startTime==`string`?t.startTime:void 0,command:typeof t.command==`string`?t.command:void 0,serverBaseUrl:t.serverBaseUrl,localBaseUrl:t.localBaseUrl,launchUrl:T(typeof t.launchUrl==`string`?t.launchUrl:void 0),registerPath:T(typeof t.registerPath==`string`?t.registerPath:void 0),unregisterPath:T(typeof t.unregisterPath==`string`?t.unregisterPath:void 0),devicePort:Number.isInteger(t.devicePort)?Number(t.devicePort):void 0,session:T(typeof t.session==`string`?t.session:void 0),bridgeScope:E(t.bridgeScope),tokenHash:t.tokenHash,consumers:n}}catch{return null}}function A(e,t){b.mkdirSync(x.dirname(e),{recursive:!0}),b.writeFileSync(e,`${JSON.stringify(t,null,2)}\n`,`utf8`)}function j(e){b.mkdirSync(x.dirname(e),{recursive:!0}),b.closeSync(b.openSync(e,`a`))}function M(e){try{b.unlinkSync(e)}catch{}}function N(e){try{b.unlinkSync(e)}catch{}}function P(e){try{b.readdirSync(e).length===0&&b.rmdirSync(e)}catch{}}function F(e,t){let n=x.dirname(e.statePath),r=x.dirname(e.logPath);M(e.statePath),N(e.logPath),P(n),r!==n&&P(r),x.basename(n)===t.slug&&P(x.dirname(n))}function I(e,t){return e.includes(t.runArg)}function L(e,i){if(!n(e.pid))return!1;if(e.startTime){let t=r(e.pid);if(!t||t!==e.startTime)return!1}let a=t(e.pid);return!a||!I(a,i.definition)||!e.bridgeScope?!1:e.serverBaseUrl===_(i.serverBaseUrl)&&e.localBaseUrl===_(i.localBaseUrl)&&e.launchUrl===T(i.launchUrl)&&e.registerPath===T(i.registerPath)&&e.unregisterPath===T(i.unregisterPath)&&e.devicePort===i.devicePort&&e.session===T(i.session)&&D(e.bridgeScope,i.bridgeScope)&&e.tokenHash===w(i.bearerToken)}function R(e){return T(e.consumerKey)??T(e.profileKey)??null}function z(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}function B(e,t){return t?{...e,consumers:e.consumers.filter(e=>e!==t)}:{...e,consumers:[]}}async function V(r,i){if(!n(r.pid))return;let a=t(r.pid);if(!(!a||!I(a,i))){try{process.kill(r.pid,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await e(r.pid,1e3)){try{process.kill(r.pid,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await e(r.pid,1e3)}}}function H(e,t){let n={...t};return n[s]=_(e.serverBaseUrl),n[h]=e.bearerToken,n[p]=_(e.localBaseUrl),n[m]=O(e.projectRoot,e.definition,e.profileKey,e.stateDir).statePath,n[v]=e.bridgeScope.tenantId,n[d]=e.bridgeScope.runId,n[o]=e.bridgeScope.leaseId,e.launchUrl?.trim()?n[a]=e.launchUrl.trim():delete n[a],e.registerPath?.trim()?n[g]=e.registerPath.trim():delete n[g],e.unregisterPath?.trim()?n[f]=e.unregisterPath.trim():delete n[f],e.devicePort===void 0?delete n[u]:n[u]=String(e.devicePort),e.session?.trim()?n[c]=e.session.trim():delete n[c],n}function U(e){let t=S(import.meta.url),n=x.extname(t)||`.js`,r=[x.join(x.dirname(t),`${C}${n}`),x.join(x.dirname(t),`internal`,`${C}${n}`)].find(e=>b.existsSync(e));if(!r)throw Error(`${e.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return r}function W(e,n){let a=U(e.definition),o=a.endsWith(`.ts`)?[`--experimental-strip-types`]:[];b.mkdirSync(x.dirname(n),{recursive:!0});let s=b.openSync(n,`a`),c=0;try{c=i(process.execPath,[...o,a,e.definition.runArg],{env:H(e,e.env??process.env),stdio:[`ignore`,s,s]})}finally{b.closeSync(s)}if(!Number.isInteger(c)||c<=0)throw Error(`Failed to start ${e.definition.displayName} process.`);return{pid:c,startTime:r(c)??void 0,command:t(c)??void 0,serverBaseUrl:_(e.serverBaseUrl),localBaseUrl:_(e.localBaseUrl),launchUrl:T(e.launchUrl),registerPath:T(e.registerPath),unregisterPath:T(e.unregisterPath),devicePort:e.devicePort,session:T(e.session),bridgeScope:e.bridgeScope,tokenHash:w(e.bearerToken),consumers:[]}}async function G(e){let t=R(e),n=O(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=k(n.statePath);if(r&&L(r,e)){let e=z(r,t);return e!==r&&A(n.statePath,e),{pid:r.pid,spawned:!1,statePath:n.statePath,logPath:n.logPath}}r&&(await V(r,e.definition),F(n,e.definition)),j(n.statePath);let i;try{i=W(e,n.logPath),A(n.statePath,z(i,t))}catch(t){throw i&&await V(i,e.definition).catch(()=>{}),F(n,e.definition),t}return{pid:i.pid,spawned:!0,statePath:n.statePath,logPath:n.logPath}}async function K(e){let t=R(e),n=O(e.projectRoot,e.definition,e.profileKey,e.stateDir),r=k(n.statePath);if(!r)return F(n,e.definition),{stopped:!1,statePath:n.statePath};let i=B(r,t);return i.consumers.length>0?(A(n.statePath,i),{stopped:!1,statePath:n.statePath}):(await V(r,e.definition),F(n,e.definition),{stopped:!0,statePath:n.statePath})}const q={slug:`metro-companion`,runArg:l,displayName:`Metro companion`};async function J(e){return await G({...e,definition:q,registerPath:e.registerPath??`/api/metro/companion/register`})}async function Y(e){return await K({...e,definition:q})}export{K as i,Y as n,G as r,J as t};
|
package/dist/src/client-metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e,P as t}from"./sdk-contracts.js";import{D as n}from"./owner-identity.js";import{n as r}from"./path-resolution.js";import{d as i,m as a}from"./exec.js";import{t as o}from"./timeouts.js";import"./file.js";import"./command.js";import"./process.js";import"./retry.js";import{t as s}from"./base-url.js";import{t as c}from"./client-metro-companion.js";import{n as l,r as u}from"./project-runtime.js";import{t as d}from"./runtime-transport-hints.js";import f from"node:fs";import p from"node:path";function m(e,t,n=`index.bundle`){let r=new URL(`${s(e)}/${n}`);return r.searchParams.set(`platform`,t),r.searchParams.set(`dev`,`true`),r.searchParams.set(`minify`,`false`),r.toString()}const h=8081,g=`.expo/.virtual-metro-entry.bundle`;function _(e,n){if(e==null||e===``)return n;let r=Number.parseInt(String(e),10);if(!Number.isInteger(r)||r<1||r>65535)throw new t(`INVALID_ARGS`,`Invalid Metro port: ${String(e)}. Use 1-65535.`);return r}function v(e){let n=S(e.bundleUrl),r=n??e.runtime?.bundleUrl,i=!!n,a=!!S(r),o=d({metroHost:y(e,i,a),metroPort:b(e,i,a),bundleUrl:r});if(!o)throw new t(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=ee(r);return{reloadUrl:x(o,o.scheme,`${s}/reload`),messageSocketUrl:x(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function y(e,t,n){return S(e.metroHost)??(t?void 0:S(e.runtime?.metroHost))??(n?void 0:`localhost`)}function b(e,t,n){if(e.metroPort!==void 0)return _(e.metroPort,h);if(!t)return e.runtime?.metroPort??(n?void 0:h)}function ee(e){let t=S(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${g}`;if(r.endsWith(i))return r.slice(0,-i.length);let a=r.lastIndexOf(`/`);return(a>=0?r.slice(a+1):r).endsWith(`.bundle`)&&a>0?r.slice(0,a):``}function x(e,t,n){let r=new URL(`${t}://localhost`);return r.hostname=e.host,r.port=String(e.port),r.pathname=n,r.toString()}function S(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function C(e){return typeof e==`string`&&e.trim()?s(e.trim()):``}function w(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function T(e,t,n){return r(e,{env:t,cwd:n})}function E(e){try{return f.accessSync(e,f.constants.F_OK),!0}catch{return!1}}function D(e){try{return f.statSync(e).isDirectory()}catch{return!1}}function O(e){let n=p.join(e,`package.json`),r=u(e);if(!r)throw new t(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const k=[{file:`pnpm-lock.yaml`,command:`pnpm`},{file:`yarn.lock`,command:`yarn`},{file:`bun.lock`,command:`bun`},{file:`bun.lockb`,command:`bun`},{file:`package-lock.json`,command:`npm`}];function te(e){let t=e;for(;;){for(let{file:e,command:n}of k)if(E(p.join(t,e)))return{command:n,installArgs:[`install`]};if(E(p.join(t,`.git`)))return null;let e=p.dirname(t);if(e===t)return null;t=e}}function A(e){return te(e)??{command:`npm`,installArgs:[`install`]}}function j(e,t){if(t!==`auto`)return t;let n=l(e);return n===`expo`||n===`repack`?n:`react-native`}function M(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function N(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>E(p.join(e,`${t}.config.${n}`)))}function P(e,t){return N(e,`rspack`)?`rspack`:N(e,`webpack`)?`webpack`:M(t,`@rspack/core`)?`rspack`:M(t,`webpack`)?`webpack`:`rspack`}function F(e,t,n){if(e==null||e===``)return t;let r=Number.parseInt(String(e),10);return Number.isInteger(r)?Math.max(r,n):t}function ne(e){return e===`expo`?g:`index.bundle`}function I(e,t,n){return{platform:t,bundleUrl:m(e,t,ne(n))}}function L(e,t){return{platform:t,metroHost:w(e?.metro_host),metroPort:e?.metro_port,bundleUrl:w(e?.metro_bundle_url),launchUrl:w(e?.launch_url)}}function R(e,t){if(D(p.join(e,`node_modules`)))return{installed:!1};let n=A(e);try{a(n.command,n.installArgs,{cwd:e,env:t})}catch(e){throw z(e,n)}return{installed:!0,packageManager:n.command}}function z(n,r){let i=e(n),a=`Dependency install failed using detected package manager "${r.command}". If dependencies are already installed (for example via a monorepo root install), pass --no-install-deps to skip this step, or install manually with "${r.command} ${r.installArgs.join(` `)}" from the project root.`;return new t(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function B(e){await o(e)}async function V(e,n,r={}){try{let t=await fetch(e,{headers:r,signal:AbortSignal.timeout(n)});return{ok:t.ok,status:t.status,body:await t.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new t(`COMMAND_FAILED`,`Timed out fetching ${e} after ${n}ms`):r}}async function H(e,t){try{let n=await V(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function U(e,t,n,r){return e===`expo`?{command:`npx`,installArgs:[`expo`,`start`,`--host`,`lan`,`--port`,String(n)]}:e===`repack`?{command:`npx`,installArgs:[`react-native`,t===`webpack`?`webpack-start`:`rspack-start`,`--host`,r,`--port`,String(n)]}:{command:`npx`,installArgs:[`react-native`,`start`,`--host`,r,`--port`,String(n)]}}function W(e,n,r,a,o,s,c){let l=U(n,r,a,o);f.mkdirSync(p.dirname(s),{recursive:!0});let u=f.openSync(s,`a`),d=0;try{d=i(l.command,l.installArgs,{cwd:e,env:c,stdio:[`ignore`,u,u]})}finally{f.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new t(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function G(e){if(!(!Number.isInteger(e)||e<=0)){try{process.kill(e,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await n(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await n(e,1e3)}}}function K(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function q(e,n){let r=new t(`COMMAND_FAILED`,e);return r.retryable=n,r}function J(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function Y(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function X(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:K(e.baseUrl,e.bearerToken),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){throw t instanceof Error&&t.name===`TimeoutError`?q(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):q(t instanceof Error?t.message:String(t),!0)}let n=Z(await t.text(),t.status,e.baseUrl);if(!t.ok)throw q(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,J(t.status,n));return ie(n)}function Z(e,t,n){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Expected a JSON object`);return t}catch(r){let i=e.slice(0,200);throw q(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,J(t,e))}}function re(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:L(e.ios_runtime,`ios`),androidRuntime:L(e.android_runtime,`android`),upstream:{bundleUrl:e.upstream.bundle_url??``,host:e.upstream.host??``,port:e.upstream.port??0,statusUrl:e.upstream.status_url??``},probe:{reachable:e.probe.reachable,statusCode:e.probe.status_code,latencyMs:e.probe.latency_ms,detail:e.probe.detail}}}function ie(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw q(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return re(t)}catch(e){throw q(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function Q(e,t,n,r,i){let a=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&a.push(`bridgeError=${t}`),n?.probe.reachable===!1&&a.push(`bridgeProbe=${n.probe.detail||`unreachable (status ${n.probe.statusCode||0})`}`),r&&r!==t&&a.push(`initialBridgeError=${r}`),i&&a.push(`metroCompanionLog=${i}`),a.join(` `)}function ae(e,n){if(!n?.iosRuntime.bundleUrl)throw new t(`COMMAND_FAILED`,Q(e,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function oe(e,n,r){let i=n||w(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||e&&w(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(e&&!a)throw new t(`INVALID_ARGS`,`metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_METRO_BEARER_TOKEN or AGENT_DEVICE_DAEMON_AUTH_TOKEN.`);if(!e&&i)throw new t(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(e&&a),proxyBaseUrl:e,proxyBearerToken:a}}function se(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new t(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return e}function ce(e,n){if(!(e||n))throw new t(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function le(e,t,n){return e.runtimeFilePath?T(e.runtimeFilePath,t,n):null}function ue(e,t,n,r){return T(e.logPath??p.join(r,`.agent-device`,`metro.log`),t,n)}function $(e){let t=e.env??process.env,n=process.cwd(),r=T(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=O(r),o=j(a,i)):o=i;let s=null;o===`repack`&&(a??=O(r),s=P(r,a));let c=C(e.publicBaseUrl),l=C(e.proxyBaseUrl);ce(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=oe(l,w(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:_(e.metroPort??8081,8081),listenHost:w(e.listenHost)??`0.0.0.0`,statusHost:w(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?se(e.bridgeScope):null,startupTimeoutMs:F(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:F(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:le(e,t,n),logPath:ue(e,t,n,r)}}async function de(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await H(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await B(i)}return!1}async function fe(e){let n=Date.now()+e.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let t=await X({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(t.probe.reachable!==!1)return t;r=t,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!Y(n))throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await B(a)}throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath))}async function pe(e){let n=`http://${e.statusHost}:${e.metroPort}/status`;if(e.reuseExisting&&await H(n,e.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=W(e.projectRoot,e.kind,e.repackBundler,e.metroPort,e.listenHost,e.logPath,e.env);if(await de(n,e.startupTimeoutMs,e.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await G(r.pid).catch(()=>{}),new t(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${e.startupTimeoutMs}ms. Check ${e.logPath}.`,{logPath:e.logPath})}async function me(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await X({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!Y(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await he(e,t,n,r,i)),ae(t.proxyBaseUrl,r),r}async function he(e,n,r,i,a){let o;try{o=(await c({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:w(e.launchUrl),profileKey:w(e.companionProfileKey),consumerKey:w(e.companionConsumerKey),env:n.env})).logPath}catch(e){throw new t(`COMMAND_FAILED`,Q(n.proxyBaseUrl,e instanceof Error?e.message:String(e),i,a),void 0,e)}try{return await fe({baseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,scope:r,probeTimeoutMs:n.probeTimeoutMs,startupTimeoutMs:n.startupTimeoutMs,initialBridgeError:a,companionLogPath:o})}catch(e){throw e instanceof Error?e:Error(String(e))}}function ge(e,t){return{baseIosRuntime:e?I(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?I(e,`android`,t):{platform:`android`}}}function _e(e,t){e&&(f.mkdirSync(p.dirname(e),{recursive:!0}),f.writeFileSync(e,JSON.stringify(t,null,2)))}async function ve(e={}){let t=$(e),n=t.installProjectDeps?R(t.projectRoot,t.env):{installed:!1},r=await pe(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ge(t.publicBaseUrl,t.kind),o=await me(e,t),s=o?.iosRuntime??i,c=o?.androidRuntime??a,l={projectRoot:t.projectRoot,kind:t.kind,dependenciesInstalled:n.installed,packageManager:n.packageManager??null,started:r.started,reused:r.reused,pid:r.pid,logPath:t.logPath,statusUrl:r.statusUrl,runtimeFilePath:t.runtimeFilePath,iosRuntime:s,androidRuntime:c,bridge:o};return _e(t.runtimeFilePath,l),l}function ye(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function be(e,n){await new Promise((r,i)=>{let a=new WebSocket(e),o=e=>{clearTimeout(s);try{a.close()}catch{}i(new t(`COMMAND_FAILED`,e))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${e} after ${n}ms`)},n);a.addEventListener(`open`,()=>{a.send(JSON.stringify({version:2,method:`reload`}));let e=()=>{if(a.bufferedAmount===0){clearTimeout(s),a.close(),r();return}setTimeout(e,20)};e()}),a.addEventListener(`error`,()=>{o(`Failed to reach the dev server message socket at ${e}`)})})}async function xe(e={}){let n=F(e.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=v(e),a=await V(r,n);if(a.ok&&!ye(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await be(i,n)}catch(e){throw new t(`COMMAND_FAILED`,`React Native dev server reload failed (${a.status}).`,{reloadUrl:r,status:a.status,body:a.body.slice(0,500),messageSocketUrl:i,hint:`Verify Metro or Re.Pack is running and the target React Native app is connected to this dev server instance.`},e instanceof Error?e:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{xe as n,m as r,ve as t};
|
|
1
|
+
import{F as e,P as t}from"./sdk-contracts.js";import{O as n}from"./owner-identity.js";import{n as r}from"./path-resolution.js";import{d as i,m as a}from"./exec.js";import{t as o}from"./timeouts.js";import"./file.js";import"./command.js";import"./process.js";import"./retry.js";import{t as s}from"./base-url.js";import{t as c}from"./client-metro-companion.js";import{n as l,r as u}from"./project-runtime.js";import{t as d}from"./runtime-transport-hints.js";import f from"node:fs";import p from"node:path";function m(e,t,n=`index.bundle`){let r=new URL(`${s(e)}/${n}`);return r.searchParams.set(`platform`,t),r.searchParams.set(`dev`,`true`),r.searchParams.set(`minify`,`false`),r.toString()}const h=8081,g=`.expo/.virtual-metro-entry.bundle`;function _(e,n){if(e==null||e===``)return n;let r=Number.parseInt(String(e),10);if(!Number.isInteger(r)||r<1||r>65535)throw new t(`INVALID_ARGS`,`Invalid Metro port: ${String(e)}. Use 1-65535.`);return r}function v(e){let n=S(e.bundleUrl),r=n??e.runtime?.bundleUrl,i=!!n,a=!!S(r),o=d({metroHost:y(e,i,a),metroPort:b(e,i,a),bundleUrl:r});if(!o)throw new t(`INVALID_ARGS`,`Unable to resolve Metro host and port for reload.`);let s=ee(r);return{reloadUrl:x(o,o.scheme,`${s}/reload`),messageSocketUrl:x(o,o.scheme===`https`?`wss`:`ws`,`${s}/message`)}}function y(e,t,n){return S(e.metroHost)??(t?void 0:S(e.runtime?.metroHost))??(n?void 0:`localhost`)}function b(e,t,n){if(e.metroPort!==void 0)return _(e.metroPort,h);if(!t)return e.runtime?.metroPort??(n?void 0:h)}function ee(e){let t=S(e);if(!t)return``;let n;try{n=new URL(t)}catch{return``}let r=n.pathname.replace(/\/+$/,``),i=`/${g}`;if(r.endsWith(i))return r.slice(0,-i.length);let a=r.lastIndexOf(`/`);return(a>=0?r.slice(a+1):r).endsWith(`.bundle`)&&a>0?r.slice(0,a):``}function x(e,t,n){let r=new URL(`${t}://localhost`);return r.hostname=e.host,r.port=String(e.port),r.pathname=n,r.toString()}function S(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function C(e){return typeof e==`string`&&e.trim()?s(e.trim()):``}function w(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function T(e,t,n){return r(e,{env:t,cwd:n})}function E(e){try{return f.accessSync(e,f.constants.F_OK),!0}catch{return!1}}function D(e){try{return f.statSync(e).isDirectory()}catch{return!1}}function O(e){let n=p.join(e,`package.json`),r=u(e);if(!r)throw new t(`INVALID_ARGS`,`package.json not found at ${n}`);return r}const k=[{file:`pnpm-lock.yaml`,command:`pnpm`},{file:`yarn.lock`,command:`yarn`},{file:`bun.lock`,command:`bun`},{file:`bun.lockb`,command:`bun`},{file:`package-lock.json`,command:`npm`}];function te(e){let t=e;for(;;){for(let{file:e,command:n}of k)if(E(p.join(t,e)))return{command:n,installArgs:[`install`]};if(E(p.join(t,`.git`)))return null;let e=p.dirname(t);if(e===t)return null;t=e}}function A(e){return te(e)??{command:`npm`,installArgs:[`install`]}}function j(e,t){if(t!==`auto`)return t;let n=l(e);return n===`expo`||n===`repack`?n:`react-native`}function M(e,t){return typeof{...e.dependencies??{},...e.devDependencies??{}}[t]==`string`}function N(e,t){return[`js`,`mjs`,`cjs`,`ts`,`mts`,`cts`].some(n=>E(p.join(e,`${t}.config.${n}`)))}function P(e,t){return N(e,`rspack`)?`rspack`:N(e,`webpack`)?`webpack`:M(t,`@rspack/core`)?`rspack`:M(t,`webpack`)?`webpack`:`rspack`}function F(e,t,n){if(e==null||e===``)return t;let r=Number.parseInt(String(e),10);return Number.isInteger(r)?Math.max(r,n):t}function ne(e){return e===`expo`?g:`index.bundle`}function I(e,t,n){return{platform:t,bundleUrl:m(e,t,ne(n))}}function L(e,t){return{platform:t,metroHost:w(e?.metro_host),metroPort:e?.metro_port,bundleUrl:w(e?.metro_bundle_url),launchUrl:w(e?.launch_url)}}function R(e,t){if(D(p.join(e,`node_modules`)))return{installed:!1};let n=A(e);try{a(n.command,n.installArgs,{cwd:e,env:t})}catch(e){throw z(e,n)}return{installed:!0,packageManager:n.command}}function z(n,r){let i=e(n),a=`Dependency install failed using detected package manager "${r.command}". If dependencies are already installed (for example via a monorepo root install), pass --no-install-deps to skip this step, or install manually with "${r.command} ${r.installArgs.join(` `)}" from the project root.`;return new t(i.code,i.message,{...i.details??{},hint:a,packageManager:r.command},i)}async function B(e){await o(e)}async function V(e,n,r={}){try{let t=await fetch(e,{headers:r,signal:AbortSignal.timeout(n)});return{ok:t.ok,status:t.status,body:await t.text()}}catch(r){throw r instanceof Error&&r.name===`TimeoutError`?new t(`COMMAND_FAILED`,`Timed out fetching ${e} after ${n}ms`):r}}async function H(e,t){try{let n=await V(e,t);return n.ok&&n.body.includes(`packager-status:running`)}catch{return!1}}function U(e,t,n,r){return e===`expo`?{command:`npx`,installArgs:[`expo`,`start`,`--host`,`lan`,`--port`,String(n)]}:e===`repack`?{command:`npx`,installArgs:[`react-native`,t===`webpack`?`webpack-start`:`rspack-start`,`--host`,r,`--port`,String(n)]}:{command:`npx`,installArgs:[`react-native`,`start`,`--host`,r,`--port`,String(n)]}}function W(e,n,r,a,o,s,c){let l=U(n,r,a,o);f.mkdirSync(p.dirname(s),{recursive:!0});let u=f.openSync(s,`a`),d=0;try{d=i(l.command,l.installArgs,{cwd:e,env:c,stdio:[`ignore`,u,u]})}finally{f.closeSync(u)}if(!Number.isInteger(d)||d<=0)throw new t(`COMMAND_FAILED`,`Failed to start React Native dev server. Expected a detached child PID.`);return{pid:d}}async function G(e){if(!(!Number.isInteger(e)||e<=0)){try{process.kill(e,`SIGTERM`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}if(!await n(e,1e3)){try{process.kill(e,`SIGKILL`)}catch(e){let t=e.code;if(t===`ESRCH`||t===`EPERM`)return;throw e}await n(e,1e3)}}}function K(e,t){return{Authorization:`Bearer ${t}`,"Content-Type":`application/json`,...e.includes(`ngrok`)?{"ngrok-skip-browser-warning":`1`}:{}}}function q(e,n){let r=new t(`COMMAND_FAILED`,e);return r.retryable=n,r}function J(e,t){return!!(e>=500||e===408||e===425||e===429||JSON.stringify(t).includes(`Metro companion is not connected`))}function Y(e){return!!(e&&typeof e==`object`&&`retryable`in e&&e.retryable===!0)}async function X(e){let t;try{t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:`POST`,headers:K(e.baseUrl,e.bearerToken),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){throw t instanceof Error&&t.name===`TimeoutError`?q(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0):q(t instanceof Error?t.message:String(t),!0)}let n=Z(await t.text(),t.status,e.baseUrl);if(!t.ok)throw q(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(n)}`,J(t.status,n));return ie(n)}function Z(e,t,n){if(!e)return{};try{let t=JSON.parse(e);if(!t||typeof t!=`object`||Array.isArray(t))throw Error(`Expected a JSON object`);return t}catch(r){let i=e.slice(0,200);throw q(`/api/metro/bridge returned invalid JSON (${t}) from ${n}: ${r instanceof Error?r.message:String(r)}. body=${JSON.stringify(i)}`,J(t,e))}}function re(e){return{enabled:e.enabled,baseUrl:e.base_url,statusUrl:e.status_url??``,bundleUrl:e.bundle_url??``,iosRuntime:L(e.ios_runtime,`ios`),androidRuntime:L(e.android_runtime,`android`),upstream:{bundleUrl:e.upstream.bundle_url??``,host:e.upstream.host??``,port:e.upstream.port??0,statusUrl:e.upstream.status_url??``},probe:{reachable:e.probe.reachable,statusCode:e.probe.status_code,latencyMs:e.probe.latency_ms,detail:e.probe.detail}}}function ie(e){let t=e.data??e;if(!t||typeof t!=`object`||Array.isArray(t))throw q(`/api/metro/bridge returned malformed descriptor: Expected a JSON object.`,!1);try{return re(t)}catch(e){throw q(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function Q(e,t,n,r,i){let a=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&a.push(`bridgeError=${t}`),n?.probe.reachable===!1&&a.push(`bridgeProbe=${n.probe.detail||`unreachable (status ${n.probe.statusCode||0})`}`),r&&r!==t&&a.push(`initialBridgeError=${r}`),i&&a.push(`metroCompanionLog=${i}`),a.join(` `)}function ae(e,n){if(!n?.iosRuntime.bundleUrl)throw new t(`COMMAND_FAILED`,Q(e,`bridge descriptor is missing ios_runtime.metro_bundle_url`,n))}function oe(e,n,r){let i=n||w(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||``,a=i||e&&w(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||``;if(e&&!a)throw new t(`INVALID_ARGS`,`metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_METRO_BEARER_TOKEN or AGENT_DEVICE_DAEMON_AUTH_TOKEN.`);if(!e&&i)throw new t(`INVALID_ARGS`,`metro prepare requires --proxy-base-url when proxy auth is provided.`);return{proxyEnabled:!!(e&&a),proxyBaseUrl:e,proxyBearerToken:a}}function se(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new t(`INVALID_ARGS`,`metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.`);return e}function ce(e,n){if(!(e||n))throw new t(`INVALID_ARGS`,`metro prepare requires --public-base-url <url> or --proxy-base-url <url>.`)}function le(e,t,n){return e.runtimeFilePath?T(e.runtimeFilePath,t,n):null}function ue(e,t,n,r){return T(e.logPath??p.join(r,`.agent-device`,`metro.log`),t,n)}function $(e){let t=e.env??process.env,n=process.cwd(),r=T(e.projectRoot??n,t,n),i=e.kind??`auto`,a=null,o;i===`auto`?(a=O(r),o=j(a,i)):o=i;let s=null;o===`repack`&&(a??=O(r),s=P(r,a));let c=C(e.publicBaseUrl),l=C(e.proxyBaseUrl);ce(c,l);let{proxyEnabled:u,proxyBaseUrl:d,proxyBearerToken:f}=oe(l,w(e.proxyBearerToken)??``,t);return{env:t,projectRoot:r,kind:o,repackBundler:s,metroPort:_(e.metroPort??8081,8081),listenHost:w(e.listenHost)??`0.0.0.0`,statusHost:w(e.statusHost)??`127.0.0.1`,publicBaseUrl:c,proxyBaseUrl:d,proxyBearerToken:f,bridgeScope:u?se(e.bridgeScope):null,startupTimeoutMs:F(e.startupTimeoutMs,18e4,3e4),probeTimeoutMs:F(e.probeTimeoutMs,1e4,1e3),reuseExisting:e.reuseExisting??!0,installProjectDeps:e.installDependenciesIfNeeded??!0,runtimeFilePath:le(e,t,n),logPath:ue(e,t,n,r)}}async function de(e,t,n){let r=Date.now()+t;for(;Date.now()<r;){let t=r-Date.now();if(await H(e,Math.min(n,Math.max(t,1))))return!0;let i=Math.min(500,Math.max(r-Date.now(),0));i>0&&await B(i)}return!1}async function fe(e){let n=Date.now()+e.startupTimeoutMs,r=null,i=null;for(;Date.now()<n;){try{let t=await X({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(t.probe.reachable!==!1)return t;r=t,i=null}catch(n){if(i=n instanceof Error?n.message:String(n),!Y(n))throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath),void 0,n)}let a=Math.min(1e3,Math.max(n-Date.now(),0));a>0&&await B(a)}throw new t(`COMMAND_FAILED`,Q(e.baseUrl,i,r,e.initialBridgeError,e.companionLogPath))}async function pe(e){let n=`http://${e.statusHost}:${e.metroPort}/status`;if(e.reuseExisting&&await H(n,e.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let r=W(e.projectRoot,e.kind,e.repackBundler,e.metroPort,e.listenHost,e.logPath,e.env);if(await de(n,e.startupTimeoutMs,e.probeTimeoutMs))return{started:!0,reused:!1,pid:r.pid,statusUrl:n};throw await G(r.pid).catch(()=>{}),new t(`COMMAND_FAILED`,`React Native dev server did not become ready at ${n} within ${e.startupTimeoutMs}ms. Check ${e.logPath}.`,{logPath:e.logPath})}async function me(e,t){let n=t.bridgeScope;if(!n)return null;let r=null,i=null;try{r=await X({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:n,timeoutMs:t.probeTimeoutMs})}catch(e){if(!Y(e))throw e;i=e instanceof Error?e.message:String(e)}return(!r||r.probe.reachable===!1)&&(r=await he(e,t,n,r,i)),ae(t.proxyBaseUrl,r),r}async function he(e,n,r,i,a){let o;try{o=(await c({projectRoot:n.projectRoot,serverBaseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${n.statusHost}:${n.metroPort}`,launchUrl:w(e.launchUrl),profileKey:w(e.companionProfileKey),consumerKey:w(e.companionConsumerKey),env:n.env})).logPath}catch(e){throw new t(`COMMAND_FAILED`,Q(n.proxyBaseUrl,e instanceof Error?e.message:String(e),i,a),void 0,e)}try{return await fe({baseUrl:n.proxyBaseUrl,bearerToken:n.proxyBearerToken,scope:r,probeTimeoutMs:n.probeTimeoutMs,startupTimeoutMs:n.startupTimeoutMs,initialBridgeError:a,companionLogPath:o})}catch(e){throw e instanceof Error?e:Error(String(e))}}function ge(e,t){return{baseIosRuntime:e?I(e,`ios`,t):{platform:`ios`},baseAndroidRuntime:e?I(e,`android`,t):{platform:`android`}}}function _e(e,t){e&&(f.mkdirSync(p.dirname(e),{recursive:!0}),f.writeFileSync(e,JSON.stringify(t,null,2)))}async function ve(e={}){let t=$(e),n=t.installProjectDeps?R(t.projectRoot,t.env):{installed:!1},r=await pe(t),{baseIosRuntime:i,baseAndroidRuntime:a}=ge(t.publicBaseUrl,t.kind),o=await me(e,t),s=o?.iosRuntime??i,c=o?.androidRuntime??a,l={projectRoot:t.projectRoot,kind:t.kind,dependenciesInstalled:n.installed,packageManager:n.packageManager??null,started:r.started,reused:r.reused,pid:r.pid,logPath:t.logPath,statusUrl:r.statusUrl,runtimeFilePath:t.runtimeFilePath,iosRuntime:s,androidRuntime:c,bridge:o};return _e(t.runtimeFilePath,l),l}function ye(e){let t=e.trimStart().slice(0,15).toLowerCase();return t.startsWith(`<!doctype`)||t.startsWith(`<html`)}async function be(e,n){await new Promise((r,i)=>{let a=new WebSocket(e),o=e=>{clearTimeout(s);try{a.close()}catch{}i(new t(`COMMAND_FAILED`,e))},s=setTimeout(()=>{o(`Timed out broadcasting reload to ${e} after ${n}ms`)},n);a.addEventListener(`open`,()=>{a.send(JSON.stringify({version:2,method:`reload`}));let e=()=>{if(a.bufferedAmount===0){clearTimeout(s),a.close(),r();return}setTimeout(e,20)};e()}),a.addEventListener(`error`,()=>{o(`Failed to reach the dev server message socket at ${e}`)})})}async function xe(e={}){let n=F(e.timeoutMs,1e4,1e3),{reloadUrl:r,messageSocketUrl:i}=v(e),a=await V(r,n);if(a.ok&&!ye(a.body))return{reloaded:!0,reloadUrl:r,status:a.status,body:a.body,transport:`http`};try{await be(i,n)}catch(e){throw new t(`COMMAND_FAILED`,`React Native dev server reload failed (${a.status}).`,{reloadUrl:r,status:a.status,body:a.body.slice(0,500),messageSocketUrl:i,hint:`Verify Metro or Re.Pack is running and the target React Native app is connected to this dev server instance.`},e instanceof Error?e:void 0)}return{reloaded:!0,reloadUrl:i,status:a.status,body:``,transport:`message-socket`}}export{xe as n,m as r,ve as t};
|