1032 Commits

Author SHA1 Message Date
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
Michał Pierzchała 4eeec6093d 0.16.11 v0.16.11 2026-06-03 05:16:24 -07:00
Michał Pierzchała 86687feba6 fix: restore snapshot request timeout (#680) 2026-06-03 05:15:55 -07:00
Michał Pierzchała 7400701857 perf: speed up iOS swipes and harden runner cache (#676)
* perf: speed up ios swipes and harden runner cache

* fix: harden maestro replay smoke tests
2026-06-03 04:59:13 -07:00
Michał Pierzchała 6946c2f156 fix: allow fresh session device binding (#677) 2026-06-02 20:16:42 -07:00
Michał Pierzchała 491ad7e922 fix: improve session ownership and recovery guidance (#674)
* fix: improve session recovery guidance

* fix: quote session recovery commands

* test: simplify record session cleanup fixtures

* test: cover recovery hint edge cases

* test: trim duplicate recovery quoting coverage

* fix: scope implicit sessions by caller workspace

* fix: surface session state directory

* fix: remove unused session store check

* test: trim duplicate session recovery coverage
2026-06-02 14:06:00 -07:00
Michał Pierzchała 041b48222f feat: add iOS runner prepare command (#673)
* feat: add ios runner prepare command

* fix: shorten snapshot request timeout

* fix: refine prepare and snapshot timeouts

* test: cover prepare ios runner provider scenario
2026-06-02 12:08:34 -07:00
Michał Pierzchała 6f637d0e93 fix: filter covered Android snapshot surfaces (#675)
* fix: filter covered android snapshot surfaces

* fix: guard android drawing order metadata
2026-06-02 12:01:34 -07:00
Michał Pierzchała 0313262a6a docs: clarify physical device signing help (#672) 2026-06-02 08:50:35 -07:00
Michał Pierzchała 6247a3d4a5 0.16.10 v0.16.10 2026-06-02 06:42:54 -07:00
Michał Pierzchała 3847f71c50 perf: avoid android hierarchy probe for scroll (#671) 2026-06-02 06:41:53 -07:00
Michał Pierzchała 66119e21bb perf: adapt ios runner uptime preflight (#662) 2026-06-01 21:15:15 -07:00
Michał Pierzchała 7f035f34b4 fix: reduce ios runner invalidation after status recovery (#666) 2026-06-01 20:58:50 -07:00
Michał Pierzchała 7e30a83057 fix: tune iOS runner response retention (#665)
* fix: tune iOS runner response retention

* fix: require explicit runner response retention
2026-06-01 20:24:04 -07:00
Michał Pierzchała 3ae2472d44 fix: keep iOS runner status transport visible (#663) 2026-06-01 20:23:29 -07:00
Michał Pierzchała f2ef68871c docs(ios): note idleTimeout: false guardrail + why swipe/mouseClick bypass performGesture (review nits) (#664) 2026-06-01 21:27:07 -05:00
Michał Pierzchała 57cd3f3a07 perf: recover iOS runner responses by status (#661)
* perf: recover ios runner responses by status

* docs: plan ios runner protocol optimizations

* fix: clarify ios runner recovery errors

* fix: retry read-only in-flight runner commands

* refactor: split ios runner status recovery handling
2026-06-01 21:26:15 -05:00