feat(gesture): hold a single-pointer pan at its origin with --hold-ms

Draft
ZI
5h ago
+218-32

Summary

Single-pointer gesture pan takes --hold-ms: the pointer holds still at the origin, then moves over durationMs. Long-press-then-drag UIs (reorderable lists, web pages with a long-press timer) can then be driven by coordinates; gesture drag already holds, but only between selector or ref endpoints. The plan reuses drag's stationary segment (withContactHolds), so every backend that plays plan samples holds; endpoint-only backends (tvOS remote, HarmonyOS) do not, as the docs say.

  • CLI: agent-device gesture pan 200 420 0 240 600 --hold-ms 600
  • Node: client.interactions.pan({ x: 200, y: 420, dx: 0, dy: 240, durationMs: 600, holdMs: 600 })
  • MCP: gesture with { kind: "pan", origin, delta, durationMs, holdMs }

holdMs + durationMs is capped at 10000ms; --pointer-count 2 with --hold-ms is refused. .ad lines carry it as a recorded flag. 19 files changed, 218 insertions(+), 32 deletions(-).

Context: zijinmedia/device-harness#149 (the harness patches 0.21.15's dist until this ships).

Validation

Tested SHA db04d90. pnpm check:affected --run --head: format, lint, typecheck, layering, fallow, build passed; vitest-related failed only in help-conformance-sample-outputs, daemon-runtime-composition and daemon-client-startup-race, which fail the same way on base 72c051d on this host (macOS, Node 22.22). New unit tests cover input, normalization, plan samples, CLI, client and MCP schema.

Draft: device-facing and not yet run live. iOS Simulator evidence will be added here.