Skip to content

(remote): distinguish unknown, unreachable and empty remote hosts - #234

Merged
devsuitup merged 2 commits into
mainfrom
feat/remote-host-freshness-212
Sep 9, 2026
Merged

devsuitup merged 2 commits into
mainfrom
feat/remote-host-freshness-212

Conversation

@devsuitup

Copy link
Copy Markdown
Owner

Closes #212.

A remote host answering with an empty session list was indistinguishable from
a host that had never been read and from a host that could not be reached at
all. All three rendered the same way, so an SSH timeout looked exactly like an
idle VPS — which is what made the attach feature look broken last night when
the real cause was three SSH timeouts in two and a half hours.

Freshness contract

getRemoteSessions(alias) now returns { sessions, at, error } instead of a
bare array:

  • at — epoch ms of the last cycle that completed without throwing, null if
    the host has never been read.
  • error — the last failure's message, null when the last cycle succeeded.

A failed cycle clears sessions but never bumps at, so staleness and failure
stay separable. Both call sites are updated in the same commit.

What it shows

A dot on each remote project header:

State Dot Title
Never read amber not yet synced with this host
Last cycle failed red host unreachable: <reason> (last confirmed 4m ago)
Read, no session dim no live session (confirmed 12s ago)
Read, sessions green 2 live sessions (confirmed 12s ago)

Each remote session row also carries its CLI status with the age of that
status — idle · 26s ago versus idle · 23h ago. The descriptor's status
field records the last transition, not a heartbeat, so a day-old state must not
be readable as a fresh one.

Badge tooltip

The badge title still claimed Read-only session mirrored from <host>, written
before attach existed. It now reads the same remoteAttachable flag the click
routing uses, so hover and click agree: attach for a live session, transcript
otherwise.

Verification

Every behaviour above is pinned by a mutation that turns the relevant test red:
forcing remoteHostError false, hardcoding the age formatter, hardcoding the
live/empty class, and restoring the old badge wording.

task check: 1154 tests, 0 fail, lint 0 errors.

getRemoteSessions(alias) returned [] for three cases the sidebar could
not tell apart: never read, read with zero live sessions, and a failed
cycle (descriptors cleared on purpose). It now returns
{ sessions, at, error } instead of a bare array -- at is the last
successful cycle's timestamp (null if never), error is the last
failure's message (null if the last cycle succeeded) -- because a
failed cycle must not look identical to a genuinely idle host, nor
overwrite the last known-good timestamp. annotateRemoteAttachable
threads at/error onto each remote project and each session's live
status/statusUpdatedAt onto the sidebar payload.

The sidebar shows a host-level dot (unknown / unreachable with reason
/ empty / live with a count) next to the project name, and a per-session
status + age line so a 24h-old status never reads as a few seconds old.

Refs #212
…ranscript

The badge tooltip was written before remote attach existed and claimed every
remote row was a read-only mirror. It now reads the same remoteAttachable flag
the click routing uses, so hover and click agree.
@devsuitup
devsuitup merged commit 6ccfe9f into main Sep 9, 2026
10 checks passed
@devsuitup
devsuitup deleted the feat/remote-host-freshness-212 branch September 9, 2026 09:18
@devsuitup devsuitup mentioned this pull request Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(remote): show live status for remote sessions

1 participant