* fix: stabilize android settings integration test
* test: use selector click in android integration test
* test: simplify android selector integration flow
* Add open --relaunch and persist replay semantics
* Update agent-device skill docs for open --relaunch
* Disambiguate relaunch and save-script examples
* Support non-hierarchical deep links in open target detection
* ci: add manual iOS runner prebuild cache for iOS workflow
* ci: simplify manual iOS prebuild workflow
* ci: pin cache actions in iOS workflows
* ci: fix iOS workflow env paths for parser compatibility
* ci: increase daemon timeout for iOS boot preflight
* ios: harden simulator state timeout and reuse preflight session
* ci: remove redundant iOS boot preflight step
* ios: retry transient simctl launch failures on simulator
* ci: pin iOS integration test target to resolved 26.2 simulator
* ci: harden iOS prebuild cache keys and remove derived-data copy path
* ci: simplify iOS workflow caching and drop redundant prebuild workflow
- Remove standalone ios-runner-prebuild.yml (redundant — ios.yml builds on cache miss)
- Switch from actions/cache/restore to actions/cache (auto-saves on miss)
- Drop restore-keys and -stable suffix (no longer needed without prebuild workflow)
- Remove UDID resolution step (test falls back to --platform ios)
- Use point-free shouldRetry for isTransientSimulatorLaunchFailure
Co-authored-by: Cursor <cursoragent@cursor.com>
* ios: increase simctl launch retry budget for CI simulators
SpringBoard can take several seconds after boot to accept app launches.
Increase from 3 attempts / 500ms–2s to 5 attempts / 1s–5s to give CI
simulators enough time.
Co-authored-by: Cursor <cursoragent@cursor.com>
* ios: use deadline-based retry for simulator app launch
The fixed-attempt retry (5 attempts, ~12s window) is too short for CI
simulators where SpringBoard needs 30-60s after boot to accept app
launches — especially when the build step is cached and provides zero
warm-up time.
Switch to a deadline-based approach matching ensureBootedSimulator:
- Default 30s timeout (configurable via AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS)
- CI sets 60s to handle cold-boot scenarios
- maxAttempts set high (30) so the deadline is the real limit
Co-authored-by: Cursor <cursoragent@cursor.com>
* ci(ios): keep tests platform-based and stabilize simulator selection
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Refine reinstall flow and add agent-focused coverage
* Avoid duplicate readiness preflight in open flow
* Document boot and reinstall in website docs and skill
* Bound iOS boot commands and enforce runCmd timeouts
* Align boot readiness with timeout profiles across platforms
* Refine boot docs: troubleshooting-only and non-CI wording
* Clarify open vs boot fallback guidance
* Complete issue #39 phase diagnostics telemetry and boot command
* Address review findings for boot diagnostics and command gating
* Use agent-device boot preflight in iOS CI workflow
* Run iOS boot preflight via source CLI in CI
* fix(android): parse uiautomator XML attributes with single or double quotes
* fix(android): harden hierarchy parser and tighten tests
---------
Co-authored-by: Zhongjin Lu <zhongjin.lu@mondorobotics.com>
Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
* chore: use macos-26 runner for ios integration test; ubuntu for smoke
* revert smoke test
* update test for iOS 26.2
* restart sim after timeout
* fixup timeout
* feat: for self-healing e2e tests; assertions
* fix: support long-press on iOS simulators via XCTest runner
The long-press command was failing on iOS simulators because dispatch.ts
called interactor.longPress() which mapped to a stub in ios/index.ts
that always threw UNSUPPORTED_OPERATION. Unlike press, type, fill, etc.,
the long-press case was missing the iOS simulator routing through the
XCTest runner.
Rather than adding yet another platform branch in dispatch.ts, this
refactors the Interactor abstraction to absorb runner routing internally.
getInteractor() now accepts an optional RunnerContext; when the device is
an iOS simulator, it returns an interactor whose tap/longPress/focus/
type/fill/scroll/scrollIntoView methods route through
runIosRunnerCommand. This removes 7 scattered if-ios-simulator branches
from dispatch.ts, making it impossible to forget runner routing for
future commands.
Changes:
- Swift runner: add longPress command type + longPressAt helper using
XCUICoordinate.press(forDuration:)
- runner-client.ts: add longPress to RunnerCommand type + durationMs field
- interactors.ts: add RunnerContext type, createIosSimulatorInteractor()
that routes through the XCTest runner, move invertScrollDirection here
- dispatch.ts: pass RunnerContext to getInteractor, remove all iOS sim
branching for interactor commands (-90 lines)
Co-authored-by: Cursor <cursoragent@cursor.com>
* restore attempts
* refactor: unify iOS interactor, remove dead input stubs
Since runnerContext is always passed and the capability matrix ensures
iOS only runs on simulators in v1, the two iOS interactor code paths
collapse into one: shared methods (open, close, screenshot) plus runner
overrides spread on top. No branch needed.
This deletes 7 dead iOS input stubs from ios/index.ts (pressIos,
longPressIos, focusIos, typeIos, fillIos, scrollIos, scrollIntoViewIos)
that only ever threw UNSUPPORTED_OPERATION errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
* cleanup
* fixup save-script
* update
---------
Co-authored-by: Cursor <cursoragent@cursor.com>