Commit Graph

818 Commits

Author SHA1 Message Date
Michał Pierzchała 28a1dcdb0a refactor: extract provider device runtime seam 2026-06-29 16:53:46 +02:00
Michał Pierzchała 9d4a5ce3bd feat: add direct Limrun cloud runtime 2026-06-27 14:15:23 +02:00
Michał Pierzchała fc81c9edc5 refactor: derive replay metadata platforms from the canonical selectors (#899) 2026-06-27 14:02:00 +02:00
Michał Pierzchała cd00ff8699 refactor: validate JSON-RPC at the MCP/HTTP boundary (#897)
* refactor: validate JSON-RPC at the MCP/HTTP boundary

Wire the previously dead jsonRpcRequestSchema into the MCP stdio decode path and
add a sibling commandRpcParamsSchema for the daemon HTTP command params, replacing
unchecked casts of attacker-controllable wire input with real boundary parsing.

- mcp/server.ts: each inbound payload (and each batch element) is parsed via
  jsonRpcRequestSchema instead of being force-cast to JsonRpcMessage. Valid
  requests (with id), notifications (no id), and batches are accepted and routed
  exactly as before; only genuinely malformed input (non-object, or wrong-typed
  jsonrpc/method/id) is rejected with the standard -32600 Invalid Request error.
  JSON.parse failures still surface as -32700, and malformed input never crashes.
- contracts.ts: add commandRpcParamsSchema next to jsonRpcRequestSchema validating
  the command RPC params; optionalStringArray helper added.
- daemon/http-server.ts: replace the 'params as unknown as Partial<DaemonRequest>'
  double-cast with commandRpcParamsSchema.parse(params).

* fix(daemon): reject malformed command params as 400/-32602

methodToDaemonRequest validated command params via commandRpcParamsSchema.parse, which throws a plain Error on malformed input. That mapped to UNKNOWN -> HTTP 500 / -32000 and leaked the internal '$.x' schema path on the wire. Reporting malformed client input as a server error is the wrong signal.

Wrap the parse so failures throw AppError('INVALID_ARGS', 'Invalid params: ...') with the schema path sigil stripped, and map normalized INVALID_ARGS to JSON-RPC -32602 in the boundary catch so malformed command params now surface as 400/-32602, matching the explicit sibling checks.
2026-06-27 14:01:03 +02:00
Michał Pierzchała 22a9b2fee2 feat: add AppleOS discriminant to the device model (additive) (#896)
* feat: add AppleOS discriminant to the device model (additive)

Add an explicit, stored AppleOS ('ios' | 'ipados' | 'tvos' | 'watchos' |
'visionos' | 'macos') and an optional appleOs field on DeviceInfo so Apple
operating systems are first-class instead of inferred late from DeviceTarget.

- device.ts: add AppleOS type, optional DeviceInfo.appleOs, and make
  resolveApplePlatformName prefer device.appleOs while falling back to the
  existing target-based inference for legacy records. iOS and iPadOS both map
  to the single iOS runner profile; tvOS -> tvOS; macOS -> macOS.
- Populate appleOs at discovery only (no widened filters): iPhone/iPod -> ios,
  iPad -> ipados, tvOS -> tvos, host Mac -> macos.
- resolveRunnerPlatformName threads device.appleOs through.

Non-breaking groundwork for the platforms/apple consolidation: records without
appleOs resolve byte-identically, and no runner SDK/destination selection
changes (iPad still resolves to the iOS runner profile).

* fix: keep appleOs internal and derive ipados from simctl device type
2026-06-27 14:00:32 +02:00
Michał Pierzchała d16f01cb5b refactor: derive platform allow-lists from the canonical device tuples (#895)
The set of platforms was hand-restated in three places that must agree:
the canonical tuples in src/utils/device.ts, the --platform flag's
enumValues in cli-flags.ts, and the leaf-platform validation in
client-normalizers.ts. The two non-canonical copies could drift.

- Export PLATFORMS from device.ts and add an isPlatform() leaf-platform
  type guard derived from it (excludes the `apple` selector).
- Derive the --platform enumValues and usageLabel from PLATFORM_SELECTORS.
- Derive normalizeOpenDevice's leaf-platform check from isPlatform();
  per-platform udid/serial identifier shaping is unchanged.

Behaviorless: the derived sets equal the previous hardcoded sets.
2026-06-27 13:48:55 +02:00
Michał Pierzchała 5a67623585 perf: reduce Apple runner build overhead (#898) 2026-06-27 13:48:38 +02:00
Michał Pierzchała 93d5275e69 refactor: type-safe recording backends + exhaustive capability gating (#894)
* docs: add perfect-shape architecture roadmap

Captures the target architecture (two-registry thesis: CommandDescriptor +
PlatformPlugin over a clean folder DAG with a typed-result spine) and a sequenced,
strangler-fig migration path, grounded in a survey of the current codebase.

This PR implements the first two behaviorless Phase-0 items from that roadmap; the
larger registry work is deliberately deferred to later, independently shippable PRs.

* refactor: parametrize RecordingBackend by recording tag

RecordingBackend is now generic over the recording's platform tag, so each
backend's stop() receives an already-narrowed recording. This deletes all five
'recording as Extract<ActiveRecording, { platform: ... }>' casts — the textbook
discriminated-union-narrowing-by-cast anti-pattern — and makes a backend/tag
mismatch unrepresentable.

start() stays wide (DaemonResponse | ActiveRecording) because a device platform
does not map 1:1 to a recording tag (an iOS device resolves to either the 'ios' or
'ios-device-runner' recording). Device resolution returns a stop-less view
(RecordingStartBackend); stop is dispatched per active recording via the new
exhaustive stopActiveRecording(), replacing resolveRecordingBackendForRecording().

Behaviorless: pure type-level change, no runtime behavior change.

* refactor: make capability platform selection exhaustive

isCommandSupportedOnDevice resolved the per-platform capability bucket with an
if/else ladder whose final branch funneled every unmatched platform into
capability.web. That silently absorbs a future Platform with no compile error.

Replace it with selectCapabilityForPlatform(), an exhaustive switch over the
Platform union with a 'never' guard, so adding a new platform is a compile error
here instead of a silent web mis-gate. Identical behavior for all five current
platforms (ios/macos -> apple, android, linux, web).

* docs(adr): amend ADR 0003 for the single-declaration/derivation model

Ratifies the PR review caveat into the ADR itself: the daemon command registry
boundary is about ownership + the predicate interface, not the physical file a trait
is typed in. A derived/projected daemon registry is permitted only if it preserves
four invariants (daemon-owned declaration, unchanged predicate interface, no leakage
into public projections, one declaration per concern enforced by types). The original
decision stands; collapsing daemon policy into a public command registry remains
forbidden.

* docs: refine command axis to facet composition (ADR 0003-aligned)

- §2/§5.2: CommandDescriptor composes domain-owned facets (surface@commands,
  capability@core, daemon@src/daemon) and projects them — compose-with, not
  collapse-into. Adds the four ADR-0003 invariants.
- §6: mark the two shipped Phase-0 items (generic RecordingBackend<P>, exhaustive
  capability selection); link the Apple plan from Phase 3.
- §5.1: Apple as the first PlatformPlugin instance, owning an AppleOS leaf axis.
- §8: before/after diagrams for the command axis + the two-axis summary.

* docs: add apple-platform-consolidation plan (AppleOS leaf axis)

One 'apple' Platform with an AppleOS discriminant (ios/ipados/tvos/watchos/
visionos/macos) rather than six Platform literals (which would collide with the
cross-platform 'target' axis). Captures the 4-investigator survey: ~85% of
platforms/ios is already the OS-agnostic Apple engine; the XCTest runner already
builds ios|macos|tvos; macOS is included as a distinct AppKit leaf (already
entangled). visionOS is scoped net-new work; watchOS is an unsupported sentinel
(XCUITest can't drive it). Before/after diagrams, per-OS readiness, sequencing.
2026-06-27 12:33:48 +02:00
Michał Pierzchała 78ca8fb9be 0.18.0 v0.18.0 2026-06-26 19:53:24 +02:00
Michał Pierzchała a822325375 feat: add integrated device leasing (#890)
* feat: add integrated device leasing

* fix: keep metro bearer token out of generated proxy profile

The proxy connect profile is written to disk as a non-secret remote config,
but it unconditionally copied `metroBearerToken` into that file, leaking the
secret at rest. Mirror the cloud path, which keeps `daemonAuthToken` in-memory
only: the token still flows through this connect via the returned flags, and
later commands re-supply it via AGENT_DEVICE_METRO_BEARER_TOKEN. Extend the
non-secret-profile test to assert the bearer token is absent from disk.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPa5Z9GBkeqoxVctC85N7e

* fix: always release device lease on session close

releaseSessionLease + sessionStore.delete ran only on the happy path, after
several awaits (app-log/perf/snapshot teardown, platform close dispatch,
runner stop) that can throw. A failed close therefore stranded the device
lease until the inactivity expiry. Wrap teardown in try/finally so ownership
is always freed; the original error still propagates after finally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPa5Z9GBkeqoxVctC85N7e

* fix: reconcile integrated device leasing

* docs: simplify remote lease guidance

* refactor: satisfy leasing fallow checks

* fix: harden integrated device leasing

* refactor: deepen device lease lifecycle

* refactor: centralize lease scope projection

* fix: harden proxy lease e2e flow

* fix: address lease review feedback

* refactor: tighten lease release cleanup

* fix: simplify proxy startup output

* fix: harden cloud lease identity

* fix: color proxy startup output

* fix: simplify proxy tunnel placeholder

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-26 19:37:08 +02:00
Michał Pierzchała 8f92572ae4 feat: expose web screen recording (#891) 2026-06-26 19:36:50 +02:00
Michał Pierzchała a9069692de refactor: model recording backends (#893)
* refactor: model recording backends

* refactor: simplify recording backend seam
2026-06-26 18:30:35 +02:00
Michał Pierzchała 2d6fc98222 refactor: tighten daemon output helpers (#892)
* refactor: tighten daemon screenshot typing

* refactor: share screenshot result typing

* refactor: inline record shape checks

* refactor: inline record readers

* refactor: type batch and network output

* refactor: type batch run response

* refactor: narrow batch and observability output types

* refactor: validate typed batch runtime hints

* refactor: restore record boundary guard

* refactor: split daemon output parsers

* refactor: narrow screenshot overlay parser

* refactor: type screenshot overlay data

* refactor: type shutdown result payload
2026-06-26 16:32:52 +02:00
Michał Pierzchała 8c2b1adeb1 feat: support agent-cdp remote bridge sessions (#878) 2026-06-26 12:51:21 +02:00
Michał Pierzchała c16a8d5efb docs: clarify agent-device help entrypoint (#884)
* docs: clarify agent-device help entrypoint

* docs: trim duplicated help guidance
2026-06-26 12:11:29 +02:00
Michał Pierzchała 053bbace30 0.17.10 v0.17.10 2026-06-25 21:48:19 +02:00
Michał Pierzchała be1e1c9931 feat: add cdp command agent-cdp passthrough (#873)
* feat: add agent-cdp passthrough

* docs: narrow agent-cdp memory guidance

* chore: pin agent-cdp 1.6.0

* test: cover agent-cdp guidance

* fix: preserve agent-cdp passthrough flags

* fix: expose CDP wrapper as cdp

* docs: move CDP workflow to debugging guide

* docs: mention cdp in command reference
2026-06-25 21:44:47 +02:00
Michał Pierzchała 8c49d54ff1 fix: clarify proxy runner ownership (#882)
* fix: clarify proxy runner ownership

* fix: tighten proxy runner review follow-ups
2026-06-25 21:44:31 +02:00
Michał Pierzchała 98c0b1d3bf test: migrate test app to expo dev client (#881)
* test: migrate test app to expo dev client

* docs: align test app device targeting

* docs: clarify dev client setup tradeoffs

* docs: remove stale sdk reference
2026-06-25 21:43:14 +02:00
Michał Pierzchała 24cb2b622c fix: refine Apple provider pressure reporting (#877) 2026-06-25 17:34:50 +02:00
Michał Pierzchała 56d8e3902a test: migrate Android recording sizing coverage (#876) 2026-06-25 17:33:51 +02:00
Michał Pierzchała c142514ca6 docs: clarify agent-device QA mental model (#875) 2026-06-25 17:19:22 +02:00
Michał Pierzchała 19417f0a01 fix: avoid copying pnpm node_modules into worktrees (#872) 2026-06-25 12:12:29 +02:00
Michał Pierzchała fa1b0b7c8a docs: configure agent skill conventions (#871) 2026-06-25 11:02:37 +02:00
Michał Pierzchała 63e68cd596 0.17.9 v0.17.9 2026-06-25 10:18:41 +02:00
Michał Pierzchała ced61ce382 fix: disable nested sandboxing for ios runner builds (#869) 2026-06-25 10:18:00 +02:00
Michał Pierzchała f253d50a63 fix: resolve web find locators (#870) 2026-06-25 10:12:29 +02:00
Michał Pierzchała 09339e12cc fix: honor scroll duration across platform plumbing (#866)
* refactor: modularize scroll command plumbing

* fix: honor scroll duration across platforms

* fix: address scroll duration review comments
2026-06-25 10:11:50 +02:00
Michał Pierzchała ba825d8df2 fix: use desktop scroll events on macOS (#863)
* fix: use desktop scroll events on macOS

* fix: support paced macOS desktop scroll

* fix: clear scroll CI quality gates

* fix: address macos scroll review feedback

* refactor: simplify macos scroll plumbing

* fix: tighten scroll duration contract

* fix: limit apple scroll duration reporting
2026-06-25 07:38:21 +02:00
Michał Pierzchała df490ee859 fix: recover Android snapshots from system-only helper output (#861)
* fix: recover Android snapshots from system-only helper output

* fix: tighten Android snapshot recovery follow-up

* fix: preserve Android foreground container pruning
2026-06-25 07:37:23 +02:00
Michał Pierzchała d8e6bb7aa7 fix: add web viewport control and screenshot aliases (#865)
* fix: add web full-page screenshots

* fix: add web viewport command and screenshot aliases

* fix: address viewport CI regressions
2026-06-24 19:35:03 +02:00
Michał Pierzchała 5be101c281 fix: clean up Android snapshot helper sessions (#862) 2026-06-24 19:29:24 +02:00
Michał Pierzchała c9748a9a35 refactor: extract daemon selector capture runtime (#859) 2026-06-24 17:53:24 +02:00
Michał Pierzchała e97e2542a8 refactor: unify selector capture runtime (#857) 2026-06-24 17:29:22 +02:00
Michał Pierzchała 8a34821079 test: guard Maestro swipe stabilization flag (#860) 2026-06-24 17:13:56 +02:00
Michał Pierzchała b2030289e1 refactor: migrate command families to facets (#854)
* refactor: split management command facets

* refactor: migrate command families to facets

* test: isolate android bundletool lookup

* refactor: tighten command facet assembly

* fix: polish command facet follow-ups
2026-06-24 17:13:14 +02:00
Michał Pierzchała 5a84507b08 docs: add selector capture reliability contract (#858) 2026-06-24 17:03:57 +02:00
Michał Pierzchała a179e1e07a docs: add README articles and videos (#855) 2026-06-24 13:23:08 +02:00
Michał Pierzchała 7739b71a25 refactor: centralize command family facets (#849) 2026-06-24 12:40:03 +02:00
Michał Pierzchała 0b840d957d chore: add worktree include config (#853) 2026-06-24 08:04:17 +02:00
Michał Pierzchała 091c7dbc14 refactor: deepen runner command traits (#847) 2026-06-23 19:00:21 +02:00
Michał Pierzchała 2e02f767ed fix: validate batch steps through command contracts (#848) 2026-06-23 18:58:38 +02:00
Michał Pierzchała 180a74b63f refactor: share daemon HTTP contract helpers (#846) 2026-06-23 18:16:14 +02:00
Michał Pierzchała 51eaa7fd20 0.17.8 v0.17.8 2026-06-23 17:38:26 +02:00
Michał Pierzchała d47cd30117 feat: add agent-device proxy command (#844) 2026-06-23 17:20:08 +02:00
Michał Pierzchała c28148420b fix: use native web ref interactions (#843) 2026-06-23 16:36:21 +02:00
Michał Pierzchała 19f73c8fe3 ci: fix iOS simulator boot timeout (#845) 2026-06-23 16:24:50 +02:00
Michał Pierzchała bf8d952e21 fix: speed up web snapshots (#842)
* fix: speed up web snapshots

* ci: stabilize iOS simulator smoke boot
2026-06-23 14:13:30 +02:00
Michał Pierzchała b3b8c90fda 0.17.7 v0.17.7 2026-06-23 10:07:07 +02:00
Michał Pierzchała e6b40dc6ed docs: simplify CLI help flag scoping (#840)
* docs: simplify CLI help flag scoping

* fix: restore connect remote config flags

* docs: restore targeted CLI help cues

* fix: address CLI help review comments

* docs: tighten agent CLI planning guidance
2026-06-23 09:32:03 +02:00