mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
Add a "Guarantees" section to `agent-device help workflow`: statements of fact for agents to reason from instead of probing behavior with trial commands. Covers selector ambiguity (folds/extends the existing #1040 paragraph instead of duplicating it), hittability/targetHittable, open idempotent-foreground vs --relaunch's single simctl launch --terminate-running-process call, close's runner retention policy plus the AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS idle-stop window, ref lifetime (cleared by open/relaunch), diff snapshot's comparison baseline, and wait's polling model. Each statement is traceable to source, noted in the PR body. Adds three doc-assertion tests in cli-help.test.ts mirroring the #1040 pattern.
This commit is contained in:
committed by
GitHub
parent
2adf3d5535
commit
f98111ef7e
@@ -118,6 +118,58 @@ test('help workflow documents the selector disambiguation policy (#1037)', async
|
||||
assert.match(result.stdout, /targetHittable: false/);
|
||||
});
|
||||
|
||||
test('help workflow documents selector and hittability guarantees (#1051)', async () => {
|
||||
const result = await runCliCapture(['help', 'workflow']);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result.calls.length, 0);
|
||||
assert.match(result.stdout, /Guarantees:/);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/auto-disambiguates deepest node first, then smallest on-screen area/,
|
||||
);
|
||||
assert.match(result.stdout, /Selector did not resolve uniquely/);
|
||||
assert.match(result.stdout, /non-hittable resolution is allowed by design/);
|
||||
assert.match(result.stdout, /targetHittable: false plus a hint/);
|
||||
});
|
||||
|
||||
test('help workflow documents open/close/relaunch runner guarantees (#1051)', async () => {
|
||||
const result = await runCliCapture(['help', 'workflow']);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result.calls.length, 0);
|
||||
assert.match(result.stdout, /idempotent-foreground for an already-running app/);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/one simctl launch --terminate-running-process call instead of a separate terminate-then-launch/,
|
||||
);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/keeps a healthy iOS simulator XCTest runner warm by default so the next open on that device skips the runner build/,
|
||||
);
|
||||
assert.match(result.stdout, /the session held a device lease/);
|
||||
assert.match(result.stdout, /AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS/);
|
||||
assert.match(result.stdout, /default 5 minutes/);
|
||||
});
|
||||
|
||||
test('help workflow documents ref lifetime, snapshot diff, and wait guarantees (#1051)', async () => {
|
||||
const result = await runCliCapture(['help', 'workflow']);
|
||||
assert.equal(result.code, 0);
|
||||
assert.equal(result.calls.length, 0);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/open and open --relaunch clear the session's stored snapshot outright/,
|
||||
);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/diff snapshot compares the current capture against the session's last stored snapshot/,
|
||||
);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
/initializes the baseline and reports zero additions\/removals instead of failing/,
|
||||
);
|
||||
assert.match(result.stdout, /polls on a fixed interval \(300ms\)/);
|
||||
assert.match(result.stdout, /Timing out raises a command failure/);
|
||||
});
|
||||
|
||||
test('help unknown command prints error plus global usage and skips daemon dispatch', async () => {
|
||||
const result = await runCliCapture(['help', 'not-a-command']);
|
||||
assert.equal(result.code, 1);
|
||||
|
||||
@@ -321,6 +321,16 @@ React Native dev loop:
|
||||
If apps lookup misses the project but shows Expo Go/dev-client and a project URL is available, open the URL/host shell; if no URL is available, ask instead of inventing an app id.
|
||||
Expo Dev Client/development builds: open the installed dev-client app id/name; if a dev-client URL is provided, open that URL next. For Metro setup use metro prepare --kind expo.
|
||||
|
||||
Guarantees:
|
||||
Statements of fact for agents to reason from without probing them via trial commands. Each is backed by source in the agent-device repo; behavior changes land with an updated statement here.
|
||||
Selector ambiguity: a selector on an interactive command that matches multiple elements does not fail by default. Resolution auto-disambiguates deepest node first, then smallest on-screen area; only an exact tie on both fails with "Selector did not resolve uniquely (...)". replay and replay-heal apply the same depth-then-area policy, so recorded and live commands pick the same candidate.
|
||||
Hittability: iOS AX hittable:false on a resolved node does not block resolution or fail the command; non-hittable resolution is allowed by design because iOS AX hittable flags are unreliable on deep React Native trees. press/fill/click success responses carry targetHittable: false plus a hint when the resolved ref or selector target reports hittable: false, so treat that as a signal to verify with a snapshot or re-target, not as a failure.
|
||||
Open: on iOS, open <app> without --relaunch dispatches a plain simctl launch, which is idempotent-foreground for an already-running app (it brings the process forward; it does not restart it). open --relaunch restarts the app; on iOS simulators (not real devices or macOS) this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch, so relaunch is a single step there.
|
||||
Close and runner retention: close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that device skips the runner build, unless --shutdown was requested, the session was recording, the session held a device lease, or the device used a scoped (non-default) simulator set — any of those tear the runner down on close. A retained runner auto-stops after an idle window (default 5 minutes) to release the device's runner lease for other daemons; set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override the window, or 0 to disable idle stop and retain until daemon exit.
|
||||
Ref lifetime: refs from a snapshot/snapshot -i are only valid until the next state-changing command. open and open --relaunch clear the session's stored snapshot outright, so every ref from before an open/relaunch is invalid; press/fill/click/scroll/back and similar mutations invalidate refs from prior turns even though the session snapshot itself is refreshed internally by those commands.
|
||||
Snapshot diff: diff snapshot compares the current capture against the session's last stored snapshot (from any prior snapshot, snapshot -i, or diff snapshot call), not a fixed baseline from session start. If no prior snapshot exists yet, diff snapshot initializes the baseline and reports zero additions/removals instead of failing.
|
||||
Wait: wait text|selector|@ref polls on a fixed interval (300ms) up to a timeout (10s default, override with the trailing timeoutMs positional) by re-capturing state each poll; it does not push/subscribe. Timing out raises a command failure rather than returning a not-found result.
|
||||
|
||||
Escalate:
|
||||
help debugging logs, network, alerts, traces, flaky runtime failures
|
||||
help react-devtools React Native performance, profiling, props/state/hooks, slow renders, rerenders
|
||||
|
||||
Reference in New Issue
Block a user