fix(v0.4): mirror size-clamp bug + session manager page
The mirror looked broken because a backgrounded tab on one device still pinned the shared PTY to its (default 80x24) size — so the device actively viewing got a cramped terminal. Fix: only an ACTIVELY-VIEWING client votes on PTY size. - attachWs no longer seeds a default size vote (a join may be a hidden mirror) - new 'blur' client message + clearClientDims(): a tab going hidden withdraws its size vote (still mirrors output); show() re-casts it - PTY size = min cols/rows across clients that have actually reported dims - session/protocol tests cover hidden-mirror-doesn't-clamp + blur Session manager (separate page, for the 'too many sessions' problem): - GET stays; add DELETE /live-sessions/:id and DELETE /live-sessions[?detached=1] - manager.killById(); LiveSessionInfo gains cols/rows - public/manage.html + manage.ts: list/open/kill sessions, kill-all / kill-detached, auto-refresh; 🗂 toolbar button; bundled as a 2nd esbuild entry Verified: two concurrent clients mirror output + shared input; manage page lists/kills (3→2→0). 225 tests green, tsc clean.
This commit is contained in:
13
src/types.ts
13
src/types.ts
@@ -45,6 +45,9 @@ export type ClientMessage =
|
||||
| { type: 'attach'; sessionId: string | null; cwd?: string }
|
||||
| { type: 'input'; data: string }
|
||||
| { type: 'resize'; cols: number; rows: number }
|
||||
// v0.4: this client stopped actively viewing (tab hidden) — withdraw its size
|
||||
// vote so a background mirror doesn't clamp the shared PTY (min-dims).
|
||||
| { type: 'blur' }
|
||||
| { type: 'approve' }
|
||||
| { type: 'reject' };
|
||||
|
||||
@@ -167,10 +170,11 @@ export interface Session {
|
||||
// impl anchors [src/session/session.ts]:
|
||||
// createSession(cfg: Config, dims: Dims, now: number, onExit: (s: Session) => void): Session
|
||||
// // spawn failure THROWS, not swallowed (M4)
|
||||
// attachWs(session: Session, ws: WebSocketLike, dims: Dims): void // adds a client, replays buffer (no kick)
|
||||
// attachWs(session: Session, ws: WebSocketLike): void // adds a client, replays buffer (no size vote until it resizes)
|
||||
// detachWs(session: Session, ws: WebSocketLike, now: number): void // removes one client; never kills PTY
|
||||
// writeInput(session: Session, data: string): void // no-op after exit (L4)
|
||||
// setClientDims(session: Session, ws: WebSocketLike, cols, rows): void // PTY = min over clients (L4 no-op after exit)
|
||||
// setClientDims(session: Session, ws: WebSocketLike, cols, rows): void // PTY = min over active viewers (L4 no-op after exit)
|
||||
// clearClientDims(session: Session, ws: WebSocketLike): void // withdraw this client's size vote (tab hidden / blur)
|
||||
// kill(session: Session): void
|
||||
|
||||
/* ──────────────────────── manager (§3.5) ─────────────────────── */
|
||||
@@ -183,6 +187,8 @@ export interface LiveSessionInfo {
|
||||
status: ClaudeStatus;
|
||||
exited: boolean;
|
||||
cwd: string | null;
|
||||
cols: number; // current PTY size (for the manage page)
|
||||
rows: number;
|
||||
}
|
||||
|
||||
export interface SessionManager {
|
||||
@@ -196,6 +202,9 @@ export interface SessionManager {
|
||||
get(id: string): Session | undefined;
|
||||
/** Live sessions for multi-device discovery (newest first). */
|
||||
list(): LiveSessionInfo[];
|
||||
/** Kill a session by id (manage page): close its clients, kill the PTY, drop it.
|
||||
* Returns true if a session was found and killed. */
|
||||
killById(id: string): boolean;
|
||||
/** Set a session's Claude status (from a hook) and push it to the attached ws (H2/H3). */
|
||||
handleHookEvent(
|
||||
sessionId: string,
|
||||
|
||||
Reference in New Issue
Block a user