feat(proxy): allocate by device spec and bind the device the lease names
Summary
In proxy mode the CLI picked a device from the daemon's device list before allocating, so open failed when no device existed yet or when several matched. A service that boots devices on allocate could not choose one.
Now, without --udid/--serial, open/install send --platform, --target, --device (and the simulator-set/allowlist scoping) with lease_allocate and no deviceKey. The proxy daemon picks the device with the same resolveDevice rules and names it in the reply (data.device); the CLI binds that device and its deviceKey. A later open on a live lease reuses the leased device. A daemon that names no device: the CLI releases that lease and falls back to the local pick. Exact --udid/--serial and local mode are unchanged. Additive; no protocol version bump.
agent-device open MyApp --platform ios --device "iPhone 17" # through connect proxy
15 files (one doc paragraph, one façade pin in chore(gates)).
Validation
Tested SHA e38bc9ef4. pnpm check:affected --run: all runnable checks passed (466 files, 3604 tests).
Live run on head 4dc358dfba (main merged through 562e798d1b). The built CLI ran through connect proxy to a local agent-device proxy daemon with a private simulator set. A fresh open --platform ios --device "PR3487 Alpha" bound deviceKey ios:mobile:1136B6B3-…4901, and the next screenshot ran on that UDID. On the same lease, open --device "PR3487 Bravo" and open --ios-simulator-device-set <empty set> were refused with INVALID_ARGS / CONNECTION_DEVICE_CONFLICT. No command ran on Alpha (only a devices inventory request).
- New unit tests (daemon pick by name/target, no pick for exact key/no spec/non-proxy; CLI by-spec, renew, older-daemon fallback, exact udid; client reply parsing; HTTP projection) fail without the change.
- Built CLI → built proxy → local daemon, private simulator set:
open --platform ios --device "AD Spec Phone"bound the reply's device (deviceKey ios:mobile:<udid>),screenshotran on it, and the daemon logged nodevicescall. Raw RPC allocate by spec returneddata.device. Old paths (proxy--udid, local--device) still pass.