say which shells nobody is looking at

The sidecar has always sent `clients` on each session and this list has always dropped it, so a shell
you are typing into and a shell nothing is attached to rendered identically. It is now on the type,
shown as "N attached", and a zero earns the row an orphan badge — the count only helps if you do not
have to read it to notice.

Also records §5.1 and the whole of §1 in the todo, including that the diff-the-layout implementation
§5.1 used to propose is struck and why.
This commit is contained in:
2026-08-07 09:58:04 +00:00
parent c92b51cacb
commit 2c84bb34be
2 changed files with 79 additions and 17 deletions
@@ -22,6 +22,10 @@ type PtySession = {
lastActivityAt: number;
title?: string;
pid?: number;
// How many sockets are attached. The sidecar has always sent it and this list has always dropped it,
// which left every row looking the same — yet it is the only field that says whether a shell is one
// you are looking at or one nothing is pointing at any more.
clients?: number;
};
const RELATIVE_UNITS: [limit: number, div: number, unit: string][] = [
@@ -87,10 +91,19 @@ export const RunningShells = () => {
<div className="min-w-0 flex-1">
{/* The title the shell set for itself (OSC 0/2) — usually the running command. It is what
makes an abandoned shell identifiable instead of a bare uuid. */}
<p className="truncate text-xs font-medium">{s.title || 'shell'}</p>
<p className="truncate text-xs font-medium">
{s.title || 'shell'}
{s.clients === 0 && (
<span className="ml-1.5 rounded bg-amber-500/15 px-1 py-px text-[10px] text-amber-400">
orphan
</span>
)}
</p>
<p className="truncate font-mono text-[10px] opacity-50">
{s.sessionId.slice(0, 8)} · {s.cols}×{s.rows}
{s.pid ? ` · pid ${s.pid}` : ''} · idle {since(s.lastActivityAt)} · up {since(s.createdAt)}
{s.pid ? ` · pid ${s.pid}` : ''}
{s.clients === undefined ? '' : ` · ${s.clients} attached`} · idle {since(s.lastActivityAt)} · up{' '}
{since(s.createdAt)}
</p>
</div>
<button