agent-device 0.12.5 → 0.12.6
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/dist/src/641.js +33 -33
- package/dist/src/backend.d.ts +326 -4
- package/dist/src/bin.js +32 -32
- package/dist/src/commands/index.d.ts +978 -6
- package/dist/src/commands/index.js +1 -1
- package/dist/src/daemon.js +15 -15
- package/dist/src/index.d.ts +977 -5
- package/dist/src/index.js +3 -3
- package/dist/src/testing/conformance.d.ts +341 -4
- package/dist/src/testing/conformance.js +1 -1
- package/package.json +1 -1
- package/skills/agent-device/references/macos-desktop.md +1 -1
- package/skills/agent-device/references/remote-tenancy.md +13 -5
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export declare const adminConformanceSuite: CommandConformanceSuite;
|
|
2
|
+
|
|
1
3
|
declare type AgentDeviceBackend = {
|
|
2
4
|
platform: AgentDeviceBackendPlatform;
|
|
3
5
|
capabilities?: BackendCapabilitySet;
|
|
@@ -11,12 +13,44 @@ declare type AgentDeviceBackend = {
|
|
|
11
13
|
typeText?(context: BackendCommandContext, text: string, options?: {
|
|
12
14
|
delayMs?: number;
|
|
13
15
|
}): Promise<BackendActionResult>;
|
|
16
|
+
focus?(context: BackendCommandContext, point: Point): Promise<BackendActionResult>;
|
|
17
|
+
longPress?(context: BackendCommandContext, point: Point, options?: BackendLongPressOptions): Promise<BackendActionResult>;
|
|
18
|
+
swipe?(context: BackendCommandContext, from: Point, to: Point, options?: BackendSwipeOptions): Promise<BackendActionResult>;
|
|
19
|
+
scroll?(context: BackendCommandContext, target: BackendScrollTarget, options: BackendScrollOptions): Promise<BackendActionResult>;
|
|
20
|
+
pinch?(context: BackendCommandContext, options: BackendPinchOptions): Promise<BackendActionResult>;
|
|
14
21
|
pressKey?(context: BackendCommandContext, key: string, options?: {
|
|
15
22
|
modifiers?: string[];
|
|
16
23
|
}): Promise<BackendActionResult>;
|
|
17
|
-
|
|
24
|
+
pressBack?(context: BackendCommandContext, options?: BackendBackOptions): Promise<BackendActionResult>;
|
|
25
|
+
pressHome?(context: BackendCommandContext): Promise<BackendActionResult>;
|
|
26
|
+
rotate?(context: BackendCommandContext, orientation: BackendDeviceOrientation): Promise<BackendActionResult>;
|
|
27
|
+
setKeyboard?(context: BackendCommandContext, options: BackendKeyboardOptions): Promise<BackendKeyboardResult | BackendActionResult>;
|
|
28
|
+
getClipboard?(context: BackendCommandContext): Promise<string | BackendClipboardTextResult>;
|
|
29
|
+
setClipboard?(context: BackendCommandContext, text: string): Promise<BackendActionResult>;
|
|
30
|
+
openSettings?(context: BackendCommandContext, target?: string): Promise<BackendActionResult>;
|
|
31
|
+
handleAlert?(context: BackendCommandContext, action: BackendAlertAction, options?: {
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}): Promise<BackendAlertResult>;
|
|
34
|
+
openAppSwitcher?(context: BackendCommandContext): Promise<BackendActionResult>;
|
|
35
|
+
openApp?(context: BackendCommandContext, target: BackendOpenTarget, options?: BackendOpenOptions): Promise<BackendActionResult>;
|
|
18
36
|
closeApp?(context: BackendCommandContext, app?: string): Promise<BackendActionResult>;
|
|
19
|
-
|
|
37
|
+
listApps?(context: BackendCommandContext, filter?: BackendAppListFilter): Promise<readonly BackendAppInfo[]>;
|
|
38
|
+
getAppState?(context: BackendCommandContext, app: string): Promise<BackendAppState>;
|
|
39
|
+
pushFile?(context: BackendCommandContext, input: BackendPushInput, target: string): Promise<BackendActionResult>;
|
|
40
|
+
triggerAppEvent?(context: BackendCommandContext, event: BackendAppEvent): Promise<BackendActionResult>;
|
|
41
|
+
listDevices?(context: BackendCommandContext, filter?: BackendDeviceFilter): Promise<readonly BackendDeviceInfo[]>;
|
|
42
|
+
bootDevice?(context: BackendCommandContext, target?: BackendDeviceTarget): Promise<BackendActionResult>;
|
|
43
|
+
ensureSimulator?(context: BackendCommandContext, options: BackendEnsureSimulatorOptions): Promise<BackendEnsureSimulatorResult>;
|
|
44
|
+
resolveInstallSource?(context: BackendCommandContext, source: BackendInstallSource): Promise<BackendInstallSource>;
|
|
45
|
+
installApp?(context: BackendCommandContext, target: BackendInstallTarget): Promise<BackendInstallResult>;
|
|
46
|
+
reinstallApp?(context: BackendCommandContext, target: BackendInstallTarget): Promise<BackendInstallResult>;
|
|
47
|
+
startRecording?(context: BackendCommandContext, options?: BackendRecordingOptions): Promise<BackendRecordingResult>;
|
|
48
|
+
stopRecording?(context: BackendCommandContext, options?: BackendRecordingOptions): Promise<BackendRecordingResult>;
|
|
49
|
+
startTrace?(context: BackendCommandContext, options?: BackendTraceOptions): Promise<BackendTraceResult>;
|
|
50
|
+
stopTrace?(context: BackendCommandContext, options?: BackendTraceOptions): Promise<BackendTraceResult>;
|
|
51
|
+
readLogs?(context: BackendCommandContext, options?: BackendReadLogsOptions): Promise<BackendReadLogsResult>;
|
|
52
|
+
dumpNetwork?(context: BackendCommandContext, options?: BackendDumpNetworkOptions): Promise<BackendDumpNetworkResult>;
|
|
53
|
+
measurePerf?(context: BackendCommandContext, options?: BackendMeasurePerfOptions): Promise<BackendMeasurePerfResult>;
|
|
20
54
|
};
|
|
21
55
|
|
|
22
56
|
declare type AgentDeviceBackendPlatform = 'ios' | 'android' | 'macos' | 'linux';
|
|
@@ -31,6 +65,8 @@ declare type AgentDeviceRuntime = {
|
|
|
31
65
|
signal?: AbortSignal;
|
|
32
66
|
};
|
|
33
67
|
|
|
68
|
+
export declare const appsConformanceSuite: CommandConformanceSuite;
|
|
69
|
+
|
|
34
70
|
declare type ArtifactAdapter = {
|
|
35
71
|
resolveInput(ref: FileInputRef, options: ResolveInputOptions): Promise<ResolvedInputFile>;
|
|
36
72
|
reserveOutput(ref: FileOutputRef | undefined, options: ReserveOutputOptions): Promise<ReservedOutputFile>;
|
|
@@ -61,10 +97,65 @@ declare const BACKEND_CAPABILITY_NAMES: readonly ["android.shell", "ios.runnerCo
|
|
|
61
97
|
|
|
62
98
|
declare type BackendActionResult = Record<string, unknown> | void;
|
|
63
99
|
|
|
100
|
+
declare type BackendAlertAction = 'get' | 'accept' | 'dismiss' | 'wait';
|
|
101
|
+
|
|
102
|
+
declare type BackendAlertInfo = {
|
|
103
|
+
title?: string;
|
|
104
|
+
message?: string;
|
|
105
|
+
buttons?: string[];
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
declare type BackendAlertResult = {
|
|
109
|
+
kind: 'alertStatus';
|
|
110
|
+
alert: BackendAlertInfo | null;
|
|
111
|
+
} | {
|
|
112
|
+
kind: 'alertHandled';
|
|
113
|
+
handled: boolean;
|
|
114
|
+
alert?: BackendAlertInfo;
|
|
115
|
+
button?: string;
|
|
116
|
+
} | {
|
|
117
|
+
kind: 'alertWait';
|
|
118
|
+
alert: BackendAlertInfo | null;
|
|
119
|
+
waitedMs?: number;
|
|
120
|
+
timedOut?: boolean;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
declare type BackendAppEvent = {
|
|
124
|
+
name: string;
|
|
125
|
+
payload?: Record<string, unknown>;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
declare type BackendAppInfo = {
|
|
129
|
+
id: string;
|
|
130
|
+
name?: string;
|
|
131
|
+
bundleId?: string;
|
|
132
|
+
packageName?: string;
|
|
133
|
+
activity?: string;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
declare type BackendAppListFilter = 'all' | 'user-installed';
|
|
137
|
+
|
|
138
|
+
declare type BackendAppState = {
|
|
139
|
+
appId?: string;
|
|
140
|
+
bundleId?: string;
|
|
141
|
+
packageName?: string;
|
|
142
|
+
activity?: string;
|
|
143
|
+
state?: 'unknown' | 'notRunning' | 'running' | 'foreground' | 'background';
|
|
144
|
+
details?: Record<string, unknown>;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
declare type BackendBackOptions = {
|
|
148
|
+
mode?: 'in-app' | 'system';
|
|
149
|
+
};
|
|
150
|
+
|
|
64
151
|
declare type BackendCapabilityName = (typeof BACKEND_CAPABILITY_NAMES)[number];
|
|
65
152
|
|
|
66
153
|
declare type BackendCapabilitySet = readonly BackendCapabilityName[];
|
|
67
154
|
|
|
155
|
+
declare type BackendClipboardTextResult = {
|
|
156
|
+
text: string;
|
|
157
|
+
};
|
|
158
|
+
|
|
68
159
|
declare type BackendCommandContext = {
|
|
69
160
|
session?: string;
|
|
70
161
|
requestId?: string;
|
|
@@ -74,6 +165,71 @@ declare type BackendCommandContext = {
|
|
|
74
165
|
metadata?: Record<string, unknown>;
|
|
75
166
|
};
|
|
76
167
|
|
|
168
|
+
declare type BackendDeviceFilter = {
|
|
169
|
+
platform?: AgentDeviceBackendPlatform | 'apple';
|
|
170
|
+
target?: 'mobile' | 'tv' | 'desktop';
|
|
171
|
+
kind?: 'simulator' | 'emulator' | 'device' | 'desktop';
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
declare type BackendDeviceInfo = {
|
|
175
|
+
id: string;
|
|
176
|
+
name: string;
|
|
177
|
+
platform: AgentDeviceBackendPlatform;
|
|
178
|
+
target?: 'mobile' | 'tv' | 'desktop';
|
|
179
|
+
kind?: 'simulator' | 'emulator' | 'device' | 'desktop';
|
|
180
|
+
booted?: boolean;
|
|
181
|
+
details?: Record<string, unknown>;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
declare type BackendDeviceOrientation = 'portrait' | 'portrait-upside-down' | 'landscape-left' | 'landscape-right';
|
|
185
|
+
|
|
186
|
+
declare type BackendDeviceTarget = {
|
|
187
|
+
id?: string;
|
|
188
|
+
name?: string;
|
|
189
|
+
platform?: AgentDeviceBackendPlatform;
|
|
190
|
+
target?: 'mobile' | 'tv' | 'desktop';
|
|
191
|
+
headless?: boolean;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
declare type BackendDiagnosticsPageOptions = BackendDiagnosticsTimeWindow & {
|
|
195
|
+
cursor?: string;
|
|
196
|
+
limit?: number;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
declare type BackendDiagnosticsTimeWindow = {
|
|
200
|
+
since?: string;
|
|
201
|
+
until?: string;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
declare type BackendDumpNetworkOptions = BackendDiagnosticsPageOptions & {
|
|
205
|
+
include?: BackendNetworkIncludeMode;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
declare type BackendDumpNetworkResult = {
|
|
209
|
+
entries: readonly BackendNetworkEntry[];
|
|
210
|
+
nextCursor?: string;
|
|
211
|
+
timeWindow?: BackendDiagnosticsTimeWindow;
|
|
212
|
+
backend?: string;
|
|
213
|
+
redacted?: boolean;
|
|
214
|
+
notes?: readonly string[];
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
declare type BackendEnsureSimulatorOptions = {
|
|
218
|
+
device: string;
|
|
219
|
+
runtime?: string;
|
|
220
|
+
boot?: boolean;
|
|
221
|
+
reuseExisting?: boolean;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
declare type BackendEnsureSimulatorResult = {
|
|
225
|
+
udid: string;
|
|
226
|
+
device: string;
|
|
227
|
+
runtime: string;
|
|
228
|
+
created: boolean;
|
|
229
|
+
booted: boolean;
|
|
230
|
+
simulatorSetPath?: string | null;
|
|
231
|
+
};
|
|
232
|
+
|
|
77
233
|
declare type BackendEscapeHatches = {
|
|
78
234
|
androidShell?(context: BackendCommandContext, args: readonly string[]): Promise<BackendShellResult>;
|
|
79
235
|
iosRunnerCommand?(context: BackendCommandContext, command: BackendRunnerCommand): Promise<BackendActionResult>;
|
|
@@ -88,21 +244,166 @@ declare type BackendFindTextResult = {
|
|
|
88
244
|
found: boolean;
|
|
89
245
|
};
|
|
90
246
|
|
|
247
|
+
declare type BackendInstallResult = Record<string, unknown> & {
|
|
248
|
+
appId?: string;
|
|
249
|
+
appName?: string;
|
|
250
|
+
bundleId?: string;
|
|
251
|
+
packageName?: string;
|
|
252
|
+
launchTarget?: string;
|
|
253
|
+
installablePath?: string;
|
|
254
|
+
archivePath?: string;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
declare type BackendInstallSource = {
|
|
258
|
+
kind: 'path';
|
|
259
|
+
path: string;
|
|
260
|
+
} | {
|
|
261
|
+
kind: 'uploadedArtifact';
|
|
262
|
+
id: string;
|
|
263
|
+
} | {
|
|
264
|
+
kind: 'url';
|
|
265
|
+
url: string;
|
|
266
|
+
};
|
|
267
|
+
|
|
91
268
|
declare type BackendInstallTarget = {
|
|
92
|
-
app
|
|
93
|
-
|
|
269
|
+
app?: string;
|
|
270
|
+
source: BackendInstallSource;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
declare type BackendKeyboardOptions = {
|
|
274
|
+
action: 'status' | 'get' | 'dismiss';
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
declare type BackendKeyboardResult = {
|
|
278
|
+
platform?: 'android' | 'ios' | 'macos' | 'linux';
|
|
279
|
+
action?: BackendKeyboardOptions['action'];
|
|
280
|
+
visible?: boolean;
|
|
281
|
+
inputType?: string | null;
|
|
282
|
+
type?: string | null;
|
|
283
|
+
wasVisible?: boolean;
|
|
284
|
+
dismissed?: boolean;
|
|
285
|
+
attempts?: number;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
declare type BackendLogEntry = {
|
|
289
|
+
timestamp?: string;
|
|
290
|
+
level?: 'debug' | 'info' | 'warn' | 'error' | string;
|
|
291
|
+
message: string;
|
|
292
|
+
source?: string;
|
|
293
|
+
metadata?: Record<string, unknown>;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
declare type BackendLongPressOptions = {
|
|
297
|
+
durationMs?: number;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
declare type BackendMeasurePerfOptions = BackendDiagnosticsTimeWindow & {
|
|
301
|
+
sampleMs?: number;
|
|
302
|
+
metrics?: readonly string[];
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
declare type BackendMeasurePerfResult = {
|
|
306
|
+
metrics: readonly BackendPerfMetric[];
|
|
307
|
+
startedAt?: string;
|
|
308
|
+
endedAt?: string;
|
|
309
|
+
backend?: string;
|
|
310
|
+
redacted?: boolean;
|
|
311
|
+
notes?: readonly string[];
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
declare type BackendNetworkEntry = {
|
|
315
|
+
timestamp?: string;
|
|
316
|
+
method?: string;
|
|
317
|
+
url?: string;
|
|
318
|
+
status?: number;
|
|
319
|
+
durationMs?: number;
|
|
320
|
+
requestHeaders?: Record<string, string>;
|
|
321
|
+
responseHeaders?: Record<string, string>;
|
|
322
|
+
requestBody?: string;
|
|
323
|
+
responseBody?: string;
|
|
324
|
+
metadata?: Record<string, unknown>;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
declare type BackendNetworkIncludeMode = 'summary' | 'headers' | 'body' | 'all';
|
|
328
|
+
|
|
329
|
+
declare type BackendOpenOptions = {
|
|
330
|
+
relaunch?: boolean;
|
|
94
331
|
};
|
|
95
332
|
|
|
96
333
|
declare type BackendOpenTarget = {
|
|
334
|
+
/**
|
|
335
|
+
* Generic app identifier accepted by the backend. Hosted adapters should
|
|
336
|
+
* prefer structured appId, bundleId, or packageName when available.
|
|
337
|
+
*/
|
|
97
338
|
app?: string;
|
|
339
|
+
appId?: string;
|
|
340
|
+
bundleId?: string;
|
|
341
|
+
packageName?: string;
|
|
342
|
+
/**
|
|
343
|
+
* URL may be used by itself for a deep link or with an app identifier when
|
|
344
|
+
* the backend supports opening a URL in a specific app context.
|
|
345
|
+
*/
|
|
98
346
|
url?: string;
|
|
347
|
+
/**
|
|
348
|
+
* Platform-specific activity override, primarily for Android app launches.
|
|
349
|
+
*/
|
|
99
350
|
activity?: string;
|
|
100
351
|
};
|
|
101
352
|
|
|
353
|
+
declare type BackendPerfMetric = {
|
|
354
|
+
name: string;
|
|
355
|
+
value?: number;
|
|
356
|
+
unit?: string;
|
|
357
|
+
status?: 'ok' | 'unavailable' | 'error';
|
|
358
|
+
message?: string;
|
|
359
|
+
metadata?: Record<string, unknown>;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
declare type BackendPinchOptions = {
|
|
363
|
+
scale: number;
|
|
364
|
+
center?: Point;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
declare type BackendPushInput = {
|
|
368
|
+
kind: 'json';
|
|
369
|
+
payload: Record<string, unknown>;
|
|
370
|
+
} | {
|
|
371
|
+
kind: 'file';
|
|
372
|
+
path: string;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
declare type BackendReadLogsOptions = BackendDiagnosticsPageOptions & {
|
|
376
|
+
levels?: readonly string[];
|
|
377
|
+
search?: string;
|
|
378
|
+
source?: string;
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
declare type BackendReadLogsResult = {
|
|
382
|
+
entries: readonly BackendLogEntry[];
|
|
383
|
+
nextCursor?: string;
|
|
384
|
+
timeWindow?: BackendDiagnosticsTimeWindow;
|
|
385
|
+
backend?: string;
|
|
386
|
+
redacted?: boolean;
|
|
387
|
+
notes?: readonly string[];
|
|
388
|
+
};
|
|
389
|
+
|
|
102
390
|
declare type BackendReadTextResult = {
|
|
103
391
|
text: string;
|
|
104
392
|
};
|
|
105
393
|
|
|
394
|
+
declare type BackendRecordingOptions = {
|
|
395
|
+
outPath?: string;
|
|
396
|
+
fps?: number;
|
|
397
|
+
quality?: number;
|
|
398
|
+
showTouches?: boolean;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
declare type BackendRecordingResult = Record<string, unknown> & {
|
|
402
|
+
path?: string;
|
|
403
|
+
telemetryPath?: string;
|
|
404
|
+
warning?: string;
|
|
405
|
+
};
|
|
406
|
+
|
|
106
407
|
declare type BackendRunnerCommand = {
|
|
107
408
|
command: string;
|
|
108
409
|
args?: readonly string[];
|
|
@@ -120,6 +421,19 @@ declare type BackendScreenshotResult = {
|
|
|
120
421
|
overlayRefs?: ScreenshotOverlayRef[];
|
|
121
422
|
};
|
|
122
423
|
|
|
424
|
+
declare type BackendScrollOptions = {
|
|
425
|
+
direction: 'up' | 'down' | 'left' | 'right';
|
|
426
|
+
amount?: number;
|
|
427
|
+
pixels?: number;
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
declare type BackendScrollTarget = {
|
|
431
|
+
kind: 'viewport';
|
|
432
|
+
} | {
|
|
433
|
+
kind: 'point';
|
|
434
|
+
point: Point;
|
|
435
|
+
};
|
|
436
|
+
|
|
123
437
|
declare type BackendShellResult = {
|
|
124
438
|
exitCode: number;
|
|
125
439
|
stdout: string;
|
|
@@ -154,6 +468,10 @@ declare type BackendSnapshotResult = {
|
|
|
154
468
|
appBundleId?: string;
|
|
155
469
|
};
|
|
156
470
|
|
|
471
|
+
declare type BackendSwipeOptions = {
|
|
472
|
+
durationMs?: number;
|
|
473
|
+
};
|
|
474
|
+
|
|
157
475
|
declare type BackendTapOptions = {
|
|
158
476
|
button?: 'primary' | 'secondary' | 'middle';
|
|
159
477
|
count?: number;
|
|
@@ -163,6 +481,14 @@ declare type BackendTapOptions = {
|
|
|
163
481
|
doubleTap?: boolean;
|
|
164
482
|
};
|
|
165
483
|
|
|
484
|
+
declare type BackendTraceOptions = {
|
|
485
|
+
outPath?: string;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
declare type BackendTraceResult = Record<string, unknown> & {
|
|
489
|
+
outPath?: string;
|
|
490
|
+
};
|
|
491
|
+
|
|
166
492
|
export declare const captureConformanceSuite: CommandConformanceSuite;
|
|
167
493
|
|
|
168
494
|
declare type CommandClock = {
|
|
@@ -191,11 +517,16 @@ export declare type CommandConformanceFailure = {
|
|
|
191
517
|
|
|
192
518
|
export declare type CommandConformanceFixtures = {
|
|
193
519
|
session: string;
|
|
520
|
+
app: string;
|
|
521
|
+
installSourcePath: string;
|
|
522
|
+
appEventName: string;
|
|
523
|
+
appPushPayload: Record<string, unknown>;
|
|
194
524
|
visibleSelector: string;
|
|
195
525
|
visibleText: string;
|
|
196
526
|
editableTarget: InteractionTarget;
|
|
197
527
|
fillText: string;
|
|
198
528
|
point: Point;
|
|
529
|
+
swipeTo: Point;
|
|
199
530
|
};
|
|
200
531
|
|
|
201
532
|
export declare type CommandConformanceReport = {
|
|
@@ -262,6 +593,8 @@ declare type CreateTempFileOptions = {
|
|
|
262
593
|
|
|
263
594
|
export declare const defaultCommandConformanceFixtures: CommandConformanceFixtures;
|
|
264
595
|
|
|
596
|
+
export declare const diagnosticsConformanceSuite: CommandConformanceSuite;
|
|
597
|
+
|
|
265
598
|
declare type DiagnosticsSink = {
|
|
266
599
|
emit(event: {
|
|
267
600
|
level: 'debug' | 'info' | 'warn' | 'error';
|
|
@@ -329,6 +662,8 @@ declare type RawSnapshotNode = {
|
|
|
329
662
|
hiddenContentBelow?: boolean;
|
|
330
663
|
};
|
|
331
664
|
|
|
665
|
+
export declare const recordingConformanceSuite: CommandConformanceSuite;
|
|
666
|
+
|
|
332
667
|
declare type Rect = {
|
|
333
668
|
x: number;
|
|
334
669
|
y: number;
|
|
@@ -407,6 +742,8 @@ declare type SnapshotState = {
|
|
|
407
742
|
comparisonSafe?: boolean;
|
|
408
743
|
};
|
|
409
744
|
|
|
745
|
+
export declare const systemConformanceSuite: CommandConformanceSuite;
|
|
746
|
+
|
|
410
747
|
declare type TemporaryFile = {
|
|
411
748
|
path: string;
|
|
412
749
|
visibility: 'internal';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:assert/strict";import{commands as
|
|
1
|
+
import e from"node:assert/strict";import{commands as a,selector as s}from"../commands/index.js";let t={session:"default",app:"com.example.app",installSourcePath:"/tmp/example.app",appEventName:"example.ready",appPushPayload:{aps:{alert:"hello"}},visibleSelector:"label=Continue",visibleText:"Continue",editableTarget:s("label=Email"),fillText:"hello@example.com",point:{x:4,y:8},swipeTo:{x:24,y:28}},n=w({name:"capture",cases:[{name:"captures screenshots through the backend primitive",command:"capture.screenshot",run:async(s,t)=>{let n=await a.capture.screenshot(s,{session:t.session});e.equal(typeof n.path,"string"),e.ok(n.path.length>0)}},{name:"captures snapshots with nodes",command:"capture.snapshot",run:async(s,t)=>{let n=await a.capture.snapshot(s,{session:t.session});e.ok(Array.isArray(n.nodes))}}]}),i=w({name:"selectors",cases:[{name:"finds visible text",command:"selectors.find",run:async(s,t)=>{let n=await a.selectors.find(s,{session:t.session,query:t.visibleText,action:"exists"});e.equal(n.kind,"found"),e.equal(n.found,!0)}},{name:"reads text from a selector",command:"selectors.getText",run:async(t,n)=>{let i=await a.selectors.getText(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"text"),e.equal(i.text,n.visibleText)}},{name:"checks selector visibility",command:"selectors.isVisible",run:async(t,n)=>{let i=await a.selectors.isVisible(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.pass,!0)}},{name:"waits for visible text",command:"selectors.waitForText",run:async(s,t)=>{let n=await a.selectors.waitForText(s,{session:t.session,text:t.visibleText,timeoutMs:1});e.equal(n.kind,"text"),e.equal(n.text,t.visibleText)}}]}),o=w({name:"interactions",cases:[{name:"clicks selector targets",command:"interactions.click",run:async(t,n)=>{let i=await a.interactions.click(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"selector")}},{name:"presses explicit points",command:"interactions.press",run:async(s,t)=>{let n=await a.interactions.press(s,{session:t.session,target:{kind:"point",...t.point}});e.deepEqual(n.point,t.point)}},{name:"fills editable targets",command:"interactions.fill",run:async(s,t)=>{let n=await a.interactions.fill(s,{session:t.session,target:t.editableTarget,text:t.fillText});e.equal(n.text,t.fillText)}},{name:"types text without a target",command:"interactions.typeText",run:async(s,t)=>{let n=await a.interactions.typeText(s,{session:t.session,text:t.fillText});e.equal(n.text,t.fillText)}},{name:"focuses selector targets",command:"interactions.focus",run:async(t,n)=>{let i=await a.interactions.focus(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"selector")}},{name:"long presses selector targets",command:"interactions.longPress",run:async(t,n)=>{let i=await a.interactions.longPress(t,{session:n.session,target:s(n.visibleSelector),durationMs:500});e.equal(i.kind,"selector")}},{name:"swipes explicit points",command:"interactions.swipe",run:async(s,t)=>{let n=await a.interactions.swipe(s,{session:t.session,from:t.point,to:t.swipeTo});e.deepEqual(n.from,t.point)}},{name:"scrolls viewport targets",command:"interactions.scroll",run:async(s,t)=>{let n=await a.interactions.scroll(s,{session:t.session,target:{kind:"viewport"},direction:"down"});e.equal(n.kind,"viewport")}},{name:"pinches through the backend primitive",command:"interactions.pinch",run:async s=>{let t=await a.interactions.pinch(s,{scale:1.1});e.equal(t.kind,"pinch")}}]}),r=w({name:"system",cases:[{name:"presses back",command:"system.back",run:async(s,t)=>{let n=await a.system.back(s,{session:t.session,mode:"in-app"});e.equal(n.kind,"systemBack")}},{name:"presses home",command:"system.home",run:async(s,t)=>{let n=await a.system.home(s,{session:t.session});e.equal(n.kind,"systemHome")}},{name:"rotates devices",command:"system.rotate",run:async(s,t)=>{let n=await a.system.rotate(s,{session:t.session,orientation:"portrait"});e.equal(n.orientation,"portrait")}},{name:"reads keyboard state",command:"system.keyboard",run:async(s,t)=>{let n=await a.system.keyboard(s,{session:t.session,action:"status"});e.equal(n.kind,"keyboardState")}},{name:"reads clipboard text",command:"system.clipboard",run:async(s,t)=>{let n=await a.system.clipboard(s,{session:t.session,action:"read"});e.equal(n.kind,"clipboardText")}},{name:"opens settings",command:"system.settings",run:async(s,t)=>{let n=await a.system.settings(s,{session:t.session});e.equal(n.kind,"settingsOpened")}},{name:"reads alert state",command:"system.alert",run:async(s,t)=>{let n=await a.system.alert(s,{session:t.session,action:"get"});e.equal(n.kind,"alertStatus")}},{name:"opens app switcher",command:"system.appSwitcher",run:async(s,t)=>{let n=await a.system.appSwitcher(s,{session:t.session});e.equal(n.kind,"appSwitcherOpened")}}]}),c=w({name:"apps",cases:[{name:"opens apps by id",command:"apps.open",run:async(s,t)=>{let n=await a.apps.open(s,{session:t.session,app:t.app});e.equal(n.kind,"appOpened"),e.equal(n.target.app,t.app)}},{name:"closes apps by id",command:"apps.close",run:async(s,t)=>{let n=await a.apps.close(s,{session:t.session,app:t.app});e.equal(n.kind,"appClosed"),e.equal(n.app,t.app)}},{name:"lists apps",command:"apps.list",run:async s=>{let t=await a.apps.list(s,{filter:"all"});e.equal(t.kind,"appsList"),e.ok(Array.isArray(t.apps))}},{name:"reads app state",command:"apps.state",run:async(s,t)=>{let n=await a.apps.state(s,{session:t.session,app:t.app});e.equal(n.kind,"appState"),e.equal(n.app,t.app)}},{name:"pushes app payloads",command:"apps.push",run:async(s,t)=>{let n=await a.apps.push(s,{session:t.session,app:t.app,input:{kind:"json",payload:t.appPushPayload}});e.equal(n.kind,"appPushed"),e.equal(n.inputKind,"json")}},{name:"triggers app events",command:"apps.triggerEvent",run:async(s,t)=>{let n=await a.apps.triggerEvent(s,{session:t.session,name:t.appEventName});e.equal(n.kind,"appEventTriggered"),e.equal(n.name,t.appEventName)}}]}),l=w({name:"admin",cases:[{name:"lists devices",command:"admin.devices",run:async s=>{let t=await a.admin.devices(s,{});e.equal(t.kind,"adminDevices"),e.ok(Array.isArray(t.devices))}},{name:"boots devices",command:"admin.boot",run:async s=>{let t=await a.admin.boot(s,{});e.equal(t.kind,"deviceBooted")}},{name:"ensures simulators",command:"admin.ensureSimulator",run:async s=>{let t=await a.admin.ensureSimulator(s,{device:"iPhone 16",runtime:"iOS 18"});e.equal(t.kind,"simulatorEnsured")}},{name:"installs apps from structured sources",command:"admin.install",run:async(s,t)=>{let n=await a.admin.install(s,{app:t.app,source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appInstalled")}},{name:"reinstalls apps from structured sources",command:"admin.reinstall",run:async(s,t)=>{let n=await a.admin.reinstall(s,{app:t.app,source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appReinstalled")}},{name:"installs apps from source resolver",command:"admin.installFromSource",run:async(s,t)=>{let n=await a.admin.installFromSource(s,{source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appInstalledFromSource")}}]}),m=w({name:"recording",cases:[{name:"starts recording",command:"record",run:async s=>{let t=await a.recording.record(s,{action:"start"});e.equal(t.kind,"recordingStarted")}},{name:"stops traces",command:"trace",run:async s=>{let t=await a.recording.trace(s,{action:"stop"});e.equal(t.kind,"traceStopped")}}]}),p=w({name:"diagnostics",cases:[{name:"reads paginated logs",command:"diagnostics.logs",run:async s=>{let t=await a.diagnostics.logs(s,{limit:10});e.equal(t.kind,"diagnosticsLogs"),e.ok(Array.isArray(t.entries))}},{name:"dumps structured network entries",command:"diagnostics.network",run:async s=>{let t=await a.diagnostics.network(s,{limit:10,include:"summary"});e.equal(t.kind,"diagnosticsNetwork"),e.ok(Array.isArray(t.entries))}},{name:"measures perf metrics",command:"diagnostics.perf",run:async s=>{let t=await a.diagnostics.perf(s,{sampleMs:100});e.equal(t.kind,"diagnosticsPerf"),e.ok(Array.isArray(t.metrics))}}]}),d=[n,i,o,r,c,l,m,p];async function u(e,a={}){let s=a.suites??d,t=[];for(let a of s)t.push(await a.run(e));let n=t.flatMap(e=>e.failures);return{target:e.name,passed:t.reduce((e,a)=>e+a.passed,0),failed:t.reduce((e,a)=>e+a.failed,0),failures:n,suites:t}}async function y(e,a={}){let s=await u(e,a);if(s.failed>0)throw AggregateError(s.failures.map(e=>e.error),`${e.name} failed ${s.failed} agent-device conformance case${1===s.failed?"":"s"}`);return s}function w(e){return{name:e.name,cases:e.cases,run:async a=>{let s={...t,...a.fixtures},n=[],i=0;for(let t of e.cases){let o={suite:e.name,caseName:t.name,fixtures:s};try{await a.beforeEach?.(o);let e=await a.createRuntime();await t.run(e,s),i+=1}catch(a){n.push({suite:e.name,caseName:t.name,command:t.command,error:a})}finally{await a.afterEach?.(o)}}return{suite:e.name,passed:i,failed:n.length,failures:n}}}}export{l as adminConformanceSuite,c as appsConformanceSuite,y as assertCommandConformance,n as captureConformanceSuite,d as commandConformanceSuites,t as defaultCommandConformanceFixtures,p as diagnosticsConformanceSuite,o as interactionConformanceSuite,m as recordingConformanceSuite,u as runCommandConformance,i as selectorConformanceSuite,r as systemConformanceSuite};
|
package/package.json
CHANGED
|
@@ -75,7 +75,7 @@ Use `snapshot --raw --platform macos` only when debugging AX structure or collec
|
|
|
75
75
|
Things not to rely on:
|
|
76
76
|
|
|
77
77
|
- Mobile-only helpers such as `install`, `reinstall`, or `push`.
|
|
78
|
-
- Desktop-global click or
|
|
78
|
+
- Desktop-global click, fill, or gesture parity from `desktop` or `menubar` sessions.
|
|
79
79
|
- Raw coordinate assumptions across runs.
|
|
80
80
|
|
|
81
81
|
Troubleshooting:
|
|
@@ -13,7 +13,7 @@ Open this file for remote daemon HTTP flows that let an agent running in a Linux
|
|
|
13
13
|
|
|
14
14
|
## Most common mistake to avoid
|
|
15
15
|
|
|
16
|
-
Do not run remote tenant work by repeating `--remote-config` on every command. `--remote-config` is a `connect` input. After connecting, use normal `agent-device` commands; the active connection supplies daemon URL, tenant, run,
|
|
16
|
+
Do not run remote tenant work by repeating `--remote-config` on every command. `--remote-config` is a `connect` input. After connecting, use normal `agent-device` commands; the active connection supplies daemon URL, tenant, run, and session context, then resolves lease and Metro details only when a later command actually needs them.
|
|
17
17
|
|
|
18
18
|
## Preferred remote flow
|
|
19
19
|
|
|
@@ -34,7 +34,7 @@ agent-device fill @e3 "test@example.com"
|
|
|
34
34
|
agent-device disconnect
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
`connect` resolves the remote profile,
|
|
37
|
+
`connect` resolves the remote profile, generates a local session name when the profile omits one, stores local non-secret connection state, and defers tenant lease allocation plus Metro preparation until a later command needs them. When a command such as `open`, `install`, `apps`, or `snapshot` needs a lease, the client allocates or refreshes it from the connected scope. When a command needs Metro runtime hints, the client prepares Metro locally at that point and starts the local Metro companion when the bridge needs it, including `batch` runs whose steps open an app. `disconnect` closes the session when possible, stops the Metro companion owned by that connection, releases the lease when one was allocated, and removes local connection state.
|
|
38
38
|
|
|
39
39
|
After `connect`, normal `agent-device` commands use the active remote connection. Do not repeat `--remote-config` on every command.
|
|
40
40
|
|
|
@@ -63,18 +63,26 @@ Example `remote-config.json` shape:
|
|
|
63
63
|
"tenant": "acme",
|
|
64
64
|
"runId": "run-123",
|
|
65
65
|
"sessionIsolation": "tenant",
|
|
66
|
-
"session": "adc-android",
|
|
67
66
|
"platform": "android",
|
|
67
|
+
"metroPublicBaseUrl": "http://127.0.0.1:8081"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Optional overrides stay available for advanced cases:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"session": "adc-android",
|
|
68
76
|
"leaseBackend": "android-instance",
|
|
69
77
|
"metroProjectRoot": ".",
|
|
70
|
-
"
|
|
78
|
+
"metroKind": "expo",
|
|
71
79
|
"metroProxyBaseUrl": "https://bridge.example.com/metro/acme/run-123"
|
|
72
80
|
}
|
|
73
81
|
```
|
|
74
82
|
|
|
75
83
|
- Keep secrets in env/config managed by the operator boundary. Do not persist auth tokens in connection state.
|
|
76
84
|
- Omit Metro fields for non-React Native flows.
|
|
77
|
-
- Put `tenant`, `runId`,
|
|
85
|
+
- Put `tenant`, `runId`, and `sessionIsolation` in the remote profile so agents can run `agent-device connect --remote-config ./remote-config.json` without extra scope flags. Add `platform`, `leaseBackend`, `session`, or Metro overrides only when the default inference is not enough for that flow.
|
|
78
86
|
- Explicit command-line flags override connected defaults. Use them intentionally when switching session, platform, target, tenant, run, or lease scope.
|
|
79
87
|
- For React Native Metro runs with `metroProxyBaseUrl`, `agent-device >= 0.11.12` can manage the local companion tunnel, but Metro itself still needs to be running locally.
|
|
80
88
|
- Use a lease backend that matches the bridge target platform, for example `android-instance`, `ios-instance`, or an explicit `--lease-backend` override.
|