agent-device 0.12.5 → 0.12.7
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/818.js +1 -1
- package/dist/src/backend.d.ts +326 -4
- package/dist/src/bin.js +36 -36
- 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/bootstrap-install.md +5 -3
- package/skills/agent-device/references/macos-desktop.md +1 -1
- package/skills/agent-device/references/remote-tenancy.md +64 -16
|
@@ -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
|
@@ -62,15 +62,17 @@ agent-device install com.example.app ./build/MyApp.app --platform ios --device "
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
|
|
66
|
-
agent-device install-from-source
|
|
65
|
+
ARTIFACT_URL="<trusted-artifact-url>"
|
|
66
|
+
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
67
|
+
GITHUB_ARTIFACT_URL="<trusted-github-actions-artifact-api-url>"
|
|
68
|
+
agent-device install-from-source "$GITHUB_ARTIFACT_URL" --platform ios --header "authorization: Bearer TOKEN"
|
|
67
69
|
```
|
|
68
70
|
|
|
69
71
|
## Install guidance
|
|
70
72
|
|
|
71
73
|
- Use `install <app> <path>` when the app may already be installed and you do not need a fresh-state reset.
|
|
72
74
|
- Use `reinstall <app> <path>` when you explicitly need uninstall plus install as one deterministic step.
|
|
73
|
-
- Use `install-from-source <url>` when an existing artifact URL is
|
|
75
|
+
- Use `install-from-source <url>` only when an existing artifact URL is trusted, operator-approved, and reachable by the daemon.
|
|
74
76
|
- Local `.apk`, `.aab`, `.app`, and `.ipa` paths go through `install` or `reinstall`; existing reachable URLs go through `install-from-source`.
|
|
75
77
|
- Do not download, re-zip, publish temporary GitHub releases, or move CI artifacts elsewhere just to make an install command work.
|
|
76
78
|
- Keep install and open as separate phases. Do not turn them into one default command flow.
|
|
@@ -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:
|
|
@@ -7,47 +7,87 @@ Open this file for remote daemon HTTP flows that let an agent running in a Linux
|
|
|
7
7
|
## Main commands to reach for first
|
|
8
8
|
|
|
9
9
|
- `agent-device connect --remote-config <path>`
|
|
10
|
+
- `agent-device install-from-source <url> --remote-config <path> --platform android`
|
|
11
|
+
- `agent-device open <package> --remote-config <path> --relaunch`
|
|
12
|
+
- `agent-device snapshot --remote-config <path> -i`
|
|
13
|
+
- `agent-device disconnect --remote-config <path>`
|
|
10
14
|
- `agent-device connection status`
|
|
11
|
-
- `agent-device disconnect`
|
|
12
15
|
- `AGENT_DEVICE_DAEMON_AUTH_TOKEN=...`
|
|
13
16
|
|
|
14
17
|
## Most common mistake to avoid
|
|
15
18
|
|
|
16
|
-
Do not
|
|
19
|
+
Do not mix an arbitrary `--session` plus ad-hoc daemon, tenant, run, or lease flags. That can bypass saved Metro runtime hints. Use one of these patterns instead:
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
- Interactive flow: run `connect --remote-config <path>` once, then normal commands, then `disconnect`.
|
|
22
|
+
- Script flow: pass the same `--remote-config <path>` to every command, including `disconnect`.
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
## Choose one flow
|
|
25
|
+
|
|
26
|
+
### Interactive flow
|
|
27
|
+
|
|
28
|
+
Use this when the agent will run several commands in one session.
|
|
21
29
|
|
|
22
30
|
```bash
|
|
23
31
|
export AGENT_DEVICE_DAEMON_AUTH_TOKEN="YOUR_TOKEN"
|
|
24
32
|
export AGENT_DEVICE_PROXY_TOKEN="$AGENT_DEVICE_DAEMON_AUTH_TOKEN"
|
|
25
33
|
|
|
26
|
-
agent-device connect
|
|
27
|
-
--remote-config ./remote-config.json
|
|
34
|
+
agent-device connect --remote-config ./remote-config.json
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
agent-device install-from-source
|
|
36
|
+
ARTIFACT_URL="<trusted-artifact-url>"
|
|
37
|
+
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
31
38
|
agent-device open com.example.app --relaunch
|
|
32
39
|
agent-device snapshot -i
|
|
33
40
|
agent-device fill @e3 "test@example.com"
|
|
34
41
|
agent-device disconnect
|
|
35
42
|
```
|
|
36
43
|
|
|
37
|
-
`connect
|
|
44
|
+
After `connect`, normal commands use the active remote connection. End with `disconnect` to release the lease and stop the owned Metro companion.
|
|
45
|
+
|
|
46
|
+
### Self-contained script flow
|
|
47
|
+
|
|
48
|
+
Use this when each command must be explicit and repeatable. Pass the same `--remote-config` to each step.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ARTIFACT_URL="<trusted-artifact-url>"
|
|
52
|
+
|
|
53
|
+
agent-device install-from-source "$ARTIFACT_URL" \
|
|
54
|
+
--remote-config ./remote-config.json \
|
|
55
|
+
--platform android
|
|
56
|
+
|
|
57
|
+
agent-device open com.example.app \
|
|
58
|
+
--remote-config ./remote-config.json \
|
|
59
|
+
--relaunch
|
|
60
|
+
|
|
61
|
+
agent-device snapshot \
|
|
62
|
+
--remote-config ./remote-config.json \
|
|
63
|
+
-i
|
|
64
|
+
|
|
65
|
+
agent-device disconnect \
|
|
66
|
+
--remote-config ./remote-config.json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The first command that needs a lease or Metro runtime prepares and persists it. Later commands with the same `--remote-config` reuse that state. End with `disconnect --remote-config <path>` to release the lease and stop the owned Metro companion.
|
|
38
70
|
|
|
39
|
-
|
|
71
|
+
## Behavior summary
|
|
72
|
+
|
|
73
|
+
- `connect` stores local non-secret connection state and defers tenant lease allocation plus Metro preparation until a later command needs them.
|
|
74
|
+
- Commands such as `install-from-source`, `open`, `snapshot`, and `apps` allocate or refresh the lease when needed.
|
|
75
|
+
- `open` prepares Metro runtime hints when the remote profile has Metro fields and no compatible runtime is already saved.
|
|
76
|
+
- `batch` also prepares Metro when any step opens an app and that step does not provide its own runtime.
|
|
77
|
+
- `disconnect` closes the session when possible, stops the Metro companion owned by the connection, releases the lease when one was allocated, and removes local connection state.
|
|
40
78
|
|
|
41
79
|
Remote install examples:
|
|
42
80
|
|
|
43
81
|
```bash
|
|
44
82
|
agent-device install com.example.app ./app.apk
|
|
45
|
-
|
|
46
|
-
agent-device install-from-source
|
|
83
|
+
ARTIFACT_URL="<trusted-artifact-url>"
|
|
84
|
+
agent-device install-from-source "$ARTIFACT_URL" --platform android
|
|
85
|
+
GITHUB_ARTIFACT_URL="<trusted-github-actions-artifact-api-url>"
|
|
86
|
+
agent-device install-from-source "$GITHUB_ARTIFACT_URL" --platform ios --header "authorization: Bearer TOKEN"
|
|
47
87
|
```
|
|
48
88
|
|
|
49
89
|
- Use `install` or `reinstall` for local paths; remote daemons upload local artifacts automatically.
|
|
50
|
-
- Use `install-from-source` for artifact URLs the remote daemon can reach.
|
|
90
|
+
- Use `install-from-source` only for trusted, operator-approved artifact URLs the remote daemon can reach. Do not fetch arbitrary user-supplied URLs.
|
|
51
91
|
- For local-path versus URL artifact rules, follow [bootstrap-install.md](bootstrap-install.md).
|
|
52
92
|
|
|
53
93
|
Use `agent-device connection status --session adc-android` to inspect the active connection without reading JSON state manually. Status output must not include auth tokens.
|
|
@@ -63,18 +103,26 @@ Example `remote-config.json` shape:
|
|
|
63
103
|
"tenant": "acme",
|
|
64
104
|
"runId": "run-123",
|
|
65
105
|
"sessionIsolation": "tenant",
|
|
66
|
-
"session": "adc-android",
|
|
67
106
|
"platform": "android",
|
|
107
|
+
"metroPublicBaseUrl": "http://127.0.0.1:8081"
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Optional overrides stay available for advanced cases:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"session": "adc-android",
|
|
68
116
|
"leaseBackend": "android-instance",
|
|
69
117
|
"metroProjectRoot": ".",
|
|
70
|
-
"
|
|
118
|
+
"metroKind": "expo",
|
|
71
119
|
"metroProxyBaseUrl": "https://bridge.example.com/metro/acme/run-123"
|
|
72
120
|
}
|
|
73
121
|
```
|
|
74
122
|
|
|
75
123
|
- Keep secrets in env/config managed by the operator boundary. Do not persist auth tokens in connection state.
|
|
76
124
|
- Omit Metro fields for non-React Native flows.
|
|
77
|
-
- Put `tenant`, `runId`,
|
|
125
|
+
- 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
126
|
- Explicit command-line flags override connected defaults. Use them intentionally when switching session, platform, target, tenant, run, or lease scope.
|
|
79
127
|
- 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
128
|
- Use a lease backend that matches the bridge target platform, for example `android-instance`, `ios-instance`, or an explicit `--lease-backend` override.
|