Commit Graph

698 Commits

Author SHA1 Message Date
Michał Pierzchała 79c8bc7542 feat: support iOS simulator camera videos 2026-06-11 07:55:32 +02:00
Michał Pierzchała af5eeb6835 fix: address camera video PR feedback 2026-06-10 20:05:17 +02:00
Michał Pierzchała 0267fe2103 feat: support Android emulator camera video files 2026-06-10 19:41:55 +02:00
Michał Pierzchała 712b675cca refactor: extract daemon artifact client (#744)
* refactor: extract daemon artifact client

* docs: clarify artifact download timeout
2026-06-10 14:53:53 +02:00
Michał Pierzchała 963ffc259c refactor: move daemon-shared contracts out of commands (#741) 2026-06-10 14:28:24 +02:00
Michał Pierzchała 2dea65e7ff fix: render optimized MCP command output by default (#748) 2026-06-10 14:28:09 +02:00
Michał Pierzchała b30292d867 refactor(types): deepen type consolidation (#743)
* refactor(types): deepen type consolidation

* fix: satisfy fallow type refactor audit
2026-06-10 14:05:39 +02:00
Michał Pierzchała 582710e01a docs: add agent tightening pass guidance (#746) 2026-06-10 13:38:19 +02:00
Michał Pierzchała a0522c7bcc docs: document issue label workflow (#742) 2026-06-10 13:00:34 +02:00
Michał Pierzchała b8172e3da3 perf(daemon): offload PNG decode/encode and screenshot diff to a worker thread (#734)
* perf(daemon): offload PNG decode/encode and screenshot pixel diff to a worker thread

PNG decode (inflateSync) and per-pixel screenshot diffing previously ran
synchronously on the daemon event loop, stalling all concurrent sessions
while multi-MB screenshots were processed.

- add src/utils/png-worker.ts worker_threads entry (rslib internal/png-worker)
  handling one decode, encode, or diff-pixels job per message
- add src/utils/png-worker-client.ts async wrappers (decodePngAsync,
  encodePngAsync, computeScreenshotDiffPixelsAsync) that lazily spawn the
  worker, resolve it next to the current module in dev (.ts) and dist (.js)
  like the companion tunnel entry, and fall back to the in-process
  synchronous path when the worker is unavailable
- extract the unchanged pixel-compare loop into
  src/utils/screenshot-diff-pixels.ts so both paths share identical logic
- route daemon call sites (screenshot-overlay annotate, compareScreenshots)
  through the async wrappers; results stay byte-identical

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* refactor(daemon): apply review findings to PNG worker offload

- guard postMessage failures: a job-specific send error (e.g. DataCloneError)
  now cleans up its pending entry and falls back to sync for that call only
- resolve the worker entry via a shared src/utils/internal-entry.ts helper
  that returns null on any resolution failure (non-file import.meta.url)
- match repo precedent: spawn the worker with --experimental-strip-types
  when the resolved entry is a .ts module
- report permanent worker degradation once (scoped diagnostic + process
  warning with the failure reason) instead of silently going sync-only
- daemon lifecycle: pre-warm the worker at startup and terminate it during
  shutdown with a 1s best-effort timeout (daemon-only)
- collapse the three async wrappers onto one kind-typed job runner with a
  single unavailability channel (rejection, no null path) and drop the dead
  mismatched-result guards
- derive the diff-pixels contract types from screenshot-diff-pixels.ts and
  share toBuffer via the contract module
- serialize worker errors with normalizeError and reconstruct AppError
  (code/message/details) client-side; the worker reuses decodePng so decode
  failures are identical on both paths
- transfer result buffers back to the client when a view fully owns its
  ArrayBuffer; clone pooled buffers to protect Node's shared buffer pool
- decode baseline/current screenshots concurrently in compareScreenshots
- move resizePngFileToMaxSize to src/utils/png-resize.ts and route its
  decode/encode through the worker (daemon screenshot --max-size path)

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* fix(fallow): declare png worker entry and simplify resultTransferList

The Fallow audit flagged src/utils/png-worker.ts as unreachable from any
entry point and resultTransferList as over the complexity threshold.

- Declare src/utils/png-worker.ts in .fallowrc.json's entry list: it is a
  worker_threads entry point loaded at runtime (mirrors src/daemon.ts /
  src/companion-tunnel.ts and the internal/png-worker rslib entry).
- Flatten resultTransferList into filter/map over an extracted
  ownsEntireArrayBuffer predicate, preserving the exact transfer rule
  (byteOffset === 0, byteLength === owner.byteLength, real ArrayBuffer).
- Add direct unit coverage asserting fully-owned buffers are transferred
  while pooled/offset views are not.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 12:27:44 +02:00
Michał Pierzchała 87d6d0ee6c test: cover artifact transfer characterization (#740)
* test: cover artifact transfer characterization

* test: pin upload resume boundaries
2026-06-10 12:19:03 +02:00
Michał Pierzchała b1d62a365c test: cover daemon-client lifecycle characterization (#739) 2026-06-10 12:18:49 +02:00
Michał Pierzchała 69d296cd32 test: cover daemon HTTP server edge cases (#738) 2026-06-10 11:32:33 +02:00
Michał Pierzchała 8baeb367b9 docs: document daemon trust model and auth hook threat model (#733)
* docs: document daemon trust model and auth hook threat model

Add the daemon trust model (loopback bind, per-boot token, version+code-
signature reuse, artifact safeguards) and AGENT_DEVICE_HTTP_AUTH_HOOK
guidance to the Security & Trust page.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* docs: make daemon token location state-dir aware

Aligns with the worktree-scoped daemon state directories introduced in #719.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* docs: scope the token requirement to authenticated endpoints

GET /health is intentionally unauthenticated (loopback-only liveness),
so the blanket 'every request' claim was inaccurate.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 11:13:58 +02:00
Michał Pierzchała 4f95ca8881 fix(daemon): timing-safe token comparison, daemon.json hardening, shell-quote CVE (#731)
* fix(daemon): timing-safe token comparison and daemon.json permission hardening

Use crypto.timingSafeEqual (via SHA-256 digests, length-independent) for the
three daemon token checks, and chmod daemon.json to 0600 after writes since
writeFileSync only applies mode on creation.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* fix(deps): clear CVE-2026-9277 by overriding shell-quote to >=1.8.4 in test-app

Override added to examples/test-app/pnpm-workspace.yaml (package.json-level
overrides are silently ignored for this nested app, see the comment there).
Lockfile change is limited to shell-quote 1.8.3 -> 1.8.4; pnpm audit is clean.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 11:00:19 +02:00
Michał Pierzchała ab2026816f refactor(types): tuple ownership, LogBackend rename, string-enum helpers + tail dedupes (#720)
* refactor(types): rename NetworkLogBackend -> LogBackend

The union is reused for both network-log and app-log backends, so the
network-specific name was misleading. Also renames the resolveNetworkLogBackend
helper to resolveLogBackend. No behavior change.

* refactor(types): add string-enum helpers (isStringMember/parseStringMember)

Small utils/string-enum.ts helpers for the now-common 'as const tuple' string
enums: a membership guard and a strict exact-match parser. Adopt at the strict
sites (parseSessionSurface, parseScrollDirection, parseSwipePreset, isPerfArea,
isPerfAction), replacing hand-rolled switch/includes boilerplate. Alias-accepting
parsers (device rotation) keep their custom logic. Error messages unchanged.

Chose focused helpers over a defineStringEnum factory: the modules are already
concise with tuple-as-source, and a factory would force export-name churn for no
gain.

* refactor(types): dedupe runner/interaction tail shapes

- RunnerXctestrunCacheKind / RunnerXctestrunArtifactState shared between
  RunnerXctestrunArtifact and AppleRunnerPrepareResult.
- Annotate buildInteractionSurfaceSignature with its existing
  InteractionSurfaceSignature alias.
- RunnerOpts / runnerOptionsFromContext use Pick<RunnerContext, ...>.

(Skipped daemon-invoke-fn: maestro already has its own MaestroRuntimeInvoke
alias, so forcing a shared DaemonInvoke creates naming inconsistency for ~2 lines.)

* refactor(types): dedupe remaining tail shapes

- ElementSelectorTarget (core/interactor-types.ts) shared by
  DirectIosSelectorTarget and ElementSelectorTapOptions (= Omit<...,'raw'>).
- Collapse client-types ClientCommandBaseOptions into the identical exported
  DeviceCommandBaseOptions; merge the two byte-identical snapshot-pick aliases.
- File-local SelectorRuntimeError and LineWriter for repeated inline shapes.
- Export mcp ToolResult and use it for the router's textToolResult return.

Pure refactor, type-only.

* address review: adopt helpers, fix alias direction, tidy tail dedupes

- Adopt parseStringMember/isStringMember at parseGestureDirection and the
  swipe-pattern guard in dispatch-interactions.ts (same module the PR touched;
  byte-identical error/behavior).
- Extract RunnerCallOptions = Pick<RunnerContext,...> in interactor-types.ts;
  reuse in dispatch-interactions + ios/interactions (was written twice).
- Invert the ElementSelector alias direction: ElementSelectorTapOptions stays the
  plain core type; DirectIosSelectorTarget = ElementSelectorTapOptions & { raw }
  (keeps the daemon-only raw field in the daemon module).
- Drop redundant cleanStaleBundles in AppleRunnerLifecycleOptions (already in
  AppleRunnerCommandOptions); drop the now-unnecessary cast in isStringMember.
- callTool returns Promise<ToolResult>; rename SelectorRuntimeError ->
  DirectIosSelectorErrorResult (matches the DirectIosSelector* family).
- Dedupe the log-backend device mapping: export resolveLogBackend and reuse it
  in resolveSessionLogBackendLabel.

Pure refactor; typecheck/lint green, affected tests pass.
2026-06-10 10:55:37 +02:00
Michał Pierzchała a7efcd468f chore(fallow): align local runs with the CI diff gate and upgrade to 2.91 (#735)
* chore(fallow): fit config to repo profile so baselines stay near-empty

- Raise health thresholds in .fallowrc.json to the smallest values that
  pass on a clean tree (maxCyclomatic 58, maxCognitive 77, maxCrap 591)
  instead of grandfathering ~180 findings in fallow-baselines/health.json.
- Raise duplicates.minTokens to 66, the smallest value covering the four
  tolerated clone groups (largest is 65 tokens).
- Regenerate baselines: health.json shrinks from ~18.6 KB of grandfathered
  finding counts to refactoring-target metadata only; dead-code.json is
  empty.
- Upgrade fallow 2.52.0 -> 2.91.0: 2.87.0 made ignorePatterns silence the
  "examples/test-app is not declared as a workspace" warning, which 2.52.0
  emitted regardless of config.
- Remove the unused ensureAdb export (and its now-unused imports) from
  src/platforms/android/adb.ts; it is not re-exported by any public entry
  and has no references anywhere in the repo.
- Document local (pnpm fallow) vs CI (fallow audit) usage in
  CONTRIBUTING.md.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* chore(fallow): keep default thresholds, gate locally via diff-based audit

Revise the previous commit after review: pinning global thresholds at the
repo's historical maxima (cyclomatic 58, cognitive 77, CRAP 591, minTokens
66) weakened the gate for brand-new code and left zero headroom on the
worst existing functions. Restore the original design — fallow default
thresholds with legacy findings grandfathered per-file in
fallow-baselines/health.json — and fix the local-DX problem at the script
level instead:

- .fallowrc.json: drop the health/duplicates overrides so fallow defaults
  (cyclomatic 20, cognitive 15, CRAP 30, minTokens 50) apply to new code.
- fallow-baselines/health.json: regenerate at default thresholds under
  fallow 2.91 (201 grandfathered findings across 108 files); dead-code
  baseline stays empty.
- package.json: `pnpm fallow` now runs `fallow audit --base origin/main`,
  the same diff-based gate CI uses, so it passes on a clean tree. The old
  full-tree summary moves to `pnpm fallow:all` (expected to report legacy
  findings). `check:fallow` is unchanged (CI passes an explicit --base).
- CONTRIBUTING.md: correct the fallow docs accordingly.

Verified: clean tree passes; a new unused export fails the audit; a new
cyclomatic-25 function fails the audit; +1 branch growth in an already-
grandfathered function (classifyBootFailure) is absorbed by the baseline.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 10:53:04 +02:00
Michał Pierzchała aa8a350010 test(maestro): cover runtime target resolution and point parsing behaviors (#736)
* test(maestro): cover runtime target resolution and point parsing behaviors

Pin previously untested behaviors of the Maestro compat target-resolution
layer: selector platform mapping, visible-text query extraction, fuzzy text
exact/partial ordering, index selection and out-of-range errors, childOf
failure messages, ancestor rect inheritance, zero-size rect visibility
errors, regex selector handling (including invalid regexes), malformed
selector INVALID_ARGS errors, visible match counts, and absolute/percentage
point coordinate parsing with malformed-input rejections.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

* test(maestro): tighten assertions per review

- Reduce the malformed-selector test to a single propagation case using a
  tolerant /Unknown selector key/i regex; exact parser wording stays owned
  by src/daemon/__tests__/selectors.test.ts.
- Make the blank fuzzy-query whitespace explicit via a hoisted
  ' '.repeat(3) query interpolated into the expected message.
- Add readMaestroSelectorPlatform boundary cases pinning the
  case-sensitive === 'android' contract ('Android' and 'tvos' -> 'ios').
- Introduce a resolveIosNode helper to collapse the repeated
  resolveMaestroNodeFromSnapshot(..., 'ios', IOS_TAB_FRAME) call sites in
  the new tests.
- Add '50,75%' and '100.5,200' to the parseMaestroPoint rejection loop
  (percent on one coordinate only; integer-only absolute regex).

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 10:39:45 +02:00
Michał Pierzchała a544dc156a refactor(types): documentary NormalizedRect/NormalizedPoint aliases (#721)
* refactor(types): documentary NormalizedRect/NormalizedPoint aliases

Add NormalizedRect/NormalizedPoint aliases of Rect/Point (utils/snapshot.ts)
to convey coordinate space at the two normalized-percentage sites that were
typed as absolute Rect: ScreenshotDiffRegion.normalizedRect and the OCR
block normalizedRect (+ the OCR center-distance path). Documentary only — the
aliases are structurally Rect/Point, so this is intent-conveying, not enforced.

Full nominal branding was scoped out as disproportionate: the normalized
surface is 2 fields with no current cross-space mixing, and rectCenter/
squaredDistance are intentionally space-agnostic.

* address review: relocate NormalizedRect/Point to screenshot-geometry + fix doc

- Move the documentary aliases out of the general snapshot.ts into
  screenshot-geometry.ts (the screenshot-diff geometry module), where their
  only consumers live (better collocation).
- Correct the doc: coords are normalized to the screenshot IMAGE's dimensions,
  not 'viewport'.
2026-06-10 10:37:53 +02:00
Michał Pierzchała 645577554a ci: enforce lint and formatting, add warn-only layering guard (#732)
Add a Lint & Format job (oxlint --deny-warnings + new format:check script) and
a warn-only guard that flags imports of src/commands/* from src/daemon and
src/platforms; the guard flips to a hard failure once shared contracts move
out of the commands layer.

https://claude.ai/code/session_01LXZXzxi55sZ11DSyqWyBA2

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-10 10:36:18 +02:00
Michał Pierzchała 0f7187f543 fix: scope source daemon state by worktree (#719)
* fix: scope source daemon state by worktree

* docs: clarify worktree daemon state tradeoffs

* ci: harden Apple runner cache

* chore: keep daemon state helper internal

* ci: validate Apple runner cache restores

* ci: simplify Apple runner cache setup
2026-06-10 10:32:58 +02:00
Michał Pierzchała 22fba8718c feat: add shutdown command (#718)
* feat: add shutdown command

* fix: address shutdown review feedback

* fix: reject active session shutdown targets

* fix: preserve shutdown failure details

* fix: satisfy shutdown fallow audit

* fix: simplify shutdown session handling
2026-06-10 10:24:42 +02:00
Michał Pierzchała 1de7e73e2a refactor(types): consolidate duplicated types across src/ into single sources of truth (#717)
* refactor(types): reuse canonical string-unions across the codebase

Replace inline duplicates of SessionSurface, ClickButton, DeviceRotation,
BackMode, ScrollDirection, Platform/PlatformSelector/DeviceTarget,
AlertAction, and LeaseBackend with imports of the existing canonical types.
Extract BackMode into a core/back-mode.ts leaf (matching click-button.ts /
session-surface.ts) to keep backend.ts dependency-clean. Add 'satisfies
readonly T[]' drift-guards to the runtime enum tuples consumed by enumField.

Pure refactor: single source of truth for these unions, no behavior change.

* refactor(types): consolidate gesture + daemon/network/metro mode unions

- Add SwipePattern to core/scroll-gesture.ts; reuse SwipePreset,
  ScrollInputDirection, ScrollDirection at remaining inline sites.
- Move DaemonServerMode / DaemonTransportPreference / SessionIsolationMode /
  NetworkIncludeMode to contracts.ts (the client<->daemon boundary); daemon/
  config.ts and daemon/network-log.ts re-export them. Drop client-types.ts's
  three private alias copies.
- Reuse MetroPrepareKind in metro.ts and remote-config-schema.ts.
- Add satisfies-guards to the runtime enum tuples.

Pure refactor, type-only changes.

* refactor(types): single-source remaining string-literal unions

- ElementSelectorKey (core/interactor-types.ts) for the 'id|label|text|value'
  selector-key subset across core/daemon/ios/maestro.
- GESTURE_KINDS + GestureKind (command-catalog.ts), dropping the duplicate
  GESTURE_KIND_VALUES.
- AndroidTextInputAction (android/adb-executor.ts); reuse NetworkLogBackend for
  the app-log backend union.
- Reuse contracts.ts JsonRpcId / JsonRpcRequestEnvelope in mcp router + server.
- New commands/log-command-contract.ts (LOG_ACTION_VALUES + LogAction),
  mirroring perf-command-contract.ts.
- Named Android snapshot helper metadata unions (transport/captureMode/install
  reason) shared between helper + backend metadata.

Pure refactor, type-only changes; full unit suite green.

* refactor(types): consolidate geometry shapes

- Reuse canonical Rect (utils/snapshot.ts) for inline {x,y,width,height}
  literals (parsing, output, screenshot-diff regions/ocr, atspi-bridge).
- GestureReferenceFrame (core/scroll-gesture.ts) as the single reference-frame
  type; TouchReferenceFrame becomes an alias; replace inline
  {referenceWidth,referenceHeight} across daemon + maestro + commands.
- New ImageDimensions (screenshot-geometry.ts) and MovementRange
  (screenshot-diff-ocr.ts) for repeated {width,height} / {min,max} shapes.
- File-local AndroidRecordingSize in record-trace-android.ts.

Pure refactor, type-only changes. Point literals with normalized-vs-absolute
semantics deliberately left untouched.

* refactor(types): consolidate result/options/resolver shapes (+oxfmt)

- Generic PlatformProviderResolver<T> collapses 6 near-identical resolver
  types in request-platform-providers.ts.
- Reuse canonical DaemonError (contracts.ts) / NormalizedError (utils/errors.ts)
  for the inline error DTOs in daemon/types.ts and utils/output.ts.
- Single DaemonFailureResponse: FailedDaemonResponse becomes an alias and the
  maestro-local redefinition is dropped.
- Extract one shared toBackendResult() into commands/runtime-types.ts, deleting
  5 duplicate copies.
- Normalize whitespace with oxfmt across the touched files.

Full unit suite green.

* refactor(types): share TransformGestureParams + RepeatedInput bundles

- TransformGestureParams (core/scroll-gesture.ts) replaces 4 identical inline
  transform-gesture param shapes (core interactor, dispatch, android multitouch,
  client options).
- Reuse RepeatedInput (commands/command-input.ts) for the tap-modifier bundle in
  PressCommandOptions and BackendTapOptions.

Pure refactor, type-only.

* refactor(types): extract BackendResultEnvelope mix-in

Replace the repeated inline { backendResult?: Record<string, unknown>;
message?: string } pair on ~17 single-object command result types with
'& BackendResultEnvelope' (commands/runtime-types.ts). Discriminated-union
variants and single-field result types are intentionally left inline.

Pure refactor, type-only changes; failing files re-verified green in isolation
(full-suite failures were flaky timeouts).

* refactor(types): dedupe runner/replay/selector/exec result shapes

- RunnerSessionOptions = AppleRunnerLifecycleOptions (field-identical).
- Reuse ReplayActionBlockInvoker for the maestro + daemon replay invoker types.
- SelectorSnapshotOptions aliases the canonical SelectorSnapshotInput; annotate
  selectorSnapshotOptionsFromFlags.
- Reuse ExecResult for the { stdout; stderr; exitCode } subset in
  record-trace-errors and app-log-process.

Pure refactor, type-only.

* refactor(types): make canonical tuples the single source for enum unions

Each string-enum module now exports an 'as const' literal tuple as the single
source and derives its union via (typeof TUPLE)[number]: SESSION_SURFACES,
CLICK_BUTTONS, DEVICE_ROTATIONS, BACK_MODES, SCROLL_DIRECTIONS/SWIPE_PRESETS/
SWIPE_PATTERNS, SCROLL_INPUT_DIRECTIONS, ALERT_ACTIONS, DEVICE_TARGETS. The
command metadata/input files import these tuples instead of redefining local
*_VALUES copies, which also retires 10 now-redundant 'satisfies' drift-guards.

Member order preserved everywhere (enumField error messages unchanged). Platform
tuples intentionally left as-is (command-input vs contracts use different orders).

Net -39 lines; tuple+type dual maintenance eliminated for these unions.
2026-06-09 19:13:55 +02:00
Michał Pierzchała 264c804376 0.17.1 v0.17.1 2026-06-09 17:25:49 +02:00
Michał Pierzchała 16312d073d fix: use XCTest drag for iOS swipes (#716)
* fix: use XCTest drag for iOS swipes

* fix: update iOS drag CI expectations
2026-06-09 17:25:31 +02:00
Michał Pierzchała 500f4f3045 refactor: deepen replay test attempt module (#715) 2026-06-09 15:07:30 +02:00
Michał Pierzchała 39e4682592 refactor: deepen runner disposal (#714)
* refactor: deepen runner disposal

* docs: clarify PR descriptions
2026-06-09 15:07:16 +02:00
Michał Pierzchała 49e59d651a feat: record replay test videos (#712)
* feat: record replay test videos

* fix: align replay test video timing

* fix: leave replay test video tail visible

* refactor: clarify replay test video lifecycle

* refactor: pass replay video attempt context directly

* fix: warn on replay video finalization failure
2026-06-09 14:17:32 +02:00
Michał Pierzchała c2b29d5600 fix: stabilize Maestro replay on iOS (#713)
* fix: stabilize Maestro replay on iOS

* fix: scope iOS runner cleanup to daemon owner

* fix: lease iOS runner ownership per device

* fix: release prepared iOS runner daemon in CI

* fix: inline runner lease release cleanup
2026-06-09 14:12:57 +02:00
Michał Pierzchała fe728814c4 0.17.0 v0.17.0 2026-06-08 18:39:25 +02:00
Michał Pierzchała 35f54a863c fix: resolve Maestro taps from regular snapshots (#709)
* fix: resolve Maestro taps from regular snapshots

* fix: tighten Maestro snapshot compatibility

* test: align Maestro snapshot freshness fixtures
2026-06-08 18:12:09 +02:00
Michał Pierzchała 2014cb6873 fix: harden covered snapshot targets (#708)
* fix: block covered snapshot targets

* fix: harden covered snapshot targets
2026-06-08 14:08:52 +02:00
Michał Pierzchała c89719f7ff fix: decode escaped selector values (#711) 2026-06-08 12:58:18 +02:00
Michał Pierzchała 31ce5903a2 feat: add replay test sharding (#707)
* feat: add replay test sharding

* refactor: simplify sharding device resolution

* fix: address sharding review feedback
2026-06-08 10:56:42 +02:00
Michał Pierzchała aa741b474b fix: recover depth-limited iOS snapshots after AX failures (#706)
* fix: recover depth-limited iOS snapshots after AX failures

* refactor: tighten iOS snapshot AX fallback

* fix: preserve iOS AX fallback guidance
2026-06-08 10:48:24 +02:00
Michał Pierzchała 5c083eacc6 fix: harden iOS replay runner prewarm (#705)
* fix: harden iOS replay runner prewarm

* fix: avoid stale iOS runner during relaunch

* fix: stop stale iOS runner processes

* fix: clean stale iOS runners before startup
2026-06-07 20:37:23 +02:00
Michał Pierzchała 81448c8f97 feat: add perf metrics and frames commands (#703)
* feat: add perf metrics and frames commands

* fix: tighten perf command ergonomics

* test: move perf area coverage to provider integration
2026-06-07 20:36:57 +02:00
Michał Pierzchała 86971990cb fix: scope runner diagnostics to sessions (#704) 2026-06-07 11:35:38 +02:00
Michał Pierzchała 76cee982ba fix: stabilize iOS runner navigation taps (#702)
* 0.16.14

* fix: stabilize iOS runner navigation taps

* fix: recover iOS runner after AX failures

* docs: clarify AX-unavailable snapshot recovery

* test: cover synthesized ios provider taps

* test: cover iOS runner AX failure paths

* fix: clarify sparse iOS AX recovery hint
2026-06-07 11:17:27 +02:00
Michał Pierzchała aa5b07faa5 fix: keep iOS runner hot across app closes (#700)
* fix: keep iOS runner hot across app closes

* fix: keep iOS snapshots fast after relaunch

* fix: bound compact iOS snapshots on broken AX trees

* docs: clarify iOS snapshot backend strategy

* test: update Settings replay selectors

* fix: stabilize Settings replay selectors

* fix: fall back for selector interactions

* chore: simplify flat interactive snapshot query
2026-06-06 21:26:12 +02:00
Michał Pierzchała f2424f9d3a refactor: centralize daemon command registry (#693) 2026-06-05 18:34:01 +02:00
Michał Pierzchała 7d7b467699 fix: retry iOS runner prepare launch (#692) 2026-06-05 18:05:04 +02:00
Michał Pierzchała 36012a9e6f fix: update docs router dependency (#691) 2026-06-05 14:49:21 +02:00
Michał Pierzchała 6babdfb6c5 0.16.13 v0.16.13 2026-06-04 15:37:22 -07:00
Michał Pierzchała ad7b386444 feat: cache iOS runner artifacts during prepare (#688)
* feat: cache ios runner artifacts during prepare

* refactor: deepen ios runner lifecycle

* refactor: generalize apple runner prepare

* refactor: simplify apple runner lifecycle

* fix: clarify runner prepare recovery diagnostics

* refactor: trim apple runner provider surface

* test: simplify runner recovery diagnostics assertion
2026-06-04 15:37:05 -07:00
Michał Pierzchała bf21540b9d refactor: consolidate android gesture backend selection (#689) 2026-06-04 15:15:34 -07:00
Michał Pierzchała 7ab9998645 fix: stabilize Maestro post-gesture snapshots (#681)
* fix: stabilize maestro post-gesture snapshots

* fix: harden maestro ci diagnostics and ios prepare

* fix: preserve android freshness baseline for optimized taps

* fix: close ios runner host after sessionless commands

* fix: require tracked app for ios snapshots

* fix: keep in-page swipes on visible content

* test: align lock policy probes with ios snapshot guard

* fix: compose post-gesture snapshots with android freshness

* refactor: clarify post-action snapshot policies

* fix: avoid redundant swipe stabilization flag

* fix: route android swipes through gesture helper

* test: cover android swipe helper fallback
2026-06-04 14:44:33 -07:00
Michał Pierzchała 1881f6f28b 0.16.12 v0.16.12 2026-06-03 12:20:25 -07:00
Michał Pierzchała 3a93071748 docs: update public documentation links (#684) 2026-06-03 12:01:23 -07:00
Michał Pierzchała 86db7e837f fix: align iOS runner cache target metadata (#682)
* fix: align iOS runner cache target metadata

* test: surface iOS cache metadata script stderr
2026-06-03 09:35:34 -07:00