Files
callstack__agent-device/CHANGELOG.md
T
Michał Pierzchała 3c09bb2566 fix(daemon): reject unsupported raw --save-script flags at request ingress (#1501)
* fix(daemon): reject unsupported raw --save-script flags at request ingress

`flags.saveScript` arms session-script publication the moment a successful
handler records the request's action, so any recordable command reaching a
handler with the raw flag set could arm publication and write a `.ad`
artifact — `record stop` immediately through record-only cleanup, `trace` and
the interaction commands later on close. The CLI/Node/MCP surfaces only emit
the flag for its released owners, so that arming path was reachable only by a
hand-built wire request or a free-form `batch` step.

Close it at the daemon request seam (`createRequestHandler`), the single entry
point both the socket and HTTP transports funnel through, and ahead of
admission, session lookup, device resolution, and handler dispatch. Ownership
is declared on the command descriptor (`saveScriptFlagOwner`) rather than
re-stated as a string set, so `open`, `close`, and `replay` keep the flag and
everything else is rejected with an ADR 0010 shaped `INVALID_ARGS` carrying a
hint, diagnosticId, and logPath.

With that path pinned closed, a record-only session can no longer carry
`recordSession`, so `record stop`'s immediate `writeSessionLog` could only ever
be a no-op; delete it.

Refs #1478.

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

* test(daemon): assert ADR 0010 diagnostics on save-script rejection

The HTTP test helper projected only code/message/hint, so `diagnosticId`
and `logPath` could regress while the transport tests stayed green.
Preserve both in the helper and assert on each transport that
`diagnosticId` is present, `logPath` is present and exists, and the log
records `save_script_flag_rejected`.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-30 18:10:50 +02:00

5.4 KiB

Changelog

Unreleased

  • --save-script is now accepted only by the commands that declare it — open, close, and replay. A hand-built daemon request (or a batch step) that set saveScript on any other command, such as record or trace, used to arm script publication and could write a .ad artifact; it is now rejected with INVALID_ARGS before the request reaches admission, the device, or any handler. CLI, Node, and MCP usage of --save-script on its documented commands is unchanged.
  • diff screenshot no longer runs the retired best-effort OCR and non-text analyzers. Their optional ocr and nonTextDeltas fields remain in the result type for source compatibility but are no longer emitted; use the baseline/current images and diff artifact with vision for qualitative interpretation.
  • Breaking: removed the deprecated --session-locked and --session-lock-conflicts flags. Use --session-lock reject|strip instead; passing either old flag now fails with Unknown flag: ... Use --session-lock reject|strip instead.
  • Breaking: removed the replay export --format flag. replay export always writes Maestro YAML.
  • Breaking: removed the unused LeaseAllocatePayload, LeaseHeartbeatPayload, and LeaseReleasePayload type exports from agent-device/contracts. Lease request metadata is fully described by DaemonRequestMeta.
  • Maestro compat: assertVisible and assertNotVisible now accept childOf for ancestor scoping, matching tapOn (#1294).
  • Breaking: removed deprecated gesture duration and rotate velocity inputs (#1218).
    • swipe x1 y1 x2 y2 no longer accepts a trailing durationMs positional; use gesture pan x1 y1 (x2-x1) (y2-y1) durationMs for deliberate timed drags.
    • Maestro swipe operations with a duration continue to normalize to gesture pan with the endpoint-hold execution profile, preserving the Maestro-compatible fast-swipe-then-hold behavior on iOS.
    • gesture fling direction x y no longer accepts a trailing durationMs positional; use gesture pan for timed movement.
    • gesture swipe preset no longer accepts a trailing durationMs positional; use gesture pan for timed movement.
    • gesture rotate degrees [x] [y] no longer accepts a trailing velocity positional; rotation pacing is derived from degrees.
    • MCP/Node schemas no longer advertise velocity or durationMs on swipe/fling/gesture swipe; durationMs remains on gesture pan and gesture transform.
    • A .ad script that still carries a removed positional now fails when the script is parsed, before the replay executes any device action, naming the line and its rewrite (for example swipe accepts 4 arguments: x1 y1 x2 y2 (line 6). The trailing durationMs positional was removed: use "gesture pan 197 650 0 -350 300" ...). Previously the script ran up to that step and then failed as a replay divergence.
    • Published the gesture migration guide covering CLI, Node.js, MCP, and saved .ad recordings, plus the deprecation policy the next such removal follows (#1216).
    • replay export now writes an explicit duration: 100 for swipe — the canonical fling duration — instead of omitting it and letting Maestro apply its own 400ms default. Maestro flows replayed by agent-device are unaffected; a timed Maestro swipe still normalizes to gesture pan with the endpoint-hold profile.
  • Breaking: the deprecated rotate CLI command alias has been removed. Use orientation instead; invoking rotate now fails with rotate was renamed to orientation; for the two-finger gesture use: gesture rotate.
  • Breaking (ADR 0014, session ref-frame lifetime): a mutation through an @ref now expires the session's ref frame, so a later ref mutation without a fresh observation fails closed with a typed details.reason (ref_frame_expired, ref_generation_mismatch, plain_ref_requires_complete_frame, or ref_not_issued) instead of acting on a possibly-navigated screen. A ref-oriented sequence that performs several mutations must re-snapshot between them, consume an honestly issued --settle ref in pinned @eN~s<gen> form, or use selectors. Enforcement applies on every platform, not just iOS. Legacy hand-written .ad scripts that reuse several bare refs from one snapshot must capture between mutations or use selectors.
  • Ref reads resolve against the authorized ref frame's source tree, so an internal read-only capture (including Android freshness) can no longer retarget an admitted @ref by positional coincidence. Read-only ref consumers keep the structured staleness warning while the frame retains the ref's evidence.

0.15.0

  • Breaking: apps discovery and public app-list helpers now default to user-installed apps. Use --all or filter: 'all' to include system/OEM apps.
  • Breaking: removed the agent-device/android-apps public subpath. Use the Android app helpers from agent-device/android-adb.
  • Breaking: removed the agent-device/daemon public subpath. Use agent-device/contracts for daemon request/response types.
  • Breaking: removed public local ADB bypass/selection helpers such as spawnAndroidAdbBySerial and resolveAndroidAdbProvider; use createLocalAndroidAdbProvider(device) or pass providers directly to the helpers from agent-device/android-adb.
  • Added Android ADB provider helpers for exec, stream, clipboard, keyboard, app lifecycle, logcat, and port reverse workflows.