agent-device 0.7.6 → 0.7.10
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 +7 -0
- package/dist/src/bin.js +47 -45
- package/dist/src/daemon.js +32 -30
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +5 -5
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -2
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +28 -7
- package/skills/agent-device/references/permissions.md +27 -0
- package/skills/agent-device/references/remote-tenancy.md +15 -5
- package/skills/agent-device/references/session-management.md +4 -0
- package/skills/agent-device/references/snapshot-refs.md +10 -0
package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift
CHANGED
|
@@ -68,14 +68,14 @@ extension RunnerTests {
|
|
|
68
68
|
let outputSettings: [String: Any] = [
|
|
69
69
|
AVVideoCodecKey: AVVideoCodecType.h264,
|
|
70
70
|
AVVideoWidthKey: Int(dimensions.width),
|
|
71
|
-
AVVideoHeightKey: Int(dimensions.height)
|
|
71
|
+
AVVideoHeightKey: Int(dimensions.height)
|
|
72
72
|
]
|
|
73
73
|
let input = AVAssetWriterInput(mediaType: .video, outputSettings: outputSettings)
|
|
74
74
|
input.expectsMediaDataInRealTime = true
|
|
75
75
|
let attributes: [String: Any] = [
|
|
76
76
|
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB,
|
|
77
77
|
kCVPixelBufferWidthKey as String: Int(dimensions.width),
|
|
78
|
-
kCVPixelBufferHeightKey as String: Int(dimensions.height)
|
|
78
|
+
kCVPixelBufferHeightKey as String: Int(dimensions.height)
|
|
79
79
|
]
|
|
80
80
|
let adaptor = AVAssetWriterInputPixelBufferAdaptor(
|
|
81
81
|
assetWriterInput: input,
|
|
@@ -82,11 +82,11 @@ extension RunnerTests {
|
|
|
82
82
|
x: Double(rootSnapshot.frame.origin.x),
|
|
83
83
|
y: Double(rootSnapshot.frame.origin.y),
|
|
84
84
|
width: Double(rootSnapshot.frame.size.width),
|
|
85
|
-
height: Double(rootSnapshot.frame.size.height)
|
|
85
|
+
height: Double(rootSnapshot.frame.size.height)
|
|
86
86
|
),
|
|
87
87
|
enabled: rootSnapshot.isEnabled,
|
|
88
88
|
hittable: rootHittable,
|
|
89
|
-
depth: 0
|
|
89
|
+
depth: 0
|
|
90
90
|
)
|
|
91
91
|
)
|
|
92
92
|
|
|
@@ -149,11 +149,11 @@ extension RunnerTests {
|
|
|
149
149
|
x: Double(snapshot.frame.origin.x),
|
|
150
150
|
y: Double(snapshot.frame.origin.y),
|
|
151
151
|
width: Double(snapshot.frame.size.width),
|
|
152
|
-
height: Double(snapshot.frame.size.height)
|
|
152
|
+
height: Double(snapshot.frame.size.height)
|
|
153
153
|
),
|
|
154
154
|
enabled: snapshot.isEnabled,
|
|
155
155
|
hittable: hittable,
|
|
156
|
-
depth: min(maxDepth, visibleDepth)
|
|
156
|
+
depth: min(maxDepth, visibleDepth)
|
|
157
157
|
)
|
|
158
158
|
)
|
|
159
159
|
|
|
@@ -216,7 +216,7 @@ extension RunnerTests {
|
|
|
216
216
|
rect: snapshotRect(from: snapshot.frame),
|
|
217
217
|
enabled: snapshot.isEnabled,
|
|
218
218
|
hittable: hittable,
|
|
219
|
-
depth: depth
|
|
219
|
+
depth: depth
|
|
220
220
|
)
|
|
221
221
|
)
|
|
222
222
|
}
|
|
@@ -19,7 +19,7 @@ extension RunnerTests {
|
|
|
19
19
|
if buffer.count + data.count > self.maxRequestBytes {
|
|
20
20
|
let response = self.jsonResponse(
|
|
21
21
|
status: 413,
|
|
22
|
-
response: Response(ok: false, error: ErrorPayload(message: "request too large"))
|
|
22
|
+
response: Response(ok: false, error: ErrorPayload(message: "request too large"))
|
|
23
23
|
)
|
|
24
24
|
connection.send(content: response, completion: .contentProcessed { [weak self] _ in
|
|
25
25
|
connection.cancel()
|
|
@@ -111,7 +111,7 @@ extension RunnerTests {
|
|
|
111
111
|
"Content-Length: \(body.utf8.count)",
|
|
112
112
|
"Connection: close",
|
|
113
113
|
"",
|
|
114
|
-
body
|
|
114
|
+
body
|
|
115
115
|
].joined(separator: "\r\n")
|
|
116
116
|
return Data(headers.utf8)
|
|
117
117
|
}
|
|
@@ -59,7 +59,7 @@ final class RunnerTests: XCTestCase {
|
|
|
59
59
|
.tabBar,
|
|
60
60
|
.textField,
|
|
61
61
|
.secureTextField,
|
|
62
|
-
.textView
|
|
62
|
+
.textView
|
|
63
63
|
]
|
|
64
64
|
// Keep blocker actions narrow to avoid false positives from generic hittable containers.
|
|
65
65
|
let actionableTypes: Set<XCUIElement.ElementType> = [
|
|
@@ -68,7 +68,7 @@ final class RunnerTests: XCTestCase {
|
|
|
68
68
|
.link,
|
|
69
69
|
.menuItem,
|
|
70
70
|
.checkBox,
|
|
71
|
-
.switch
|
|
71
|
+
.switch
|
|
72
72
|
]
|
|
73
73
|
|
|
74
74
|
// MARK: - XCTest Entry
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@ Use this skill as a router, not a full manual.
|
|
|
25
25
|
- Normal UI task: `open` -> `snapshot -i` -> `press/fill` -> `diff snapshot -i` -> `close`
|
|
26
26
|
- Debug/crash: `open <app>` -> `logs clear --restart` -> reproduce -> `network dump` -> `logs path` -> targeted `grep`
|
|
27
27
|
- Replay drift: `replay -u <path>` -> verify updated selectors
|
|
28
|
-
- Remote multi-tenant run: allocate lease -> run commands with tenant isolation flags -> heartbeat/release lease
|
|
28
|
+
- Remote multi-tenant run: allocate lease -> point client at remote daemon base URL -> run commands with tenant isolation flags -> heartbeat/release lease
|
|
29
29
|
- Device-scope isolation run: set iOS simulator set / Android allowlist -> run selectors within scope only
|
|
30
30
|
|
|
31
31
|
## Canonical Flows
|
|
@@ -62,14 +62,18 @@ agent-device replay -u ./session.ad
|
|
|
62
62
|
### 4) Remote Tenant Lease Flow (HTTP JSON-RPC)
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
+
# Client points directly at the remote daemon HTTP base URL.
|
|
66
|
+
export AGENT_DEVICE_DAEMON_BASE_URL=http://mac-host.example:4310
|
|
67
|
+
export AGENT_DEVICE_DAEMON_AUTH_TOKEN=<token>
|
|
68
|
+
|
|
65
69
|
# Allocate lease
|
|
66
|
-
curl -sS
|
|
70
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
67
71
|
-H "content-type: application/json" \
|
|
68
72
|
-H "Authorization: Bearer <token>" \
|
|
69
73
|
-d '{"jsonrpc":"2.0","id":"alloc-1","method":"agent_device.lease.allocate","params":{"runId":"run-123","tenantId":"acme","ttlMs":60000}}'
|
|
70
74
|
|
|
71
75
|
# Use lease in tenant-isolated command execution
|
|
72
|
-
agent-device
|
|
76
|
+
agent-device \
|
|
73
77
|
--tenant acme \
|
|
74
78
|
--session-isolation tenant \
|
|
75
79
|
--run-id run-123 \
|
|
@@ -77,16 +81,21 @@ agent-device --daemon-transport http \
|
|
|
77
81
|
session list --json
|
|
78
82
|
|
|
79
83
|
# Heartbeat and release
|
|
80
|
-
curl -sS
|
|
84
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
81
85
|
-H "content-type: application/json" \
|
|
82
86
|
-H "Authorization: Bearer <token>" \
|
|
83
87
|
-d '{"jsonrpc":"2.0","id":"hb-1","method":"agent_device.lease.heartbeat","params":{"leaseId":"<lease-id>","ttlMs":60000}}'
|
|
84
|
-
curl -sS
|
|
88
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
85
89
|
-H "content-type: application/json" \
|
|
86
90
|
-H "Authorization: Bearer <token>" \
|
|
87
91
|
-d '{"jsonrpc":"2.0","id":"rel-1","method":"agent_device.lease.release","params":{"leaseId":"<lease-id>"}}'
|
|
88
92
|
```
|
|
89
93
|
|
|
94
|
+
Notes:
|
|
95
|
+
- `AGENT_DEVICE_DAEMON_BASE_URL` makes the CLI skip local daemon discovery/startup and call the remote HTTP daemon directly.
|
|
96
|
+
- `AGENT_DEVICE_DAEMON_AUTH_TOKEN` is sent in both the JSON-RPC request token and HTTP auth headers.
|
|
97
|
+
- In remote daemon mode, `--debug` does not tail a local `daemon.log`; inspect logs on the remote host instead.
|
|
98
|
+
|
|
90
99
|
## Command Skeleton (Minimal)
|
|
91
100
|
|
|
92
101
|
### Session and navigation
|
|
@@ -95,6 +104,8 @@ curl -sS http://127.0.0.1:${AGENT_DEVICE_DAEMON_HTTP_PORT}/rpc \
|
|
|
95
104
|
agent-device devices
|
|
96
105
|
agent-device devices --platform ios --ios-simulator-device-set /tmp/tenant-a/simulators
|
|
97
106
|
agent-device devices --platform android --android-device-allowlist emulator-5554,device-1234
|
|
107
|
+
agent-device ensure-simulator --device "iPhone 16" --ios-simulator-device-set /tmp/tenant-a/simulators
|
|
108
|
+
agent-device ensure-simulator --device "iPhone 16" --runtime com.apple.CoreSimulator.SimRuntime.iOS-18-4 --ios-simulator-device-set /tmp/tenant-a/simulators --boot
|
|
98
109
|
agent-device open [app|url] [url]
|
|
99
110
|
agent-device open [app] --relaunch
|
|
100
111
|
agent-device close [app]
|
|
@@ -114,6 +125,12 @@ Isolation scoping quick reference:
|
|
|
114
125
|
- Scope is applied before selectors (`--device`, `--udid`, `--serial`); out-of-scope selectors fail with `DEVICE_NOT_FOUND`.
|
|
115
126
|
- With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
|
|
116
127
|
|
|
128
|
+
Simulator provisioning quick reference:
|
|
129
|
+
- Use `ensure-simulator` to create or reuse a named iOS simulator inside a device set before starting a session.
|
|
130
|
+
- `--device <name>` is required (e.g. `"iPhone 16 Pro"`). `--runtime <id>` pins the runtime; omit to use the newest compatible one.
|
|
131
|
+
- `--boot` boots it immediately. Returns `udid`, `device`, `runtime`, `ios_simulator_device_set`, `created`, `booted`.
|
|
132
|
+
- Idempotent: safe to call repeatedly; reuses an existing matching simulator by default.
|
|
133
|
+
|
|
117
134
|
TV quick reference:
|
|
118
135
|
- AndroidTV: `open`/`apps` use TV launcher discovery automatically.
|
|
119
136
|
- TV target selection works on emulators/simulators and connected physical devices (AndroidTV + AppleTV).
|
|
@@ -170,13 +187,15 @@ agent-device batch --steps-file /tmp/batch-steps.json --json
|
|
|
170
187
|
- Re-snapshot after UI mutations (navigation/modal/list changes).
|
|
171
188
|
- Prefer `snapshot -i`; scope/depth only when needed.
|
|
172
189
|
- Use refs for discovery, selectors for replay/assertions.
|
|
190
|
+
- `find "<query>" click --json` returns `{ ref, locator, query, x, y }` — all derived from the matched snapshot node. Do not rely on these fields from raw `press`/`click` responses for observability; use `find` instead.
|
|
173
191
|
- Use `fill` for clear-then-type semantics; use `type` for focused append typing.
|
|
174
192
|
- Use `install` for in-place app upgrades (keep app data when platform permits), and `reinstall` for deterministic fresh-state runs.
|
|
175
193
|
- App binary format support for `install`/`reinstall`: Android `.apk`/`.aab`, iOS `.app`/`.ipa`.
|
|
176
194
|
- Android `.aab` requires `bundletool` in `PATH`, or `AGENT_DEVICE_BUNDLETOOL_JAR=<path-to-bundletool-all.jar>` with `java` in `PATH`.
|
|
177
195
|
- Android `.aab` optional: set `AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE=<mode>` to control bundletool `build-apks --mode` (default: `universal`).
|
|
178
196
|
- iOS `.ipa`: extract/install from `Payload/*.app`; when multiple app bundles are present, `<app>` is used as a bundle id/name hint.
|
|
179
|
-
- iOS `appstate` is session-scoped; Android `appstate` is live foreground state.
|
|
197
|
+
- iOS `appstate` is session-scoped; Android `appstate` is live foreground state. iOS responses include `device_udid` and `ios_simulator_device_set` for isolation verification.
|
|
198
|
+
- iOS `open` responses include `device_udid` and `ios_simulator_device_set` to confirm which simulator handled the session.
|
|
180
199
|
- Clipboard helpers: `clipboard read` / `clipboard write <text>` are supported on Android and iOS simulators; iOS physical devices are not supported yet.
|
|
181
200
|
- Android keyboard helpers: `keyboard status|get|dismiss` report keyboard visibility/type and dismiss via keyevent when visible.
|
|
182
201
|
- `network dump` is best-effort and parses HTTP(s) entries from the session app log file.
|
|
@@ -190,6 +209,7 @@ agent-device batch --steps-file /tmp/batch-steps.json --json
|
|
|
190
209
|
- Canonical trigger behavior and caveats are documented in [`website/docs/docs/commands.md`](../../website/docs/docs/commands.md) under **App event triggers**.
|
|
191
210
|
- Permission settings are app-scoped and require an active session app:
|
|
192
211
|
`settings permission <grant|deny|reset> <camera|microphone|photos|contacts|notifications> [full|limited]`
|
|
212
|
+
- iOS simulator permission alerts: use `alert wait` then `alert accept/dismiss` — `accept`/`dismiss` retry internally for up to 2 s so you do not need manual sleeps. See [references/permissions.md](references/permissions.md).
|
|
193
213
|
- `full|limited` mode applies only to iOS `photos`; other targets reject mode.
|
|
194
214
|
- On Android, non-ASCII `fill/type` may require an ADB keyboard IME on some system images; only install IME APKs from trusted sources and verify checksum/signature.
|
|
195
215
|
- If using `--save-script`, prefer explicit path syntax (`--save-script=flow.ad` or `./flow.ad`).
|
|
@@ -197,6 +217,7 @@ agent-device batch --steps-file /tmp/batch-steps.json --json
|
|
|
197
217
|
- Use short lease TTLs and heartbeat only while work is active; release leases immediately after run completion/failure.
|
|
198
218
|
- Env equivalents for scoped runs: `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET` (compat `IOS_SIMULATOR_DEVICE_SET`) and
|
|
199
219
|
`AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST` (compat `ANDROID_DEVICE_ALLOWLIST`).
|
|
220
|
+
- For explicit remote client mode, prefer `AGENT_DEVICE_DAEMON_BASE_URL` / `--daemon-base-url` instead of relying on local daemon metadata or loopback-only ports.
|
|
200
221
|
|
|
201
222
|
## Security and Trust Notes
|
|
202
223
|
|
|
@@ -204,7 +225,7 @@ agent-device batch --steps-file /tmp/batch-steps.json --json
|
|
|
204
225
|
- If install is required, pin an exact version (for example: `npx --yes agent-device@<exact-version> --help`).
|
|
205
226
|
- Signing/provisioning environment variables are optional, sensitive, and only for iOS physical-device setup.
|
|
206
227
|
- Logs/artifacts are written under `~/.agent-device`; replay scripts write to explicit paths you provide.
|
|
207
|
-
- For remote daemon mode, prefer `AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual` with `AGENT_DEVICE_HTTP_AUTH_HOOK` and tenant-scoped lease admission.
|
|
228
|
+
- For remote daemon mode, prefer `AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual` on the host plus client-side `AGENT_DEVICE_DAEMON_BASE_URL`, with `AGENT_DEVICE_HTTP_AUTH_HOOK` and tenant-scoped lease admission where needed.
|
|
208
229
|
- Keep logging off unless debugging and use least-privilege/isolated environments for autonomous runs.
|
|
209
230
|
|
|
210
231
|
## Common Mistakes
|
|
@@ -34,6 +34,33 @@ If daemon startup fails with stale metadata hints, clean stale files and retry:
|
|
|
34
34
|
- `~/.agent-device/daemon.json`
|
|
35
35
|
- `~/.agent-device/daemon.lock`
|
|
36
36
|
|
|
37
|
+
## iOS permission alerts (simulator only)
|
|
38
|
+
|
|
39
|
+
iOS apps trigger system permission dialogs (camera, location, notifications, etc.) on first use.
|
|
40
|
+
Use `alert` to handle them without tapping coordinates:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
agent-device alert wait # block until an alert appears (default 10 s timeout)
|
|
44
|
+
agent-device alert accept # accept the frontmost alert
|
|
45
|
+
agent-device alert dismiss # dismiss the frontmost alert
|
|
46
|
+
agent-device alert get # read alert title/message without acting
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Timing note:** `alert accept` and `alert dismiss` include a built-in 2 s retry window.
|
|
50
|
+
If the alert is present in the UI hierarchy but not yet interactive, the command retries every 300 ms
|
|
51
|
+
rather than failing immediately. You do not need to add manual sleeps between triggering the alert
|
|
52
|
+
and accepting it.
|
|
53
|
+
|
|
54
|
+
**Preferred pattern for clean simulator sessions:**
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
agent-device open MyApp --platform ios
|
|
58
|
+
agent-device alert wait 5000 # wait up to 5 s for the permission prompt
|
|
59
|
+
agent-device alert accept # accept; retries internally if not yet actionable
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`alert` is only supported on iOS simulators; iOS physical devices are not supported.
|
|
63
|
+
|
|
37
64
|
## iOS: "Allow Paste" dialog
|
|
38
65
|
|
|
39
66
|
iOS 16+ shows an "Allow Paste" prompt when an app reads the system pasteboard. Under XCUITest (which `agent-device` uses), this prompt is suppressed by the testing runtime. Use `xcrun simctl pbcopy booted` to set clipboard content directly on the simulator instead.
|
|
@@ -6,7 +6,12 @@ tenant/run admission control.
|
|
|
6
6
|
## Transport prerequisites
|
|
7
7
|
|
|
8
8
|
- Start daemon in HTTP mode (`AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual`).
|
|
9
|
-
-
|
|
9
|
+
- Point remote clients at the host with `AGENT_DEVICE_DAEMON_BASE_URL=http(s)://host:port[/base-path]`
|
|
10
|
+
or `--daemon-base-url <url>` so the CLI skips local daemon discovery/startup.
|
|
11
|
+
- Use `AGENT_DEVICE_DAEMON_AUTH_TOKEN` / `--daemon-auth-token` when the client should send the
|
|
12
|
+
shared daemon token automatically.
|
|
13
|
+
- Direct JSON-RPC callers can use a token in params, `Authorization: Bearer <token>`, or
|
|
14
|
+
`x-agent-device-token`.
|
|
10
15
|
- Prefer an auth hook (`AGENT_DEVICE_HTTP_AUTH_HOOK`) for caller validation and
|
|
11
16
|
tenant injection.
|
|
12
17
|
|
|
@@ -21,7 +26,7 @@ Use `POST /rpc` with JSON-RPC 2.0 methods:
|
|
|
21
26
|
Example allocate:
|
|
22
27
|
|
|
23
28
|
```bash
|
|
24
|
-
curl -sS
|
|
29
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
25
30
|
-H "content-type: application/json" \
|
|
26
31
|
-H "Authorization: Bearer <token>" \
|
|
27
32
|
-d '{"jsonrpc":"2.0","id":"alloc-1","method":"agent_device.lease.allocate","params":{"tenantId":"acme","runId":"run-123","ttlMs":60000}}'
|
|
@@ -30,7 +35,7 @@ curl -sS http://127.0.0.1:${AGENT_DEVICE_DAEMON_HTTP_PORT}/rpc \
|
|
|
30
35
|
Example heartbeat:
|
|
31
36
|
|
|
32
37
|
```bash
|
|
33
|
-
curl -sS
|
|
38
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
34
39
|
-H "content-type: application/json" \
|
|
35
40
|
-H "Authorization: Bearer <token>" \
|
|
36
41
|
-d '{"jsonrpc":"2.0","id":"hb-1","method":"agent_device.lease.heartbeat","params":{"leaseId":"<lease-id>","ttlMs":60000}}'
|
|
@@ -39,7 +44,7 @@ curl -sS http://127.0.0.1:${AGENT_DEVICE_DAEMON_HTTP_PORT}/rpc \
|
|
|
39
44
|
Example release:
|
|
40
45
|
|
|
41
46
|
```bash
|
|
42
|
-
curl -sS
|
|
47
|
+
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
|
|
43
48
|
-H "content-type: application/json" \
|
|
44
49
|
-H "Authorization: Bearer <token>" \
|
|
45
50
|
-d '{"jsonrpc":"2.0","id":"rel-1","method":"agent_device.lease.release","params":{"leaseId":"<lease-id>"}}'
|
|
@@ -50,7 +55,7 @@ curl -sS http://127.0.0.1:${AGENT_DEVICE_DAEMON_HTTP_PORT}/rpc \
|
|
|
50
55
|
For tenant-isolated command execution, pass all four flags:
|
|
51
56
|
|
|
52
57
|
```bash
|
|
53
|
-
agent-device
|
|
58
|
+
agent-device \
|
|
54
59
|
--tenant acme \
|
|
55
60
|
--session-isolation tenant \
|
|
56
61
|
--run-id run-123 \
|
|
@@ -60,6 +65,9 @@ agent-device --daemon-transport http \
|
|
|
60
65
|
|
|
61
66
|
Admission checks require tenant/run/lease scope alignment.
|
|
62
67
|
|
|
68
|
+
The CLI sends `AGENT_DEVICE_DAEMON_AUTH_TOKEN` in both the JSON-RPC request token field and HTTP
|
|
69
|
+
auth headers so existing daemon auth paths continue to work.
|
|
70
|
+
|
|
63
71
|
## Failure semantics
|
|
64
72
|
|
|
65
73
|
- Missing tenant/run/lease fields in tenant isolation mode: `INVALID_ARGS`
|
|
@@ -70,6 +78,8 @@ Admission checks require tenant/run/lease scope alignment.
|
|
|
70
78
|
|
|
71
79
|
- Keep TTL short and heartbeat only while a run is active.
|
|
72
80
|
- Release lease immediately on run completion/error paths.
|
|
81
|
+
- For remote debug sessions, inspect logs on the remote host; client-side `--debug` no longer tails
|
|
82
|
+
a local daemon log when `AGENT_DEVICE_DAEMON_BASE_URL` is set.
|
|
73
83
|
- For bounded hosts, configure:
|
|
74
84
|
- `AGENT_DEVICE_MAX_SIMULATOR_LEASES`
|
|
75
85
|
- `AGENT_DEVICE_LEASE_TTL_MS`
|
|
@@ -21,6 +21,7 @@ Sessions isolate device context. A device can only be held by one session at a t
|
|
|
21
21
|
- On iOS, `appstate` is session-scoped and requires a matching active session on the target device.
|
|
22
22
|
- For dev loops where runtime state can persist (for example React Native Fast Refresh), use `open <app> --relaunch` to restart the app process in the same session.
|
|
23
23
|
- Use `--save-script [path]` to record replay scripts on `close`; path is a file path and parent directories are created automatically.
|
|
24
|
+
- Use `close --shutdown` (iOS simulator only) to shut down the simulator as part of session teardown, preventing resource leakage in multi-tenant or CI workloads.
|
|
24
25
|
- For ambiguous bare `--save-script` values, prefer `--save-script=workflow.ad` or `./workflow.ad`.
|
|
25
26
|
- For deterministic replay scripts, prefer selector-based actions and assertions.
|
|
26
27
|
- Use `replay -u` to update selector drift during maintenance.
|
|
@@ -36,6 +37,7 @@ agent-device devices --platform android --android-device-allowlist emulator-5554
|
|
|
36
37
|
|
|
37
38
|
- Scope is applied before selectors (`--device`, `--udid`, `--serial`).
|
|
38
39
|
- If selector target is outside scope, resolution fails with `DEVICE_NOT_FOUND`.
|
|
40
|
+
- If the scoped iOS simulator set is empty (first-run), the error includes the set path and a suggested `xcrun simctl --set <path> create ...` command.
|
|
39
41
|
- With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
|
|
40
42
|
- Environment equivalents:
|
|
41
43
|
- `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET` (compat: `IOS_SIMULATOR_DEVICE_SET`)
|
|
@@ -47,6 +49,8 @@ agent-device devices --platform android --android-device-allowlist emulator-5554
|
|
|
47
49
|
agent-device session list
|
|
48
50
|
```
|
|
49
51
|
|
|
52
|
+
iOS session entries include `device_udid` and `ios_simulator_device_set` (null when using the default set). Use these fields to confirm device routing in concurrent multi-session runs without additional `simctl` calls.
|
|
53
|
+
|
|
50
54
|
## Replay within sessions
|
|
51
55
|
|
|
52
56
|
```bash
|
|
@@ -76,6 +76,16 @@ Efficient pattern:
|
|
|
76
76
|
|
|
77
77
|
- If refs are unstable after UI transitions, switch to selector-based targeting and stop investing in ref-only flows.
|
|
78
78
|
|
|
79
|
+
## find click response
|
|
80
|
+
|
|
81
|
+
`find "<query>" click --json` returns deterministic matched-target metadata:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{ "ref": "@e3", "locator": "any", "query": "Increment", "x": 195, "y": 422 }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Fields come from the matched snapshot node, not the platform runner. Use these for observability and replay quality — they are stable across runs for the same UI state.
|
|
88
|
+
|
|
79
89
|
## Replay note
|
|
80
90
|
|
|
81
91
|
- Prefer selector-based actions in recorded `.ad` replays.
|