mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
ed8d5efb00
* fix(daemon): address cwd-scoped sessions by their store key, not their public name An implicitly cwd-scoped session is NAMED `default` and STORED under `cwd:<hash>:default`. Three surfaces built caller-facing text from the name, so each pointed at something that does not exist: - `DEVICE_IN_USE` reported `session "default"` and its recovery hint said `agent-device close --session default`. `--session` marks the session explicit, which disables cwd scoping, so following the hint addressed a different, absent session: `SESSION_NOT_FOUND`, and the device stayed held — the residual half of #2031 that #2057's superseded-daemon reconciliation does not cover. - `session list` reported `sessionStateDir` and `runnerLogPath` under `<state>/sessions/default`, a directory that is never created; the session's real artifacts sit in `<state>/sessions/cwd_<hash>_default`, which is what `open` already answers with. `SessionStore.entries()` exposes the key alongside the record, and `buildSessionRecoveryHint` takes the session's address explicitly. Call sites that only hold the session the current request named pass its name — the address there — so their text is unchanged, as are explicitly named sessions everywhere. Live before/after on an iOS simulator: `open` (cwd-scoped default), then `open --session qa` on the same device. Before, the hint's own `close --session default` answered `SESSION_NOT_FOUND` and the retry failed again; after, the hint names `cwd:8bea844ab16aa9b3:default`, that close releases the device, and the retry opens. Refs #2031, #1394 * fix(daemon): thread the resolved session address through every recovery producer The store key a request resolves — `cwd:<hash>:default` for an implicit session — was known upstream but dropped before the selector-conflict and lock-conflict producers, which then named `SessionState.name`. Both emitted `close --session default`, the unreachable recovery this PR fixes for DEVICE_IN_USE: `--session` marks the session explicit, so that command addresses a different session. `SessionRef` ({ address, session }) now carries the pair, so a recovery producer cannot be handed a record whose address was never resolved. `buildSessionRecoveryHint`, `assertSessionSelectorMatches` and `applyRequestLockPolicy` take it; `prepareLockedRequestBinding` and the Maestro replay route build it from the store key they already hold. Replaces the broad `SessionStore.entries()` with the store's own narrow lookups — `lookup`, `findByDevice`, `listRefs` — so callers receive the session with its address instead of enumerating raw key/record tuples. `session list` reports `address` alongside `name`, through the client contract and serializer, so its discovery output names a value `--session` accepts. Regressions run the production routes, not the helpers: router-level device-in-use, selector-conflict, lock-policy-conflict and `session list` cases open an implicit session and read the address back off the store, plus a typed-Maestro selector-conflict case. Each was observed red against the pre-fix behavior it pins. Refs #2031, #1394. * fix(daemon): doctor names same-device sessions by address; green the fallow gate - sessionChecks enumerated same-device sessions by SessionState.name: the printed close --session default was the exact unreachable recovery this PR removes elsewhere, the name-based dedupe hid two cwd-scoped default sessions from each other, and the evidence sessionStateDir pointed at <state>/sessions/default, which never exists. Candidates now come from listRefs() and report addresses. - findByDevice joins values/delete in .fallowrc.json usedClassMembers (same resolution false positive on this class; the call site is session-open-execution.ts). - the scoped-paths test narrows its response once instead of nine optional-chaining hops, which tripped the CRAP gate. * style: format .fallowrc.json --------- Co-authored-by: Michał Pierzchała <thymikee@gmail.com>