agent-device 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.0.apk → agent-device-android-ime-helper-0.20.2.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.2.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.0.manifest.json → agent-device-android-ime-helper-0.20.2.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.0.apk → agent-device-android-snapshot-helper-0.20.2.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.2.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.0.manifest.json → agent-device-android-snapshot-helper-0.20.2.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +2 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +30 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -21
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +8 -3
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Orientation.swift +92 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +4 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/android-input-method-overlays.js +1 -1
- package/dist/src/android.js +1 -1
- package/dist/src/app-lifecycle.js +5 -5
- package/dist/src/app-log-request-scope.js +1 -1
- package/dist/src/app-resolution.js +1 -1
- package/dist/src/apple-multitouch-support.js +1 -1
- package/dist/src/apps.js +5 -5
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +81 -24
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +14 -14
- package/dist/src/click-button.d.ts +5 -0
- package/dist/src/client-metro.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/compatibility-policy.js +1 -0
- package/dist/src/context.js +1 -1
- package/dist/src/contracts.d.ts +2 -2
- package/dist/src/debug-symbols.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/device.js +9 -0
- package/dist/src/devices2.js +1 -1
- package/dist/src/devices4.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-plan-types.js +1 -0
- package/dist/src/gesture-plan.js +1 -0
- package/dist/src/index.d.ts +1205 -1309
- package/dist/src/input-actions.js +4 -4
- package/dist/src/install-artifact.js +5 -1
- package/dist/src/install-artifact2.js +1 -0
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.d.ts +3 -6
- package/dist/src/interaction.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -0
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +14 -22
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun.d.ts +361 -0
- package/dist/src/limrun.js +1 -0
- package/dist/src/linux.js +1 -1
- package/dist/src/logcat.js +1 -5
- package/dist/src/method-scope.js +1 -0
- package/dist/src/metro.d.ts +72 -3
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -1
- package/dist/src/notifications.js +1 -1
- package/dist/src/physical-device-control.js +1 -0
- package/dist/src/plist.js +1 -0
- package/dist/src/react-native.js +1 -1
- package/dist/src/recording-export-quality.js +15 -0
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +24 -24
- package/dist/src/remote-config.d.ts +5 -2
- package/dist/src/remote-config.js +1 -1
- package/dist/src/remote-config2.js +1 -0
- package/dist/src/reporting.js +8 -8
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -2
- package/dist/src/runner-lease.js +1 -1
- package/dist/src/runner-provider.js +1 -1
- package/dist/src/runtime-transport.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +1 -1
- package/dist/src/sdk-android-adb.d.ts +4 -24
- package/dist/src/sdk-android-adb.js +4 -4
- package/dist/src/sdk-batch-runner.d.ts +13 -3
- package/dist/src/sdk-batch-runner.js +3 -2
- package/dist/src/sdk-contracts.d.ts +31 -91
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +3 -2
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +83 -53
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selector-vocabulary.js +1 -1
- package/dist/src/selectors.d.ts +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session.js +8 -8
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.js +4 -4
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/tool-provider.js +3 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/tv-remote.d.ts +213 -0
- package/dist/src/unsupported-interactor.js +1 -0
- package/dist/src/web.js +1 -1
- package/dist/src/xml.js +2 -0
- package/package.json +41 -19
- package/server.json +2 -2
- package/skills/agent-device/SKILL.md +5 -3
- package/smithery.yaml +1 -1
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.0.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.0.apk.sha256 +0 -1
- package/dist/src/android-system-chrome.js +0 -1
- package/dist/src/client-metro-companion.js +0 -1
- package/dist/src/config.js +0 -1
- package/dist/src/daemon-shutdown-report.js +0 -1
- package/dist/src/project-runtime.js +0 -1
- package/dist/src/scoped-provider.js +0 -1
- package/dist/src/sdk-batch.js +0 -2
- package/dist/src/snapshot-quality.js +0 -1
- package/dist/src/tv-remote.js +0 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{T as e}from"./sdk-batch-runner.js";import{It as t}from"./recording-export-quality.js";function n(e){return t(e)}function r(t,r){let i=n(t),a=i.leaseId??r?.leaseId,o=i.tenantId??r?.tenantId,s=i.runId??r?.runId;if(!(!o||!s||!a))return e({tenantId:o,runId:s,leaseId:a,leaseBackend:i.leaseBackend??r?.backend,leaseProvider:i.leaseProvider??r?.leaseProvider,deviceKey:i.deviceKey??r?.deviceKey,clientId:i.clientId??r?.clientId,expiresAt:r?.expiresAt})}function i(t,r){let i=n(t),a=r?.lease??r?.deviceLease??void 0;return e({tenantId:i.tenantId??a?.tenantId,runId:i.runId??a?.runId,leaseId:i.leaseId??a?.leaseId,leaseTtlMs:i.leaseTtlMs,leaseBackend:i.leaseBackend??a?.leaseBackend,leaseProvider:i.leaseProvider??a?.leaseProvider,deviceKey:i.deviceKey??a?.deviceKey,clientId:i.clientId??a?.clientId})}function a(t){let n=t.meta,r=e({leaseId:o(n?.leaseId),clientId:o(n?.clientId),tenantId:o(n?.tenantId),runId:o(n?.runId),leaseProvider:o(n?.leaseProvider),deviceKey:o(n?.deviceKey)});return Object.keys(r).length>0?r:void 0}function o(e){return typeof e==`string`&&e.trim().length>0?e.trim():void 0}export{a as i,n,i as r,r as t};
|
package/dist/src/lease.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{Bt as t,Ht as n,Lt as r,On as i,Pt as a}from"./recording-export-quality.js";import{n as o,r as s}from"./lease-context.js";import{an as c}from"./internal/daemon.js";async function l(e){let{req:a,sessionName:c,sessionStore:l,leaseRegistry:f,providerRuntimeIds:p,providerRuntimeRequiredIds:m,leaseLifecycleProvider:h,cloudArtifactProvider:g}=e,_=o(a);switch(a.command){case i.artifacts:return{ok:!0,data:await d(a,s(a,l.get(c)),g)};case`lease_allocate`:{u(_.leaseProvider,p,m);let e=f.allocateLease(r(_)),t;try{t=await h?.allocate?.(e,{req:a})}catch(t){throw f.releaseLease(n({leaseId:e.leaseId,tenantId:e.tenantId,runId:e.runId,leaseBackend:e.backend,leaseProvider:e.leaseProvider,deviceKey:e.deviceKey,clientId:e.clientId})),t}return{ok:!0,data:{lease:e,...t?{provider:t}:{}}}}case`lease_heartbeat`:{let e=f.heartbeatLease(t(_)),n=await h?.heartbeat?.(e,{req:a});return{ok:!0,data:{lease:e,...n?{provider:n}:{}}}}case`lease_release`:{let e=n(_),t=f.getLease(e),r=t?await h?.release?.(t,{req:a}):void 0;return{ok:!0,data:{released:f.releaseLease(e).released,...r?{provider:r}:{}}}}default:return null}}function u(t,n,r){if(!(!t||n===void 0||r===void 0||!r.includes(t)||n.includes(t)))throw new e(`UNSUPPORTED_OPERATION`,`Provider "${t}" is not available in this daemon runtime.`,{provider:t,hint:`Restart the daemon with ${t} configured, then retry lease allocation.`})}async function d(e,t,n){let r=h(e.flags,`providerSessionId`);return f(t,r)?await p(t.tenantId):await m(t,r,n)}function f(e,t){return a(e)||!e.leaseProvider&&!t}async function p(e){let t=await c(e);return{source:`daemon`,status:`ready`,artifacts:t,...t.length===0?{message:`No daemon artifacts available.`}:{}}}async function m(t,n,r){if(!t.leaseProvider)throw new e(`INVALID_ARGS`,`artifacts requires --provider for provider session lookup or an active cloud connection.`);if(!t.leaseId&&!n)throw new e(`INVALID_ARGS`,`artifacts requires an active cloud lease or --provider-session <id>.`);let i=await r?.listCloudArtifacts?.({provider:t.leaseProvider,leaseId:t.leaseId,providerSessionId:n});if(!i)throw new e(`UNSUPPORTED_OPERATION`,`Cloud artifacts are not available for provider "${t.leaseProvider}".`);return i}function h(e,t){let n=e?.[t];return typeof n==`string`&&n.length>0?n:void 0}export{l as handleLeaseCommands};
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { A as SnapshotNode, B as DeviceTarget, D as Rect, E as RawSnapshotNode, H as PlatformSelector, N as SnapshotState, R as DeviceInfo, T as Point, j as SnapshotOptions$1, k as SnapshotBackend, o as DaemonRequest, p as LeaseBackend } from "./sdk-contracts.js";
|
|
2
|
+
import { a as GesturePlan, s as ScrollDirection } from "./sdk-android-adb.js";
|
|
3
|
+
import { a as CloudArtifactProvider, f as SnapshotCaptureAnnotations, n as DeviceRotation, p as SessionSurface, s as BackMode, t as TvRemoteButton, u as SnapshotDiagnosticsSummary } from "./tv-remote.js";
|
|
4
|
+
import { t as ClickButton } from "./click-button.js";
|
|
5
|
+
//#region src/platforms/permission-utils.d.ts
|
|
6
|
+
type SettingOptions = {
|
|
7
|
+
permissionTarget?: string;
|
|
8
|
+
permissionMode?: string;
|
|
9
|
+
latitude?: number;
|
|
10
|
+
longitude?: number;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/backend.d.ts
|
|
14
|
+
type BackendSnapshotResult = {
|
|
15
|
+
nodes?: SnapshotNode[];
|
|
16
|
+
truncated?: boolean;
|
|
17
|
+
backend?: string;
|
|
18
|
+
snapshot?: SnapshotState;
|
|
19
|
+
appName?: string;
|
|
20
|
+
appBundleId?: string;
|
|
21
|
+
snapshotDiagnostics?: SnapshotDiagnosticsSummary;
|
|
22
|
+
} & SnapshotCaptureAnnotations;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/contracts/runner-lease-context.d.ts
|
|
25
|
+
type RunnerLogicalLeaseContext = {
|
|
26
|
+
leaseId?: string;
|
|
27
|
+
clientId?: string;
|
|
28
|
+
tenantId?: string;
|
|
29
|
+
runId?: string;
|
|
30
|
+
leaseProvider?: string;
|
|
31
|
+
deviceKey?: string;
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/contracts/interactor-types.d.ts
|
|
35
|
+
type RunnerContext = {
|
|
36
|
+
requestId?: string;
|
|
37
|
+
appBundleId?: string;
|
|
38
|
+
verbose?: boolean;
|
|
39
|
+
logPath?: string;
|
|
40
|
+
traceLogPath?: string;
|
|
41
|
+
iosXctestrunFile?: string;
|
|
42
|
+
iosXctestDerivedDataPath?: string;
|
|
43
|
+
iosXctestEnvDir?: string;
|
|
44
|
+
runnerLeaseContext?: RunnerLogicalLeaseContext;
|
|
45
|
+
};
|
|
46
|
+
type ScreenshotOptions = {
|
|
47
|
+
appBundleId?: string;
|
|
48
|
+
pixelDensity?: number;
|
|
49
|
+
fullscreen?: boolean;
|
|
50
|
+
normalizeStatusBar?: boolean;
|
|
51
|
+
stabilize?: boolean;
|
|
52
|
+
surface?: SessionSurface;
|
|
53
|
+
skipIosSimulatorBootCheck?: boolean;
|
|
54
|
+
captureBackend?: 'runner';
|
|
55
|
+
};
|
|
56
|
+
type ElementSelectorKey = 'id' | 'label' | 'text' | 'value';
|
|
57
|
+
type ElementSelectorTapOptions = {
|
|
58
|
+
key: ElementSelectorKey;
|
|
59
|
+
value: string;
|
|
60
|
+
allowNonHittableCoordinateFallback?: boolean;
|
|
61
|
+
expectedPoint?: Point;
|
|
62
|
+
};
|
|
63
|
+
type SnapshotOptions = SnapshotOptions$1 & {
|
|
64
|
+
appBundleId?: string;
|
|
65
|
+
includeRects?: boolean;
|
|
66
|
+
includeHiddenContentHints?: boolean;
|
|
67
|
+
surface?: SessionSurface;
|
|
68
|
+
};
|
|
69
|
+
type SnapshotResult = Omit<BackendSnapshotResult, 'backend' | 'nodes'> & {
|
|
70
|
+
nodes?: RawSnapshotNode[];
|
|
71
|
+
backend: Extract<SnapshotBackend, 'android' | 'xctest' | 'linux-atspi' | 'web'>;
|
|
72
|
+
};
|
|
73
|
+
type Interactor = {
|
|
74
|
+
open(app: string, options?: {
|
|
75
|
+
activity?: string;
|
|
76
|
+
appBundleId?: string;
|
|
77
|
+
launchConsole?: string;
|
|
78
|
+
launchArgs?: string[];
|
|
79
|
+
terminateRunningApp?: boolean;
|
|
80
|
+
url?: string;
|
|
81
|
+
}): Promise<void>;
|
|
82
|
+
openDevice(): Promise<void>;
|
|
83
|
+
close(app: string): Promise<void>;
|
|
84
|
+
tap(x: number, y: number): Promise<Record<string, unknown> | void>;
|
|
85
|
+
tapElementSelector?(selector: ElementSelectorTapOptions): Promise<Record<string, unknown> | void>;
|
|
86
|
+
doubleTap(x: number, y: number): Promise<Record<string, unknown> | void>;
|
|
87
|
+
longPress(x: number, y: number, durationMs?: number): Promise<Record<string, unknown> | void>;
|
|
88
|
+
focus(x: number, y: number): Promise<Record<string, unknown> | void>;
|
|
89
|
+
type(text: string, delayMs?: number): Promise<void>;
|
|
90
|
+
fillElementSelector?(selector: ElementSelectorTapOptions, text: string, delayMs?: number): Promise<Record<string, unknown> | void>;
|
|
91
|
+
fill(x: number, y: number, text: string, delayMs?: number): Promise<Record<string, unknown> | void>;
|
|
92
|
+
scroll(direction: ScrollDirection, options?: {
|
|
93
|
+
amount?: number;
|
|
94
|
+
pixels?: number;
|
|
95
|
+
durationMs?: number;
|
|
96
|
+
}): Promise<Record<string, unknown> | void>;
|
|
97
|
+
screenshot(outPath: string, options?: ScreenshotOptions): Promise<void>;
|
|
98
|
+
setViewport?(width: number, height: number): Promise<Record<string, unknown> | void>;
|
|
99
|
+
snapshot(options?: SnapshotOptions): Promise<SnapshotResult>;
|
|
100
|
+
gestureViewport?(): Promise<Rect>;
|
|
101
|
+
back(mode?: BackMode): Promise<void>;
|
|
102
|
+
home(): Promise<void>;
|
|
103
|
+
setOrientation(orientation: DeviceRotation): Promise<{
|
|
104
|
+
orientation?: DeviceRotation;
|
|
105
|
+
} | void>;
|
|
106
|
+
performGesture?(plan: GesturePlan): Promise<Record<string, unknown> | void>;
|
|
107
|
+
appSwitcher(): Promise<void>;
|
|
108
|
+
tvRemote(button: TvRemoteButton, durationMs?: number): Promise<void>;
|
|
109
|
+
readClipboard(): Promise<string>;
|
|
110
|
+
writeClipboard(text: string): Promise<void>;
|
|
111
|
+
setSetting(setting: string, state: string, appId?: string, options?: SettingOptions): Promise<Record<string, unknown> | void>;
|
|
112
|
+
};
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/contracts/device-inventory.d.ts
|
|
115
|
+
type DeviceInventoryRequest = {
|
|
116
|
+
platform?: PlatformSelector;
|
|
117
|
+
target?: DeviceTarget;
|
|
118
|
+
deviceName?: string;
|
|
119
|
+
udid?: string;
|
|
120
|
+
serial?: string;
|
|
121
|
+
leaseId?: string;
|
|
122
|
+
leaseProvider?: string;
|
|
123
|
+
deviceKey?: string;
|
|
124
|
+
clientId?: string;
|
|
125
|
+
iosSimulatorSetPath?: string;
|
|
126
|
+
androidSerialAllowlist?: string[];
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region src/contracts/device-provider.d.ts
|
|
130
|
+
type DeviceLease = {
|
|
131
|
+
leaseId: string;
|
|
132
|
+
tenantId: string;
|
|
133
|
+
runId: string;
|
|
134
|
+
backend: LeaseBackend;
|
|
135
|
+
leaseProvider?: string;
|
|
136
|
+
deviceKey?: string;
|
|
137
|
+
clientId?: string;
|
|
138
|
+
createdAt: number;
|
|
139
|
+
heartbeatAt: number;
|
|
140
|
+
expiresAt: number;
|
|
141
|
+
};
|
|
142
|
+
type LeaseLifecycleContext = {
|
|
143
|
+
req: DaemonRequest;
|
|
144
|
+
};
|
|
145
|
+
type LeaseLifecycleProvider = {
|
|
146
|
+
allocate?: (lease: DeviceLease, context?: LeaseLifecycleContext) => Promise<Record<string, unknown> | undefined>;
|
|
147
|
+
heartbeat?: (lease: DeviceLease, context?: LeaseLifecycleContext) => Promise<Record<string, unknown> | undefined>;
|
|
148
|
+
release?: (lease: DeviceLease, context?: LeaseLifecycleContext) => Promise<Record<string, unknown> | undefined>;
|
|
149
|
+
};
|
|
150
|
+
type DeviceInventoryProvider = (request: DeviceInventoryRequest) => Promise<DeviceInfo[] | null | undefined>;
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/utils/retry.d.ts
|
|
153
|
+
declare class Deadline {
|
|
154
|
+
private readonly startedAtMs;
|
|
155
|
+
private readonly expiresAtMs;
|
|
156
|
+
private constructor();
|
|
157
|
+
static fromTimeoutMs(timeoutMs: number, nowMs?: number): Deadline;
|
|
158
|
+
remainingMs(nowMs?: number): number;
|
|
159
|
+
elapsedMs(nowMs?: number): number;
|
|
160
|
+
isExpired(nowMs?: number): boolean;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/platforms/apple/core/runner/runner-cache.d.ts
|
|
164
|
+
type RunnerXctestrunCacheKind = 'exact' | 'restore-key' | 'miss' | 'external';
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/platforms/apple/core/runner/runner-artifact.d.ts
|
|
167
|
+
type RunnerXctestrunArtifactState = 'valid' | 'rebuilt';
|
|
168
|
+
type ExternalXctestRunnerOptions = {
|
|
169
|
+
iosXctestrunFile?: string;
|
|
170
|
+
iosXctestDerivedDataPath?: string;
|
|
171
|
+
iosXctestEnvDir?: string;
|
|
172
|
+
};
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/platforms/apple/core/runner/runner-contract.d.ts
|
|
175
|
+
type RunnerCommand = {
|
|
176
|
+
command: 'tap' | 'mouseClick' | 'longPress' | 'drag' | 'remotePress' | 'type' | 'swipe' | 'scroll' | 'desktopScroll' | 'findText' | 'querySelector' | 'readText' | 'snapshot' | 'screenshot' | 'back' | 'backInApp' | 'backSystem' | 'home' | 'rotate' | 'gesture' | 'gestureViewport' | 'appSwitcher' | 'keyboardDismiss' | 'keyboardReturn' | 'alert' | 'sequence' | 'recordStart' | 'recordStop' | 'status' | 'uptime' | 'activate' | 'terminate' | 'targetReset' | 'shutdown';
|
|
177
|
+
commandId?: string;
|
|
178
|
+
statusCommandId?: string;
|
|
179
|
+
appBundleId?: string;
|
|
180
|
+
text?: string;
|
|
181
|
+
selectorKey?: ElementSelectorKey;
|
|
182
|
+
selectorValue?: string;
|
|
183
|
+
allowNonHittableCoordinateFallback?: boolean;
|
|
184
|
+
delayMs?: number;
|
|
185
|
+
textEntryMode?: 'append' | 'replace';
|
|
186
|
+
action?: 'get' | 'accept' | 'dismiss';
|
|
187
|
+
x?: number;
|
|
188
|
+
y?: number;
|
|
189
|
+
button?: ClickButton;
|
|
190
|
+
remoteButton?: 'select' | 'menu' | 'home' | 'up' | 'down' | 'left' | 'right';
|
|
191
|
+
x2?: number;
|
|
192
|
+
y2?: number;
|
|
193
|
+
durationMs?: number;
|
|
194
|
+
/** Remaining request budget for runner work that performs bounded XCTest queries. */
|
|
195
|
+
timeoutMs?: number;
|
|
196
|
+
direction?: ScrollDirection;
|
|
197
|
+
amount?: number;
|
|
198
|
+
pixels?: number;
|
|
199
|
+
orientation?: DeviceRotation;
|
|
200
|
+
/** Canonical pointer samples planned by the portable gesture runtime. */
|
|
201
|
+
gesturePlan?: GesturePlan;
|
|
202
|
+
outPath?: string;
|
|
203
|
+
fps?: number;
|
|
204
|
+
maxSize?: number;
|
|
205
|
+
interactiveOnly?: boolean;
|
|
206
|
+
depth?: number;
|
|
207
|
+
scope?: string;
|
|
208
|
+
raw?: boolean;
|
|
209
|
+
fullscreen?: boolean;
|
|
210
|
+
inlineScreenshot?: boolean;
|
|
211
|
+
synthesized?: boolean;
|
|
212
|
+
steps?: RunnerSequenceStep[];
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* One allowlisted coordinate gesture step inside a fused `sequence` runner command.
|
|
216
|
+
* The kind set is intentionally narrow (tap/doubleTap/longPress) and validated on both the
|
|
217
|
+
* daemon and runner sides — see runner-sequence.ts (the single interpretation point).
|
|
218
|
+
*/
|
|
219
|
+
type RunnerSequenceStep = {
|
|
220
|
+
kind: 'tap' | 'doubleTap' | 'longPress';
|
|
221
|
+
x: number;
|
|
222
|
+
y: number;
|
|
223
|
+
durationMs?: number;
|
|
224
|
+
pauseMs?: number;
|
|
225
|
+
/**
|
|
226
|
+
* For `tap` steps on iOS non-tv: use the synthesized HID tap (synthesizedTapAt) fast path
|
|
227
|
+
* instead of the drag-based XCUICoordinate tapAt, matching the individual `tap` command.
|
|
228
|
+
*/
|
|
229
|
+
synthesized?: boolean;
|
|
230
|
+
};
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/platforms/apple/core/runner/runner-provider.d.ts
|
|
233
|
+
type AppleRunnerCommandOptions = ExternalXctestRunnerOptions & {
|
|
234
|
+
verbose?: boolean;
|
|
235
|
+
logPath?: string;
|
|
236
|
+
traceLogPath?: string;
|
|
237
|
+
cleanStaleBundles?: boolean;
|
|
238
|
+
startupTimeoutMs?: number;
|
|
239
|
+
requestId?: string;
|
|
240
|
+
runnerLeaseContext?: RunnerLogicalLeaseContext;
|
|
241
|
+
};
|
|
242
|
+
type AppleRunnerLifecycleOptions = AppleRunnerCommandOptions & {
|
|
243
|
+
buildTimeoutMs?: number;
|
|
244
|
+
forceRunnerXctestrunRebuild?: boolean;
|
|
245
|
+
};
|
|
246
|
+
type AppleRunnerPrewarmOptions = AppleRunnerLifecycleOptions;
|
|
247
|
+
type AppleRunnerPrepareOptions = AppleRunnerLifecycleOptions & {
|
|
248
|
+
healthTimeoutMs: number;
|
|
249
|
+
prepareDeadline?: Deadline;
|
|
250
|
+
};
|
|
251
|
+
type AppleRunnerPrepareResult = {
|
|
252
|
+
runner: Record<string, unknown>;
|
|
253
|
+
cache?: RunnerXctestrunCacheKind;
|
|
254
|
+
artifact?: RunnerXctestrunArtifactState;
|
|
255
|
+
buildMs?: number;
|
|
256
|
+
connectMs: number;
|
|
257
|
+
healthCheckMs: number;
|
|
258
|
+
xctestrunPath?: string;
|
|
259
|
+
recoveryReason?: string;
|
|
260
|
+
failureReason?: string;
|
|
261
|
+
};
|
|
262
|
+
type AppleRunnerCommandExecutor = (device: DeviceInfo, command: RunnerCommand, options: AppleRunnerCommandOptions) => Promise<Record<string, unknown>>;
|
|
263
|
+
type AppleRunnerPrepareExecutor = (device: DeviceInfo, options: AppleRunnerPrepareOptions) => Promise<AppleRunnerPrepareResult>;
|
|
264
|
+
type AppleRunnerPrewarmExecutor = (device: DeviceInfo, options: AppleRunnerPrewarmOptions) => Promise<void>;
|
|
265
|
+
type AppleRunnerProvider = {
|
|
266
|
+
/**
|
|
267
|
+
* Executes a runner protocol command for an already resolved Apple target.
|
|
268
|
+
* Scoped providers may adapt this call to a request-local transport.
|
|
269
|
+
*/
|
|
270
|
+
runCommand: AppleRunnerCommandExecutor;
|
|
271
|
+
/**
|
|
272
|
+
* Proves a runner can answer a cheap command after any required local setup.
|
|
273
|
+
* Command-only providers may omit this and let callers fall back to uptime.
|
|
274
|
+
*/
|
|
275
|
+
prepare?: AppleRunnerPrepareExecutor;
|
|
276
|
+
/**
|
|
277
|
+
* Starts runner setup opportunistically. This must remain best-effort.
|
|
278
|
+
*/
|
|
279
|
+
prewarm?: AppleRunnerPrewarmExecutor;
|
|
280
|
+
};
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/provider-device-runtime.d.ts
|
|
283
|
+
type ProviderDeviceInstallResult = {
|
|
284
|
+
bundleId?: string;
|
|
285
|
+
packageName?: string;
|
|
286
|
+
appName?: string;
|
|
287
|
+
launchTarget?: string;
|
|
288
|
+
};
|
|
289
|
+
type ProviderDeviceInstallOptions = {
|
|
290
|
+
relaunch?: boolean;
|
|
291
|
+
appIdentifierHint?: string;
|
|
292
|
+
packageNameHint?: string;
|
|
293
|
+
};
|
|
294
|
+
type ProviderDeviceRuntime = {
|
|
295
|
+
provider: string;
|
|
296
|
+
leaseLifecycle: LeaseLifecycleProvider;
|
|
297
|
+
recoverExpiredLease?: ProviderExpiredLeaseRecovery;
|
|
298
|
+
cloudArtifacts?: CloudArtifactProvider;
|
|
299
|
+
deviceInventoryProvider: DeviceInventoryProvider;
|
|
300
|
+
ownsDevice(device: DeviceInfo): boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Builds the interactor for an owned device. `runnerContext` carries the
|
|
303
|
+
* per-request context (requestId for cancellation, appBundleId, log paths);
|
|
304
|
+
* runtimes composing the shared Apple interactor should thread it through so
|
|
305
|
+
* runner calls stay attributable to the request that issued them.
|
|
306
|
+
*/
|
|
307
|
+
getInteractor(device: DeviceInfo, runnerContext?: RunnerContext): Interactor | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* Apple runner transport for an owned device. When present, the daemon scopes
|
|
310
|
+
* the WHOLE request with it (via the `appleRunnerProvider` request resolver),
|
|
311
|
+
* so daemon routes that issue runner commands outside interactor methods
|
|
312
|
+
* (keyboard, native alert, point read, iOS sequences) reach the provider
|
|
313
|
+
* transport instead of the local XCTest runtime.
|
|
314
|
+
*/
|
|
315
|
+
getAppleRunnerProvider?(device: DeviceInfo): AppleRunnerProvider | AppleRunnerCommandExecutor | undefined;
|
|
316
|
+
installApp?(device: DeviceInfo, app: string, appPath: string, options?: ProviderDeviceInstallOptions): Promise<ProviderDeviceInstallResult | undefined>;
|
|
317
|
+
installInstallablePath?(device: DeviceInfo, installablePath: string, options?: ProviderDeviceInstallOptions): Promise<ProviderDeviceInstallResult | undefined>;
|
|
318
|
+
configurePortReverse?(options: ProviderPortReverseOptions): Promise<Record<string, unknown> | undefined>;
|
|
319
|
+
shutdown(): Promise<void>;
|
|
320
|
+
};
|
|
321
|
+
type ProviderPortReverseOptions = {
|
|
322
|
+
leaseId: string;
|
|
323
|
+
provider?: string;
|
|
324
|
+
devicePort: number;
|
|
325
|
+
hostPort: number;
|
|
326
|
+
name: string;
|
|
327
|
+
};
|
|
328
|
+
type ProviderExpiredLeaseRecovery = (lease: DeviceLease) => Promise<void>;
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/providers/limrun/runtime.d.ts
|
|
331
|
+
type LimrunRuntimeOptions = {
|
|
332
|
+
apiKey: string;
|
|
333
|
+
region?: string;
|
|
334
|
+
};
|
|
335
|
+
declare class LimrunRuntime implements ProviderDeviceRuntime {
|
|
336
|
+
private readonly limrun;
|
|
337
|
+
private readonly sessions;
|
|
338
|
+
private readonly options;
|
|
339
|
+
readonly provider = "limrun";
|
|
340
|
+
readonly leaseLifecycle: LeaseLifecycleProvider;
|
|
341
|
+
readonly recoverExpiredLease: ProviderExpiredLeaseRecovery;
|
|
342
|
+
readonly deviceInventoryProvider: DeviceInventoryProvider;
|
|
343
|
+
constructor(options: LimrunRuntimeOptions);
|
|
344
|
+
ownsDevice(device: DeviceInfo): boolean;
|
|
345
|
+
getInteractor(device: DeviceInfo): Interactor | undefined;
|
|
346
|
+
installApp(device: DeviceInfo, app: string, appPath: string, options?: ProviderDeviceInstallOptions): Promise<ProviderDeviceInstallResult | undefined>;
|
|
347
|
+
installInstallablePath(device: DeviceInfo, installablePath: string, options?: ProviderDeviceInstallOptions): Promise<ProviderDeviceInstallResult | undefined>;
|
|
348
|
+
configurePortReverse(options: ProviderPortReverseOptions): Promise<Record<string, unknown> | undefined>;
|
|
349
|
+
shutdown(): Promise<void>;
|
|
350
|
+
private allocate;
|
|
351
|
+
private createIosSession;
|
|
352
|
+
private createAndroidSession;
|
|
353
|
+
private buildInstanceMetadata;
|
|
354
|
+
private release;
|
|
355
|
+
private releaseRecoveredSession;
|
|
356
|
+
private terminateSession;
|
|
357
|
+
private getSessionForDevice;
|
|
358
|
+
private requireAndroidPortReverseSession;
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
361
|
+
export { LimrunRuntime, type LimrunRuntimeOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./runtime2.js";export{e as LimrunRuntime};
|
package/dist/src/linux.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{I as t}from"./sdk-android-adb.js";import{n}from"./gesture-plan.js";import{t as r}from"./snapshot.js";import{t as i}from"./tool-provider2.js";import{doubleClickLinux as a,fillLinux as o,focusLinux as s,longPressLinux as c,pressLinux as l,scrollLinux as u,sendKey as d,swipeLinux as f,typeLinux as p}from"./input-actions2.js";async function m(e){await i().desktop.openTarget(e)}async function h(e){await i().desktop.closeApp(e)}async function g(){await d(`alt+Left`,[`56:1`,`105:1`,`105:0`,`56:0`])}async function _(){await d(`super+d`,[`125:1`,`32:1`,`32:0`,`125:0`])}async function v(){return await i().clipboard.readText()}async function y(e){await i().clipboard.writeText(e)}async function b(e,t){await i().screenshot.capture(e,t)}function x(){return{open:e=>m(e),openDevice:()=>Promise.resolve(),close:e=>h(e),tap:(e,t)=>l(e,t),doubleTap:(e,t)=>a(e,t),longPress:(e,t,n)=>c(e,t,n),focus:(e,t)=>s(e,t),type:(e,t)=>p(e,t),fill:(e,t,n,r)=>o(e,t,n,r),scroll:(e,t)=>u(e,t),performGesture:async t=>{if(t.topology===`two`)throw new e(`UNSUPPORTED_OPERATION`,`Multi-touch gestures are not supported on Linux`);let{start:r,end:i}=n(t);await f(r.x,r.y,i.x,i.y,t.durationMs)},screenshot:(e,t)=>b(e,t),snapshot:async e=>{let n=await t(`snapshot_capture`,async()=>await r(e?.surface),{backend:`linux-atspi`});return{nodes:n.nodes??[],truncated:n.truncated??!1,backend:`linux-atspi`}},back:()=>g(),home:()=>_(),setOrientation:()=>{throw new e(`UNSUPPORTED_OPERATION`,`orientation not supported on Linux`)},appSwitcher:()=>{throw new e(`UNSUPPORTED_OPERATION`,`appSwitcher not yet supported on Linux`)},tvRemote:()=>{throw new e(`UNSUPPORTED_OPERATION`,`tv-remote not supported on Linux`)},readClipboard:()=>v(),writeClipboard:e=>y(e),setSetting:()=>{throw new e(`UNSUPPORTED_OPERATION`,`setSetting not supported on Linux`)}}}export{x as createLinuxInteractor};
|
package/dist/src/logcat.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`).map(e=>e.trim()).filter(e=>e.length>0);if(t.length!==0)return t.at(-1)===`OK`&&t.pop(),t.join(`
|
|
3
|
-
`).trim()||void 0}async function P(e,t=E){return c(`adb`,A(e,[`shell`,`getprop`,`sys.boot_completed`]),{allowFailure:!0,timeoutMs:t})}async function F(e,t){let n=t.replace(/_/g,` `).trim();if(!j(e))return n||e;let r=await R(e);return r?r.replace(/_/g,` `):n||e}async function I(e,t,r){try{return await r(`adb`,A(e,t),{allowFailure:!0,timeoutMs:1e4})}catch(e){if(L(n(e)))return;throw e}}function L(e){return e.code===`COMMAND_FAILED`&&typeof e.details?.timeoutMs==`number`}async function R(e,t=c){for(let n of[`ro.boot.qemu.avd_name`,`persist.sys.avd_name`]){let r=await I(e,[`shell`,`getprop`,n],t);if(!r)continue;let i=r.stdout.trim();if(r.exitCode===0&&i.length>0)return i}let n=await I(e,[`emu`,`avd`,`name`],t);if(!n)return;let r=N(n.stdout);if(n.exitCode===0&&r)return r}function z(e){let t=e.toLowerCase();return t.includes(`tv`)||t.includes(`leanback`)?`tv`:null}function B(e){return/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(e)}async function V(e,t){let n=k(await c(`adb`,A(e,[`shell`,`cmd`,`package`,`has-feature`,t]),{allowFailure:!0,timeoutMs:E})).toLowerCase();return n.includes(`true`)?!0:n.includes(`false`)?!1:null}async function H(e){return(await O(D,2,async t=>await V(e,t))).some(e=>e===!0)}async function U(e){return z(k(await c(`adb`,A(e,[`shell`,`getprop`,`ro.build.characteristics`]),{allowFailure:!0,timeoutMs:E})))===`tv`||await H(e)||B(k(await c(`adb`,A(e,[`shell`,`pm`,`list`,`features`]),{allowFailure:!0,timeoutMs:E})))?`tv`:`mobile`}async function W(e={}){if(await d(),!await l(`adb`))throw new t(`TOOL_MISSING`,`adb not found in PATH`);let n=e.serialAllowlist??h(void 0),r=await O((await K()).filter(e=>!n||n.has(e.serial)),3,async({serial:e,rawModel:t})=>{let[n,r,i]=await Promise.all([F(e,t),ae(e),U(e)]);return{platform:`android`,id:e,name:n,kind:j(e)?`emulator`:`device`,target:i,booted:r}});return[...r,...await X(r)]}function G(e){return e.split(`
|
|
4
|
-
`).map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith(`List of devices`)).map(e=>e.split(/\s+/)).flatMap(e=>{let t=e[0];return t===void 0||e[1]!==`device`?[]:[{serial:t,rawModel:(e.find(e=>e.startsWith(`model:`))??``).replace(`model:`,``)}]})}async function K(){try{return G((await c(`adb`,[`devices`,`-l`],{timeoutMs:E})).stdout)}catch(e){throw o(e)}}function q(e){return e.split(`
|
|
5
|
-
`).map(e=>e.trim()).filter(e=>e.length>0)}function J(e,t){let n=e.find(e=>e===t);if(n)return n;let r=M(t);return e.find(e=>M(e)===r)}async function Y(){return q(i(await c(`emulator`,[`-list-avds`],{allowFailure:!0,timeoutMs:E}),`Failed to list Android emulator AVDs`,{hint:`Verify Android emulator tooling is installed and available in PATH.`}).stdout)}async function X(e){let t=await Y().catch(()=>[]),n=new Set(e.filter(e=>e.kind===`emulator`).map(e=>M(e.name)));return t.filter(e=>!n.has(M(e))).map(e=>({platform:`android`,id:e,name:e,kind:`emulator`,target:Z(e),booted:!1}))}function Z(e){return/\b(tv|television)\b/i.test(M(e))?`tv`:`mobile`}function ne(e,t,n){let r=M(t);return e.find(e=>e.platform!==`android`||e.kind!==`emulator`||n&&e.id!==n?!1:M(e.name)===r)}async function re(e){let n=Date.now(),r=Math.min(1e3,Math.max(50,Math.floor(e.timeoutMs/20)));for(;Date.now()-n<e.timeoutMs;){try{let t=await ie(e.avdName,e.serial);if(t)return{platform:`android`,id:t,name:e.avdName,kind:`emulator`,target:`mobile`,booted:!1}}catch{}await u(r)}throw new t(`COMMAND_FAILED`,`Android emulator did not appear in time`,{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:`Check emulator logs and verify the AVD can start from command line.`})}async function ie(e,t){let n=M(e),r=(await K()).filter(e=>t&&e.serial!==t?!1:j(e.serial));for(let e of r)if(M(e.rawModel)===n||M(await F(e.serial,e.rawModel))===n)return e.serial}async function ae(e){try{return(await P(e)).stdout.trim()===`1`}catch{return!1}}async function oe(e){await d();let n=e.avdName.trim();if(!n)throw new t(`INVALID_ARGS`,`Android emulator boot requires a non-empty AVD name.`);let i=e.timeoutMs??12e4;if(!await l(`adb`))throw new t(`TOOL_MISSING`,`adb not found in PATH`);if(!await l(`emulator`))throw new t(`TOOL_MISSING`,`emulator not found in PATH`);let a=await Y(),o=J(a,n);if(!o)throw new t(`DEVICE_NOT_FOUND`,`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:n,availableAvds:a,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let s=Date.now(),c=ne(await W(),o,e.serial),u=c&&j(c.id)?c:void 0;if(!u){let t=[`-avd`,o];e.headless&&t.push(`-no-window`,`-no-audio`),r(`emulator`,t)}let f=u??await re({avdName:o,serial:e.serial,timeoutMs:i}),p=Date.now()-s,m=Math.max(1e3,i-p);await Q(f.id,m);let h=(await W()).find(e=>e.id===f.id);return h?{...h,name:o,booted:!0}:{...f,name:o,booted:!0}}async function Q(e,r=6e4){let i=r,a=ee.fromTimeoutMs(i),o=Math.min(1e3,Math.max(50,Math.floor(i/20))),s=Math.max(1,Math.ceil(i/o)),c,l=!1;try{await g(async({deadline:n})=>{if(n?.isExpired())throw l=!0,new t(`COMMAND_FAILED`,`Android boot deadline exceeded`,{serial:e,timeoutMs:r,elapsedMs:a.elapsedMs(),message:`timeout`});let o=Math.max(1e3,n?.remainingMs()??i),s=await P(e,Math.min(o,E));if(c=s,s.stdout.trim()!==`1`)throw new t(`COMMAND_FAILED`,`Android device is still booting`,{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:s,baseDelayMs:o,maxDelayMs:o,jitter:0,shouldRetry:e=>{let t=_({error:e,stdout:c?.stdout,stderr:c?.stderr,context:{platform:`android`,phase:`boot`}});return t!==`ADB_TRANSPORT_UNAVAILABLE`&&t!==`ANDROID_BOOT_TIMEOUT`}},{deadline:a,phase:`boot`,classifyReason:e=>_({error:e,stdout:c?.stdout,stderr:c?.stderr,context:{platform:`android`,phase:`boot`}})})}catch(r){let o=n(r),s=c?.stdout,u=c?.stderr,d=c?.exitCode,f=_({error:r,stdout:s,stderr:u,context:{platform:`android`,phase:`boot`}});f===`BOOT_COMMAND_FAILED`&&o.message===`Android device is still booting`&&(f=`ANDROID_BOOT_TIMEOUT`);let p={serial:e,timeoutMs:i,elapsedMs:a.elapsedMs(),reason:f,hint:v(f),stdout:s,stderr:u,exitCode:d};throw l||f===`ANDROID_BOOT_TIMEOUT`?new t(`COMMAND_FAILED`,`Android device did not finish booting in time`,p):o.code===`TOOL_MISSING`?new t(`TOOL_MISSING`,o.message,{...p,...o.details??{}}):f===`ADB_TRANSPORT_UNAVAILABLE`?new t(`COMMAND_FAILED`,o.message,{...p,...o.details??{}}):new t(o.code,o.message,{...p,...o.details??{}},o.cause)}}async function se(e,t,n){return await s(e)(t,n)}function ce(e){return{platform:`android`,id:e,name:e,kind:e.startsWith(`emulator-`)?`emulator`:`device`,booted:!0}}function le(e,t){let n=`${e}\n${t}`.toLowerCase();return n.includes(`no shell command implementation`)||n.includes(`unknown command`)}var ue=e({prepareAndroidInstallArtifact:()=>$});async function $(e,t){let n=e.kind===`url`&&p(e.url),r=await m({source:e,isInstallablePath:(e,t)=>t.isFile()&&de(e),installableLabel:`Android installable (.apk or .aab)`,allowArchiveExtraction:e.kind!==`url`||n,signal:t?.signal});try{let e=t?.resolveIdentity===!1?{}:await fe(r.installablePath);return{archivePath:r.archivePath,installablePath:r.installablePath,packageName:e.packageName,cleanup:r.cleanup}}catch(e){throw await r.cleanup(),e}}function de(e){let t=y.extname(e).toLowerCase();return t===`.apk`||t===`.aab`}async function fe(e){let t=y.extname(e).toLowerCase();return t!==`.apk`&&t!==`.aab`?{}:{packageName:await f(e)}}async function pe(e,t={}){let n=[`logcat`,`-d`,`-v`,`time`];t.lines!==void 0&&n.push(`-t`,String(Math.max(1,Math.floor(t.lines))));let r=await e(n,{allowFailure:!0,timeoutMs:t.timeoutMs,signal:t.signal});if(r.exitCode!==0)throw a(`Failed to capture Android logcat`,r);return r.stdout}function me(e,n={}){if(!e.spawn)throw new t(`UNSUPPORTED_OPERATION`,`Android ADB provider does not support streams`,{capability:`adb.spawn`});let r=[`logcat`,`-v`,`time`];n.pid&&r.push(`--pid`,n.pid);let i=e.spawn(r,{stdio:[`ignore`,`pipe`,`pipe`],signal:n.signal});return n.output&&i.stdout&&i.stdout.pipe(n.output,{end:!1}),i}export{ce as a,T as c,b as d,x as f,$ as i,Q as l,me as n,le as o,te as p,ue as r,se as s,pe as t,S as u};
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{n as t}from"./sdk-android-adb.js";import"node:fs";async function n(e,n={}){let r=[`logcat`,`-d`,`-v`,`time`];n.lines!==void 0&&r.push(`-t`,String(Math.max(1,Math.floor(n.lines))));let i=await e(r,{allowFailure:!0,timeoutMs:n.timeoutMs,signal:n.signal});if(i.exitCode!==0)throw t(`Failed to capture Android logcat`,i);return i.stdout}function r(t,n={}){if(!t.spawn)throw new e(`UNSUPPORTED_OPERATION`,`Android ADB provider does not support streams`,{capability:`adb.spawn`});let r=[`logcat`,`-v`,`time`];n.pid&&r.push(`--pid`,n.pid);let i=t.spawn(r,{stdio:[`ignore`,`pipe`,`pipe`],signal:n.signal});return n.output&&i.stdout&&i.stdout.pipe(n.output,{end:!1}),i}export{r as n,n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){return new Proxy(e,{get(e,n,r){let i=Reflect.get(e,n,r);return typeof i==`function`?(...n)=>t(async()=>await i.apply(e,n)):i}})}export{e as t};
|
package/dist/src/metro.d.ts
CHANGED
|
@@ -1,9 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { v as SessionRuntimeHints } from "./sdk-contracts.js";
|
|
2
|
+
import { d as PrepareMetroRuntimeResult, f as ReloadMetroResult, o as MetroPrepareKind, p as MetroBridgeScope } from "./sdk-remote-config.js";
|
|
3
3
|
//#region src/utils/url.d.ts
|
|
4
4
|
declare function normalizeBaseUrl(input: string): string;
|
|
5
5
|
declare function buildBundleUrl(baseUrl: string, platform: 'ios' | 'android', entryPath?: string): string;
|
|
6
6
|
//#endregion
|
|
7
|
+
//#region src/metro/metro-types.d.ts
|
|
8
|
+
/** Re-export of {@link SessionRuntimeHints} under the Metro-specific alias used by public API consumers. */
|
|
9
|
+
type MetroRuntimeHints = SessionRuntimeHints;
|
|
10
|
+
type MetroBridgeRuntimePayload = {
|
|
11
|
+
metro_host?: string;
|
|
12
|
+
metro_port?: number;
|
|
13
|
+
metro_bundle_url?: string;
|
|
14
|
+
launch_url?: string;
|
|
15
|
+
};
|
|
16
|
+
type MetroBridgeDescriptor = {
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
base_url: string;
|
|
19
|
+
status_url?: string;
|
|
20
|
+
bundle_url?: string;
|
|
21
|
+
ios_runtime: MetroBridgeRuntimePayload;
|
|
22
|
+
android_runtime: MetroBridgeRuntimePayload;
|
|
23
|
+
upstream: {
|
|
24
|
+
bundle_url?: string;
|
|
25
|
+
host?: string;
|
|
26
|
+
port?: number;
|
|
27
|
+
status_url?: string;
|
|
28
|
+
};
|
|
29
|
+
probe: {
|
|
30
|
+
reachable: boolean;
|
|
31
|
+
status_code: number;
|
|
32
|
+
latency_ms: number;
|
|
33
|
+
detail: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
7
37
|
//#region src/metro/metro.d.ts
|
|
8
38
|
declare function resolveRuntimeTransport(runtime: SessionRuntimeHints | undefined): {
|
|
9
39
|
host: string;
|
|
@@ -65,5 +95,44 @@ type MetroTunnelWebSocketCloseMessage = {
|
|
|
65
95
|
};
|
|
66
96
|
type MetroTunnelRequestMessage = MetroTunnelPingMessage | MetroTunnelHttpRequestMessage | MetroTunnelWebSocketOpenMessage | MetroTunnelWebSocketFrameMessage | MetroTunnelWebSocketCloseMessage;
|
|
67
97
|
type MetroTunnelResponseMessage = MetroTunnelPongMessage | MetroTunnelHttpResponseMessage | MetroTunnelHttpErrorMessage | MetroTunnelWebSocketOpenResultMessage | MetroTunnelWebSocketFrameMessage | MetroTunnelWebSocketCloseMessage;
|
|
98
|
+
type StopMetroTunnelOptions = {
|
|
99
|
+
projectRoot: string;
|
|
100
|
+
profileKey?: string;
|
|
101
|
+
consumerKey?: string;
|
|
102
|
+
};
|
|
103
|
+
declare function stopMetroTunnel(options: StopMetroTunnelOptions): Promise<void>;
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/metro/client-metro.d.ts
|
|
106
|
+
type EnvSource = NodeJS.ProcessEnv | Record<string, string | undefined>;
|
|
107
|
+
type PrepareMetroRuntimeOptions = {
|
|
108
|
+
projectRoot?: string;
|
|
109
|
+
kind?: MetroPrepareKind;
|
|
110
|
+
metroPort?: number | string;
|
|
111
|
+
listenHost?: string;
|
|
112
|
+
statusHost?: string;
|
|
113
|
+
publicBaseUrl?: string;
|
|
114
|
+
proxyBaseUrl?: string;
|
|
115
|
+
proxyBearerToken?: string;
|
|
116
|
+
bridgeScope?: MetroBridgeScope;
|
|
117
|
+
launchUrl?: string;
|
|
118
|
+
companionProfileKey?: string;
|
|
119
|
+
companionConsumerKey?: string;
|
|
120
|
+
startupTimeoutMs?: number | string;
|
|
121
|
+
probeTimeoutMs?: number | string;
|
|
122
|
+
reuseExisting?: boolean;
|
|
123
|
+
installDependenciesIfNeeded?: boolean;
|
|
124
|
+
runtimeFilePath?: string;
|
|
125
|
+
logPath?: string;
|
|
126
|
+
env?: EnvSource;
|
|
127
|
+
};
|
|
128
|
+
type ReloadMetroOptions = {
|
|
129
|
+
metroHost?: string;
|
|
130
|
+
metroPort?: number | string;
|
|
131
|
+
bundleUrl?: string;
|
|
132
|
+
runtime?: MetroRuntimeHints;
|
|
133
|
+
timeoutMs?: number | string;
|
|
134
|
+
};
|
|
135
|
+
declare function prepareMetroRuntime(input?: PrepareMetroRuntimeOptions): Promise<PrepareMetroRuntimeResult>;
|
|
136
|
+
declare function reloadMetro(input?: ReloadMetroOptions): Promise<ReloadMetroResult>;
|
|
68
137
|
//#endregion
|
|
69
|
-
export { type MetroBridgeDescriptor, type MetroTunnelRequestMessage, type MetroTunnelResponseMessage, buildBundleUrl, normalizeBaseUrl, resolveRuntimeTransport };
|
|
138
|
+
export { type MetroBridgeDescriptor, type MetroTunnelRequestMessage, type MetroTunnelResponseMessage, buildBundleUrl, normalizeBaseUrl, prepareMetroRuntime, reloadMetro, resolveRuntimeTransport, stopMetroTunnel };
|
package/dist/src/metro.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./url.js";import{t as n}from"./metro2.js";export{t as buildBundleUrl,e as normalizeBaseUrl,n as resolveRuntimeTransport};
|
|
1
|
+
import{n as e,t}from"./url.js";import{n,t as r}from"./client-metro.js";import{n as i,t as a}from"./metro2.js";export{t as buildBundleUrl,e as normalizeBaseUrl,r as prepareMetroRuntime,n as reloadMetro,a as resolveRuntimeTransport,i as stopMetroTunnel};
|
package/dist/src/metro2.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{r as e}from"./client-metro.js";import{t}from"./runtime-transport.js";function n(e){return t(e)}async function r(t){await e(t)}export{r as n,n as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_ as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{a as t}from"./install-artifact.js";async function n(n,i,a){let o=typeof a.action==`string`&&a.action.trim()?a.action.trim():`${i}.TEST_PUSH`,s=[`shell`,`am`,`broadcast`,`-a`,o,`-p`,i],c=typeof a.receiver==`string`?a.receiver.trim():``;c&&s.push(`-n`,c);let l=a.extras;if(l!==void 0&&(typeof l!=`object`||!l||Array.isArray(l)))throw new e(`INVALID_ARGS`,`Android push payload extras must be an object`);let u=l??{},d=0;for(let[e,t]of Object.entries(u))e&&(r(s,e,t),d+=1);return await t(n,s),{action:o,extrasCount:d}}function r(t,n,r){if(typeof r==`string`){t.push(`--es`,n,r);return}if(typeof r==`boolean`){t.push(`--ez`,n,r?`true`:`false`);return}if(typeof r==`number`&&Number.isFinite(r)){if(Number.isInteger(r)){t.push(`--ei`,n,String(r));return}t.push(`--ef`,n,String(r));return}throw new e(`INVALID_ARGS`,`Unsupported Android broadcast extra type for "${n}". Use string, boolean, or number.`)}export{n as pushAndroidNotification};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as e}from"./sdk-contracts.js";import{C as t,j as n,p as r}from"./sdk-android-adb.js";import{n as i,t as a}from"./version.js";import{c as o,g as s,o as c,s as ee}from"./sdk-device.js";import{c as te,o as ne,s as re}from"./boot-diagnostics.js";import{a as l,s as ie}from"./tool-provider.js";import u from"node:crypto";import d,{promises as f}from"node:fs";import p from"node:os";import m from"node:path";function h(e,t={}){let n=ne(t.simulatorSetPath);return n?[`simctl`,`--set`,n,...e]:[`simctl`,...e]}function g(e,t){return!ee(e)||e.kind!==`simulator`?[`simctl`,...t]:h(t,{simulatorSetPath:e.simulatorSetPath})}function ae(e,t,n){return l(g(e,t),n)}const _={iOS:{sdkName:{simulator:`iphonesimulator`,device:`iphoneos`},derivedBaseName:{simulator:`ios-simulator`,device:`ios-device`},xctestrunHints:{simulator:{preferred:[`iphonesimulator`],disallowed:[`iphoneos`,`appletvos`,`appletvsimulator`,`macos`]},device:{preferred:[`iphoneos`],disallowed:[`iphonesimulator`,`appletvos`,`appletvsimulator`,`macos`]}}},tvOS:{sdkName:{simulator:`appletvsimulator`,device:`appletvos`},derivedBaseName:{simulator:`tvos-simulator`,device:`tvos-device`},xctestrunHints:{simulator:{preferred:[`appletvsimulator`],disallowed:[`appletvos`,`iphoneos`,`iphonesimulator`,`macos`]},device:{preferred:[`appletvos`],disallowed:[`appletvsimulator`,`iphoneos`,`iphonesimulator`,`macos`]}}},macOS:{sdkName:{simulator:`macosx`,device:`macosx`},derivedBaseName:{simulator:`macos`,device:`macos`},xctestrunHints:{simulator:{preferred:[`macos`],disallowed:[`iphoneos`,`iphonesimulator`,`appletvos`,`appletvsimulator`]},device:{preferred:[`macos`],disallowed:[`iphoneos`,`iphonesimulator`,`appletvos`,`appletvsimulator`]}}},visionOS:{sdkName:{simulator:`xrsimulator`,device:`xros`},derivedBaseName:{simulator:`visionos-simulator`,device:`visionos-device`},xctestrunHints:{simulator:{preferred:[`xrsimulator`],disallowed:[`xros`,`iphoneos`,`iphonesimulator`,`appletvos`,`appletvsimulator`,`macos`]},device:{preferred:[`xros`],disallowed:[`xrsimulator`,`iphoneos`,`iphonesimulator`,`appletvos`,`appletvsimulator`,`macos`]}}}};function v(t){if(!c(t.platform))throw new e(`UNSUPPORTED_PLATFORM`,`Unsupported platform for Apple runner: ${t.platform}`);return o(t)?`macOS`:s(t.target,t.appleOs)}function oe(e,t){return _[e].sdkName[y(t)]}function se(e){return _[v(e)].derivedBaseName[y(e.kind)]}function ce(e){return _[v(e)].xctestrunHints[y(e.kind)]}function le(e){let t=v(e);return t===`macOS`?`platform=macOS,arch=${b()}`:e.kind===`simulator`?`platform=${t} Simulator,id=${e.id}`:`platform=${t},id=${e.id}`}function ue(e){let t=v(e);return t===`macOS`?`platform=macOS,arch=${b()}`:e.kind===`simulator`?`platform=${t} Simulator,id=${e.id}`:`generic/platform=${t}`}function de(e){let t=v(e);return t===`macOS`?`platform=macOS,arch=${b()}`:e.kind===`simulator`?`generic/platform=${t} Simulator`:`generic/platform=${t}`}function y(e){return e===`simulator`?`simulator`:`device`}function b(){return process.arch===`arm64`?`arm64`:`x86_64`}const fe=new Set;function x(e={}){let t=new Map,n=e.now??(()=>Date.now()),r=e=>{e?.timer&&clearTimeout(e.timer)},i={get(e){let r=t.get(e);if(r){if(r.expiresAt!==void 0&&r.expiresAt<=n()){i.delete(e);return}return r.value}},set(i,a){r(t.get(i));let o=pe(e.ttlMs,n),s={value:a,expiresAt:o};e.scheduleExpiry&&o!==void 0&&(s.timer=setTimeout(()=>{t.delete(i)},Math.max(0,o-n())),s.timer.unref?.()),t.set(i,s)},delete(e){let n=t.get(e);return n?(r(n),t.delete(e)):!1},clear(){for(let e of t.values())r(e);t.clear()}};return fe.add(i.clear),i}function pe(e,t){if(!(e===void 0||!Number.isFinite(e)))return t()+Math.max(0,e)}const me=m.join(`apple`,`runner`,`AgentDeviceRunner`),he=m.join(`dist`,`apple`,`runner`,`AgentDeviceRunner`);function S(e){let t=m.join(e,me);return d.existsSync(t)?t:m.join(e,he)}function ge(e){return m.join(S(e),`AgentDeviceRunner.xcodeproj`)}const _e=m.join(p.homedir(),`.agent-device`,`apple-runner`),ve=`.agent-device-runner-cache.json`,ye=[`-IDEPackageSupportDisableManifestSandbox=1`,`-IDEPackageSupportDisablePluginExecutionSandbox=1`,`ENABLE_USER_SCRIPT_SANDBOXING=NO`],C=x();function w(e){return e?.trim()??``}function T(e=process.env){return w(e.AGENT_DEVICE_IOS_BUNDLE_ID)||w(e.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID)||`com.callstack.agentdevice.runner`}function E(e=process.env){return w(e.AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID)||`${T(e)}.uitests`}function be(e=process.env){let t=T(e),n=E(e);return Array.from(new Set([w(e.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID),`${n}.xctrunner`,t].filter(e=>e.length>0)))}const D=be(process.env);function xe(e,t=a()){let n=v(e);return{schemaVersion:2,packageVersion:i(t),runnerSourceFingerprint:Oe(t),...Se(n,e.kind),platformName:n,deviceKind:e.kind,target:e.target??`mobile`,buildDestinationFamily:de(e),runnerBundleBuildSettings:N(process.env),runnerSigningBuildSettings:M(process.env,e.kind===`device`,e),runnerPerformanceBuildSettings:P(),runnerSandboxBuildArgs:F()}}function Se(e,t){let n=Ce(O(`xcodebuild`,[`-version`])),r=oe(e,t);return{xcodeVersion:n.version,xcodeBuildVersion:n.buildVersion,sdkName:r,sdkVersion:O(`xcrun`,[`--sdk`,r,`--show-sdk-version`]),sdkBuildVersion:O(`xcrun`,[`--sdk`,r,`--show-sdk-build-version`])}}function O(e,n){let r=JSON.stringify([e,n]),i=C.get(r);if(i!==void 0)return i;try{let i=t(e,n,{allowFailure:!0,timeoutMs:5e3,maxBuffer:128*1024}),a=i.exitCode===0&&i.stdout.trim()||`unknown`;return C.set(r,a),a}catch{return C.set(r,`unknown`),`unknown`}}function Ce(e){return{version:e.match(/^Xcode\s+(.+)$/m)?.[1]?.trim()||`unknown`,buildVersion:e.match(/^Build version\s+(.+)$/m)?.[1]?.trim()||`unknown`}}function we(e,t){let n=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim();if(n)return m.resolve(n);let r=Ee(t),i=Te(e);return m.join(i,r)}function Te(e){return m.join(_e,`derived`,se(e))}function Ee(e){return`cache-${u.createHash(`sha256`).update(De(k(e))).digest(`hex`).slice(0,16)}`}function k(e){let{artifacts:t,packageVersion:n,...r}=e;return r}function De(e){return JSON.stringify(A(e))}function A(e){return Array.isArray(e)?e.map(e=>A(e)):!e||typeof e!=`object`?e:Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,A(t)]))}const j=new Map;function Oe(e){let t=S(e),n=Ae(t),r=ke(t,n),i=j.get(t);if(i?.fileStatsFingerprint===r)return i.sourceFingerprint;let a=u.createHash(`sha256`);for(let e of n){let n=m.relative(t,e);a.update(n),a.update(`\0`),a.update(d.readFileSync(e)),a.update(`\0`)}let o=a.digest(`hex`);return j.set(t,{fileStatsFingerprint:r,sourceFingerprint:o}),o}function ke(e,t){let n=u.createHash(`sha256`);for(let r of t){let t=m.relative(e,r),i=d.statSync(r);n.update(t),n.update(`\0`),n.update(String(i.size)),n.update(`\0`),n.update(String(Math.trunc(i.mtimeMs))),n.update(`\0`)}return n.digest(`hex`)}function Ae(e){if(!d.existsSync(e))return[];let t=[],n=[e];for(;n.length>0;){let e=n.pop();for(let r of d.readdirSync(e,{withFileTypes:!0})){let i=m.join(e,r.name);if(r.isDirectory()){if(r.name===`xcuserdata`)continue;n.push(i);continue}r.isFile()&&je(r.name,i)&&t.push(i)}}return t.sort((e,t)=>e.localeCompare(t))}function je(e,t){return e===`project.pbxproj`?t.includes(`${m.sep}.xcodeproj${m.sep}`):[`.jpg`,`.json`,`.png`,`.swift`,`.m`,`.h`,`.plist`,`.entitlements`,`.xctestplan`,`.xcconfig`,`.storyboard`,`.xib`].includes(m.extname(e))}function Me(e){return o(e)||e.kind===`device`?`-maximum-concurrent-test-device-destinations`:`-maximum-concurrent-test-simulator-destinations`}function M(e=process.env,t=!1,n={platform:`apple`}){if(o(n))return[`CODE_SIGNING_ALLOWED=NO`,`CODE_SIGNING_REQUIRED=NO`,`CODE_SIGN_IDENTITY=`,`DEVELOPMENT_TEAM=`];if(!t)return[];let r=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||``,i=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||``,a=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||``,s=[`CODE_SIGN_STYLE=Automatic`];return r&&s.push(`DEVELOPMENT_TEAM=${r}`),i&&s.push(`CODE_SIGN_IDENTITY=${i}`),a&&s.push(`PROVISIONING_PROFILE_SPECIFIER=${a}`),s}function N(e=process.env){let t=T(e),n=E(e);return[`AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID=${t}`,`AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID=${n}`]}function P(){return[`COMPILER_INDEX_STORE_ENABLE=NO`,`ENABLE_CODE_COVERAGE=NO`,`ONLY_ACTIVE_ARCH=YES`,`ENABLE_PREVIEWS=NO`,`ENABLE_DEBUG_DYLIB=NO`]}function F(){return[...ye,`OTHER_SWIFT_FLAGS=${Ne(process.env)}`]}function Ne(e){return te(e.AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS)?`$(inherited) -disable-sandbox -D AGENT_DEVICE_RUNNER_UNIT_TESTS`:`$(inherited) -disable-sandbox`}const Pe=18e4,Fe=6e4,Ie=6e4,Le=1e4,Re=15e3,ze=2e4,Be=15e3,I=2e4,Ve=1e3,He=5e3;async function L(t,n,i={}){let a=[`devicectl`,...t],o=await l(a,{allowFailure:!0,timeoutMs:i.timeoutMs??2e4});if(o.exitCode===0)return;let{stdout:s,stderr:c}=o;if(!i.tolerateOutput?.(s,c))throw new e(`COMMAND_FAILED`,`Failed to ${n.action}`,r(o,{cmd:`xcrun`,args:a,stdout:s,stderr:c,deviceId:n.deviceId,hint:G(s,c)??`Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.`}))}async function R(e,t){return Ye(qe(await B(e,{jsonPrefix:`agent-device-ios-apps`,args:[`devicectl`,`device`,`info`,`apps`,`--device`,e.id,`--include-all-apps`],failureMessage:`Failed to list iOS apps`,parseFailureMessage:`Failed to parse iOS apps list`})),t)}async function Ue(t){let n=await B(t,{jsonPrefix:`agent-device-ios-processes`,args:[`devicectl`,`device`,`info`,`processes`,`--device`,t.id],failureMessage:`Failed to list iOS processes`,parseFailureMessage:`Failed to parse iOS process list`,fallbackHint:W});if(!Ge(n))throw new e(`COMMAND_FAILED`,`Unsupported iOS process list response`,{deviceId:t.id,hint:W});return Je(n)}async function We(e,t){let{appBundleUrl:n,processes:r}=await z(e,t),i=r.sort((e,t)=>H(e,n)-H(t,n))[0];i&&await B(e,{jsonPrefix:`agent-device-ios-process-terminate`,args:[`devicectl`,`device`,`process`,`terminate`,`--device`,e.id,`--pid`,String(i.pid),`--kill`],failureMessage:`Failed to terminate iOS app`,parseFailureMessage:`Failed to parse iOS process termination response`,tolerateFailurePayload:Ke})}async function z(t,n){let r=(await R(t,`all`)).find(e=>e.bundleId===n);if(!r)throw new e(`APP_NOT_INSTALLED`,`No iOS device app found for ${n}`,{appBundleId:n,deviceId:t.id});if(!r.url)throw new e(`COMMAND_FAILED`,`Missing app bundle URL for ${n}`,{appBundleId:n,deviceId:t.id,hint:`Installed-app metadata from devicectl did not include the bundle URL required to match running processes. Use an Xcode/CoreDevice toolchain that reports app URLs.`});let i=r.url.replace(/\/+$/,``);return{appBundleUrl:i,processes:(await Ue(t)).filter(e=>e.executable.startsWith(`${i}/`))}}async function B(t,n){let i=m.join(p.tmpdir(),`${n.jsonPrefix}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),a=[...n.args,`--json-output`,i],o=await l(a,{allowFailure:!0,timeoutMs:2e4});try{if(o.exitCode!==0){let{stdout:s,stderr:c}=o;if(n.tolerateFailurePayload){let e=await V(i).catch(()=>void 0);if(e!==void 0&&n.tolerateFailurePayload(e))return e}throw new e(`COMMAND_FAILED`,n.failureMessage,r(o,{cmd:`xcrun`,args:a,stdout:s,stderr:c,deviceId:t.id,hint:G(s,c)??n.fallbackHint??`Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.`}))}return await V(i)}catch(r){throw r instanceof e?r:new e(`COMMAND_FAILED`,n.parseFailureMessage,{deviceId:t.id,cause:String(r)})}finally{await f.unlink(i).catch(()=>{})}}async function V(e){return JSON.parse(await f.readFile(e,`utf8`))}function H(e,t){return e.executable.slice(t.length+1).split(`/`).length}function Ge(e){return Array.isArray(e?.result?.runningProcesses)}function Ke(e){let t=e?.error?.userInfo?.NSUnderlyingError?.error;return t?.domain===`NSPOSIXErrorDomain`&&t.code===3}function qe(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let n=[];for(let e of t){if(!e||typeof e!=`object`)continue;let t=typeof e.bundleIdentifier==`string`?e.bundleIdentifier.trim():``;if(!t)continue;let r=typeof e.name==`string`&&e.name.trim().length>0?e.name.trim():t,i=typeof e.url==`string`&&e.url.trim().length>0?e.url.trim():void 0;n.push({bundleId:t,name:r,url:i})}return n}function Je(e){let t=e?.result?.runningProcesses;if(!Array.isArray(t))return[];let n=[];for(let e of t){if(!e||typeof e!=`object`)continue;let t=typeof e.executable==`string`?e.executable.trim():``,r=typeof e.processIdentifier==`number`&&Number.isFinite(e.processIdentifier)?e.processIdentifier:NaN;!t||!Number.isFinite(r)||n.push({executable:t,pid:r})}return n}function Ye(e,t){return ie(e,t)}const U=`Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.`,W=`This Xcode/CoreDevice toolchain must support 'devicectl device info processes' with JSON runningProcesses so agent-device can resolve app process IDs. Inspect diagnostics for the exact devicectl API failure.`;function G(e,t){let n=`${e}\n${t}`.toLowerCase();return n.includes(`device is busy`)&&n.includes(`connecting`)?`iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.`:n.includes(`coredeviceservice`)&&n.includes(`timed out`)?`CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.`:null}function K(e,t){return g(e,t)}function Xe(e,t,n){return l(K(e,t),n)}function q(e){return e.includes(`not installed`)||e.includes(`not found`)||e.includes(`no such file`)}async function Ze(e,t){return await R(e,t)}async function Qe(e,t){await L([`device`,`install`,`app`,`--device`,e.id,t],{action:`install iOS app`,deviceId:e.id},{timeoutMs:12e4})}async function $e(e,t){await L([`device`,`uninstall`,`app`,`--device`,e.id,t],{action:`uninstall iOS app ${t}`,deviceId:e.id},{tolerateOutput:(e,t)=>q(`${e}\n${t}`.toLowerCase())})}async function et(e,t){await We(e,t)}async function tt(e,t){return await z(e,t)}const J=1e4;async function nt(e,t,n={}){let r=[`device`,`process`,`launch`,`--device`,e.id,t];n.payloadUrl&&r.push(`--payload-url`,n.payloadUrl),n.launchArgs&&n.launchArgs.length>0&&r.push(`--`,...n.launchArgs),await L(r,{action:`launch iOS app`,deviceId:e.id})}async function rt(t){try{let{result:n,parsed:i}=await Y(t.id,15e3,3e3);if(n.exitCode===0){if(!i.parsed)throw new e(`COMMAND_FAILED`,`iOS device readiness probe failed`,{kind:`probe_inconclusive`,deviceId:t.id,stdout:n.stdout,stderr:n.stderr,hint:`CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device.`});let r=i.tunnelState?.toLowerCase();if(r===`connecting`)throw new e(`COMMAND_FAILED`,`iOS device is not ready for automation`,{kind:`not_ready`,deviceId:t.id,tunnelState:r,hint:`Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry.`});return}throw new e(`COMMAND_FAILED`,`iOS device is not ready for automation`,r(n,{kind:`not_ready`,deviceId:t.id,tunnelState:i.tunnelState,hint:Z(n.stdout,n.stderr)}))}catch(e){throw it(t.id,e)}}function it(t,n){return!(n instanceof e)||n.code!==`COMMAND_FAILED`?ot(t,n):(typeof n.details?.kind==`string`?n.details.kind:``)===`not_ready`?n:at(t,n)}function at(t,n){let r=n.details??{},i=String(r.stdout??``),a=String(r.stderr??``),o=Number(r.timeoutMs??15e3),s=`CoreDevice did not respond within ${o}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;return new e(`COMMAND_FAILED`,`iOS device readiness probe failed`,{deviceId:t,cause:n.message,timeoutMs:o,stdout:i,stderr:a,hint:i||a?Z(i,a):s},n)}function ot(t,n){return new e(`COMMAND_FAILED`,`iOS device readiness probe failed`,{deviceId:t,hint:`Reconnect the device, keep it unlocked, and retry.`},n instanceof Error?n:void 0)}async function st(e,t){if(typeof t==`number`&&t<=0)return null;let n=typeof t==`number`?Math.max(1,Math.min(J,t)):J;try{let t=await Y(e.id,n);return t.result.exitCode!==0||!t.parsed.parsed||t.parsed.outcome&&t.parsed.outcome!==`success`?null:t.parsed.tunnelIp??null}catch{return null}}async function Y(e,t,n=0){let r=m.join(p.tmpdir(),`agent-device-coredevice-info-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=Math.max(1,Math.ceil(t/1e3));try{return{result:await l([`devicectl`,`device`,`info`,`details`,`--device`,e,`--json-output`,r,`--timeout`,String(i)],{allowFailure:!0,timeoutMs:t+n}),parsed:await ct(r)}}finally{await f.rm(r,{force:!0}).catch(()=>{})}}async function ct(e){try{return{parsed:!0,...lt(JSON.parse(await f.readFile(e,`utf8`)))}}catch{return{parsed:!1}}}function lt(e){let t=e?.result;if(!t||typeof t!=`object`)return{};let n=t.connectionProperties,r=t.device?.connectionProperties,i=X(n?.tunnelState)??X(r?.tunnelState),a=X(n?.tunnelIPAddress)??X(r?.tunnelIPAddress),o=X(e?.info?.outcome);return{...o?{outcome:o}:{},...i?{tunnelState:i}:{},...a?{tunnelIp:a}:{}}}function X(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function Z(e,t){return G(e,t)||(`${e}\n${t}`.toLowerCase().includes(`timed out waiting for all destinations`)?`Xcode destination did not become available in time. Keep device unlocked and retry.`:U)}async function Q(t,n,r,i=I){let a=re.fromTimeoutMs(i),o={exitCode:1,stdout:``,stderr:``};for(let e of D)if(o=await l([`devicectl`,`device`,`copy`,`from`,`--device`,t.id,`--source`,n,`--destination`,r,`--domain-type`,`appDataContainer`,`--domain-identifier`,e],{allowFailure:!0,timeoutMs:ut(a,i)}),o.exitCode===0)return;throw new e(`COMMAND_FAILED`,`Failed to copy runner file from iOS device: ${o.stderr.trim()||o.stdout.trim()||`devicectl exited with code ${o.exitCode}`}`)}function ut(t,n){let r=t.remainingMs();if(r>0)return r;throw new e(`COMMAND_FAILED`,`iOS runner file copy timed out after ${n}ms`,{timeoutMs:n,step:`runner file copy`})}function $(t){if(!(t instanceof e))return{reason:t instanceof Error?t.message:String(t)};let n=t.details??{},r=Array.isArray(n.args)?n.args.filter(e=>typeof e==`string`).join(` `):void 0;return{errorCode:t.code,reason:t.message,timeoutMs:typeof n.timeoutMs==`number`?n.timeoutMs:void 0,exitCode:typeof n.exitCode==`number`?n.exitCode:void 0,stderr:typeof n.stderr==`string`&&n.stderr.trim()?n.stderr:void 0,stdout:typeof n.stdout==`string`&&n.stdout.trim()?n.stdout:void 0,commandArgs:r}}function dt(e){let t=e.details??{},n=typeof t.stdout==`string`?t.stdout:``,r=typeof t.stderr==`string`?t.stderr:``,i=Array.isArray(t.args)?t.args.filter(e=>typeof e==`string`).join(` `):``;return`${e.message}\n${n}\n${r}\n${i}`.toLowerCase()}async function ft(e,t,n){if(!n.preferRunner)try{await L([`device`,`screenshot`,`--device`,e.id,t],{action:`capture iOS screenshot`,deviceId:e.id});return}catch(t){if(!vt(t))throw t;_t(e,t)}let r=await mt(e,n,!1);await ht(r,t)||await Q(e,gt(r),t)}async function pt(t,n,r){if(!await ht(await mt(t,r,!0),n))throw new e(`COMMAND_FAILED`,`Failed to capture iOS screenshot: XCTest runner returned no inline image`,{deviceId:t.id,backend:`xctest`})}async function mt(e,t,n){return await t.runRunnerCommand(e,{command:`screenshot`,appBundleId:t.appBundleId,fullscreen:t.fullscreen,inlineScreenshot:n},t.runnerOptions??{})}async function ht(e,t){let n=e.imageBase64;return typeof n!=`string`||n.length===0?!1:(await f.writeFile(t,Buffer.from(n,`base64`)),!0)}function gt(t){let n=t.message;if(typeof n==`string`&&n.length>0)return n;throw new e(`COMMAND_FAILED`,`Failed to capture iOS screenshot: runner returned no file path`)}function _t(e,t){n({level:`warn`,phase:`ios_screenshot_fallback`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:`devicectl_screenshot`,to:`runner`,...$(t)}})}function vt(t){if(!(t instanceof e)||t.code!==`COMMAND_FAILED`)return!1;let n=dt(t);return n.includes(`unknown option '--device'`)||n.includes(`unknown subcommand`)&&n.includes(`screenshot`)||n.includes(`unrecognized subcommand`)&&n.includes(`screenshot`)}const yt={coredevice:{backend:`coredevice`,assertAppInstallationSupported:()=>{},ensureReady:rt,listApps:Ze,installApp:Qe,uninstallApp:$e,launchApp:nt,terminateApp:async(e,t)=>await et(e,t),resolveAppProcesses:tt,captureScreenshot:ft,copyRunnerFile:Q,resolveRunnerTransport:async(e,t)=>({kind:`network`,tunnelIp:await st(e,t)})},xctest:{backend:`xctest`,assertAppInstallationSupported:xt,ensureReady:Et,listApps:Ct,installApp:St,uninstallApp:St,launchApp:Dt,terminateApp:Ot,resolveAppProcesses:wt,captureScreenshot:pt,copyRunnerFile:Tt,resolveRunnerTransport:async()=>({kind:`usbmux`})}};function bt(e){return yt[e.iosPhysicalDeviceBackend===`xctest`?`xctest`:`coredevice`]}function xt(t){throw new e(`UNSUPPORTED_OPERATION`,`Installing apps is unavailable on this XCTest-backed physical iOS device.`,{deviceId:t.id,backend:`xctest`,hint:`Install the app with Xcode, then open it in agent-device by bundle ID.`})}async function St(e){return xt(e)}async function Ct(t){throw new e(`UNSUPPORTED_OPERATION`,`App inventory is unavailable on this XCTest-backed physical iOS device.`,{deviceId:t.id,backend:`xctest`,hint:`Use an installed app bundle ID when opening the device.`})}async function wt(t){throw new e(`UNSUPPORTED_OPERATION`,`Process lookup is unavailable on this XCTest-backed physical iOS device.`,{deviceId:t.id,backend:`xctest`,hint:`Use a CoreDevice-backed iOS device for performance sampling.`})}async function Tt(t){throw new e(`UNSUPPORTED_OPERATION`,`Runner file copy is unavailable on this XCTest-backed physical iOS device.`,{deviceId:t.id,backend:`xctest`})}async function Et(t){let n=[`xcdevice`,`wait`,`--both`,`--timeout=15`,t.id],i=await l(n,{allowFailure:!0,timeoutMs:18e3});if(i.exitCode!==0)throw new e(`COMMAND_FAILED`,`iOS device is not ready for XCTest automation`,r(i,{cmd:`xcrun`,args:n,deviceId:t.id,backend:`xctest`,hint:"Keep the device unlocked, trusted, connected, and visible in `xcrun xcdevice list`, then retry."}))}async function Dt(t,n,r){if(r.payloadUrl||r.launchArgs&&r.launchArgs.length>0)throw new e(`UNSUPPORTED_OPERATION`,`XCTest-backed physical iOS devices do not support deep links or launch arguments during open.`,{deviceId:t.id,backend:`xctest`,hint:`Open the installed app by bundle ID without a URL or --launch-args.`});await r.runRunnerCommand(t,{command:`activate`,appBundleId:n},r.runnerOptions??{})}async function Ot(e,t,n){await n.runRunnerCommand(e,{command:`terminate`,appBundleId:t},n.runnerOptions??{})}export{De as A,T as C,P as D,Me as E,ce as F,h as I,g as L,x as M,ue as N,F as O,le as P,ae as R,xe as S,we as T,ze as _,Xe as a,ve as b,G as c,I as d,Fe as f,Be as g,He as h,q as i,ge as j,M as k,Ie as l,Ve as m,dt as n,K as o,Le as p,$ as r,U as s,bt as t,Pe as u,Re as v,N as w,k as x,D as y};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./xml.js";import{i as n,n as r}from"./tool-provider.js";import{promises as i}from"node:fs";async function a(e,t){try{let n=(await r(e))?.[t];if(typeof n==`string`&&n.length>0)return n}catch{}try{let r=await n(`plutil`,[`-extract`,t,`raw`,`-o`,`-`,e],{allowFailure:!0});if(r.exitCode===0){let e=r.stdout.trim();if(e.length>0)return e}}catch{}try{return o(await i.readFile(e,`utf8`),t)}catch{return}}function o(n,r){let i;return e(t(n),(e,t)=>{i!==void 0||e!==r||t.name!==`string`||(i=t.text??void 0)}),i}export{a as t};
|
package/dist/src/react-native.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{S as e}from"./sdk-contracts.js";import{
|
|
1
|
+
import{S as e}from"./sdk-contracts.js";import{T as t}from"./sdk-batch-runner.js";import{On as n,vn as r}from"./recording-export-quality.js";import{_ as i}from"./gesture-plan-types.js";import{f as a}from"./runtime.js";import{c as o,l as s,n as c,s as l}from"./context.js";import{Ft as u}from"./internal/daemon.js";import{i as d,n as f,t as p}from"./interaction-snapshot.js";async function m(t){let{req:r,sessionName:c,sessionStore:l}=t;if(r.command!==n.reactNative)return null;let u=h(r.positionals??[]);if(!u.ok)return u.response;let d=l.get(c);if(!d)return o();let f=s(n.reactNative,d.device,{message:`react-native dismiss-overlay is not supported on this device`});if(f)return f;try{let e=await p(d,r.flags,l,t.contextFromFlags,{interactiveOnly:!0});if(i(e.snapshotQuality))return _(e.snapshotQuality);let n=a(e.nodes),o=n.primaryAction;return o?await v(t,d,e,o):g(n.detected)}catch(t){return{ok:!1,error:e(t)}}}function h(e){return e.length===1&&e[0]===`dismiss-overlay`?{ok:!0}:{ok:!1,response:l(`INVALID_ARGS`,`react-native supports only: dismiss-overlay`)}}function g(e){return e?l(`COMMAND_FAILED`,`React Native overlay detected, but no safe dismiss target was found`,{hint:`Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body.`}):{ok:!0,data:{action:`dismiss-overlay`,detected:!1,dismissed:!1,...r(`No React Native overlay detected`)}}}function _(e){return l(`COMMAND_FAILED`,`React Native overlay state could not be determined because the accessibility tree is unreadable`,{reason:e.reason,hint:`The snapshot quality verdict is sparse. Use screenshot as visual truth; if an overlay is visible, report it or navigate with coordinates, then retry snapshot or dismiss-overlay on a readable screen.`})}async function v(e,n,i,a){let{req:o,sessionStore:s}=e,l=Date.now();u(n);let p=await c(n.device,`press`,[String(a.point.x),String(a.point.y)],o.flags?.out,e.contextFromFlags(o.flags,n.appBundleId,n.trace?.outPath))??{},m=Date.now(),h=await y(e,n),g=t({...f(i.nodes),...p,action:`dismiss-overlay`,overlayAction:a.action,x:a.point.x,y:a.point.y,ref:a.ref,label:a.label,warning:a.warning,dismissed:!0,verified:h.verified,verificationRequired:!h.verified,verificationWarning:h.verificationWarning,nextCommand:h.nextCommand,...r(b(h))});return d({session:n,sessionStore:s,command:o.command,positionals:o.positionals??[],flags:o.flags,result:g,responseData:g,actionStartedAt:l,actionFinishedAt:m})}async function y(e,t){let{req:n,sessionStore:r}=e,o=await p(t,n.flags,r,e.contextFromFlags,{interactiveOnly:!0});return i(o.snapshotQuality)?{verified:!1,verificationWarning:`React Native overlay dismissal could not be verified because the post-dismiss accessibility tree is unreadable. Use screenshot as visual truth.`,nextCommand:`agent-device screenshot`}:a(o.nodes).detected?{verified:!1,verificationWarning:`React Native overlay is still detected after dismissal. Use screenshot --overlay-refs for visual evidence and report the overlay instead of pressing the warning body.`,nextCommand:`agent-device screenshot --overlay-refs`}:{verified:!0}}function b(e){return e.verified?`React Native overlay dismiss action sent and verified gone`:`React Native overlay dismiss action sent, but verification still detects an overlay`}export{m as handleReactNativeCommands};
|