* batch remote watcher events and defer File Explorer refreshes
Remote filesystem watcher events now batch with the shared 150ms trailing and 500ms
max-wait window, coalescing per-path like local events. File Explorer tree and
directory refreshes are scheduled with debounce and transport-aware concurrency caps
(16 local, 8 runtime, 4 SSH). Stale directory cache tracking prevents trusting
collapsed listings skipped by full refresh; they are re-read on re-expansion. Relay
implements a 15-minute idle-only grace cap for zero-PTY relays via PTY pool
lifecycle tracking, independent of explicitly configured grace time.
* fix(watch/relay): bound remote watcher fan-out and read the live relay grace
Three P1 fixes from the SSH/remote freeze audit:
- Remote watchers now debounce on the same 150/500 window as local ones
(finding D), and every teardown path drops the trailing flush timer
instead of letting it fire into a dead watch. The deferred send is
wrapped so a frame disposed mid-window can't escape as a fatal
main-process exception.
- File Explorer refreshes are scheduled and concurrency-capped rather
than fanned out unbounded over expanded dirs (finding C). Local
transports use a zero window, since main already coalesced the burst.
- relay.startGrace reads ptyHandler.configuredGraceTimeMs instead of the
launch-time argv closure, so a grace raised after launch is honored.
The branch selection moves to relay-grace-branch.ts because relay.ts
has no exports and calls main() at import, making it untestable.
Consequence: a host-sleep relay holding zero PTYs now exits after the
idle cap. Pinned by test and documented in
docs/reference/relay-grace-time-reconfiguration.md.
Also drops the duplicated 150/500/5000 constants in the runtime-RPC
batcher in favor of the shared window module.
* docs(relay): correct grace-reconfiguration line numbers after the relay.ts edit
Co-authored-by: Orca <help@stably.ai>
* refactor(file-explorer): use useMemo for paths; remove relay reference
Replace manual ref-based caching with proper React hooks for content-stable path memoization. Remove outdated relay grace-time reference documentation from code review cycle.
* rm design doc
* fix(remote-watcher): prevent stranded timer after close
An in-flight provider receive can land after the batch is torn down.
Without a guard, pushing events to a closed batch would re-arm a timer
that would never be cleared, stranding the task indefinitely. Track the
closed state and skip pushes after close().
Relay.ts comment clarifies why pool watches remain registered during
grace-period shutdown deferral — the socket server stays listening so
a reconnecting client can cancel the grace and resume.
---------
Co-authored-by: Orca <help@stably.ai>