* fix: return deterministic matched-target metadata for find click responses (#170)
On success, build the response from the matched snapshot node rather than
passing through whatever the underlying click/press handler returns.
Response now includes: ref, locator, query, and x/y derived from the
matched element's rect — all stable across runs.
Also makes `dispatch` injectable in `handleFindCommands` (matching the
pattern in `handleInteractionCommands`) and adds tests that assert the
deterministic shape and verify that non-deterministic platform runner
data does not bleed into the response.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: document find click response shape in selectors and skill references
Add response shape documentation for `find "<query>" click --json` to:
- website/docs/docs/selectors.md (new "Response shape (click)" section)
- skills/agent-device/SKILL.md (guardrail note)
- skills/agent-device/references/snapshot-refs.md (new "find click response" section)
Follows the fix in #178 that made the response deterministic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: retry alert accept/dismiss on transient 'alert not found' errors
Adds a 2 s internal retry window for `alert accept` and `alert dismiss`
when the runner returns "alert not found" or "no alert". Errors from
other causes break the loop immediately and are re-thrown unchanged.
Also injects `runnerCommand` as an optional param to enable unit testing
without spawning a real runner.
Closes#171
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: document alert accept/dismiss retry behaviour in skill and permissions reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: enrich DEVICE_NOT_FOUND error for empty scoped iOS simulator sets (#168)
When selectDevice finds no candidates and a simulatorSetPath context is
provided for iOS, throw a detailed error including the set path and a
suggested xcrun simctl --set ... create command to provision the first
simulator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: note enriched DEVICE_NOT_FOUND guidance for empty scoped iOS simulator sets
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add device identity fields to open, appstate, and session_list responses
for iOS targets, enabling isolation verification in concurrent multi-session
runs without extra simctl calls.
Closes#173
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract resolveTargetDevice, series/jitter helpers, and push payload
parsing into dedicated modules to reduce dispatch.ts from ~706 to ~564 LOC.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use snapshots for raw iOS tree traversal
Fixes#147
* refactor: unify snapshot hittable computation across modes
* refactor: account for cousin occlusion in hittable
* refactor: tighten snapshot occlusion heuristic
* fix: add daemon remote HTTP server mode with isolation controls
* feat: add tenant lease lifecycle and admission control
* refactor: simplify lease scope and rpc method routing
* fix: correct smoke expectations for close without session
* fix(ios): use XCTest runner for screenshots on physical devices
`xcrun devicectl device screenshot` was removed in Xcode 26.x, causing
`agent-device screenshot` to fail on physical iOS devices with exit code 64.
This fix routes physical device screenshots through the AgentDeviceRunner
XCTest runner (already used for snapshot/interaction commands) instead:
- Add `screenshot` command to the Swift runner's `CommandType` enum
- Implement the handler using `XCUIScreen.main.screenshot()`, writing a
timestamped PNG to the app's temp directory (returned as `tmp/<file>`)
- If `appBundleId` is provided, activate the target app before capturing
so the screenshot shows the app under test rather than the runner itself
- In `screenshotIos()`, pass `appBundleId` to the runner command then pull
the file back to the host via `xcrun devicectl device copy from` (same
mechanism used by the recording feature)
- Thread `appBundleId` through `Interactor.screenshot()` → `dispatch.ts`
→ `screenshotIos()` so the active session's app is always captured
- Extract `IOS_RUNNER_CONTAINER_BUNDLE_IDS` to `runner-client.ts` so it
can be shared between `apps.ts` and `record-trace.ts`
Fixes: screenshots failing with "Failed to capture iOS screenshot" on
devices using Xcode 26.x / devicectl 506.6+
* fix: clean up iOS screenshot fallback follow-ups
---------
Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
* fix: add MAIN/LAUNCHER flags to Android launcher activity resolver
The `resolve-activity` fallback command was missing `-a android.intent.action.MAIN`
and `-c android.intent.category.LAUNCHER`, causing it to resolve the wrong activity
on multi-entry apps like Microsoft Outlook. This adds the correct intent flags so
the resolver consistently returns the launcher activity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: detect am start silent failures and fall back to resolved component
am start -p <package> can exit 0 while printing "Error: Activity not
started" to stdout. The previous try/catch never entered the fallback
because runCmd did not throw. Now we check the output for error
indicators via isAmStartError() and proceed to the resolve-activity
fallback when the primary launch silently fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: EarthXP <15072042+EarthXP@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>