Skip to content

Commit 1a0477d

Browse files
fix(stats): support legacy daemon responses
1 parent 64edbe2 commit 1a0477d

4 files changed

Lines changed: 40 additions & 5 deletions

File tree

docs/client.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ interface StatsResult {
258258
};
259259
clients: {
260260
total: number; attached: number; readOnly: number;
261-
connections: Array<
261+
connections?: Array<
262262
| {
263263
role: "writable";
264264
rows: number; cols: number;
@@ -290,8 +290,10 @@ point-in-time explanation of the current min-wins result, not an event stream;
290290
polling stats cannot order geometry changes relative to attached-session DATA.
291291
`lastRequestSequence` is a daemon-local counter for the writable connection's
292292
most recent attach or resize request, not a connection identity or timestamp.
293-
The daemon does not retain a durable client identity; socket and packet-parser
294-
state are transport internals and are not exposed.
293+
Older daemons omit `connections`; the aggregate counts remain authoritative and
294+
must not be reconstructed as an empty connection list. The daemon does not
295+
retain a durable client identity; socket and packet-parser state are transport
296+
internals and are not exposed.
295297

296298
## Session Interaction (CLI-oriented)
297299

src/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ export interface StatsResult {
314314
total: number;
315315
attached: number;
316316
readOnly: number;
317-
connections: Array<
317+
connections?: Array<
318318
| {
319319
role: "writable";
320320
rows: number;

src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ export class PtyServer {
774774

775775
let attached = 0;
776776
let readOnly = 0;
777-
const connections: StatsResult["clients"]["connections"] = [];
777+
const connections: NonNullable<StatsResult["clients"]["connections"]> = [];
778778
for (const c of this.clients.values()) {
779779
if (c.readonly) {
780780
readOnly++;

tests/protocol.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
decodeExit,
1818
} from "../src/protocol.ts";
1919
import { Buffer } from "node:buffer";
20+
import type { StatsResult } from "../src/client.ts";
2021

2122
describe("protocol", () => {
2223
describe("encodePacket / PacketReader", () => {
@@ -281,5 +282,37 @@ describe("protocol", () => {
281282
expect(packets[0].type).toBe(MessageType.STATUS);
282283
expect(JSON.parse(packets[0].payload.toString())).toEqual(response);
283284
});
285+
286+
it("accepts an old-daemon STATUS response without connection details", () => {
287+
const response = {
288+
name: "legacy",
289+
terminal: {
290+
cols: 80,
291+
rows: 24,
292+
cursorX: 0,
293+
cursorY: 0,
294+
scrollbackUsed: 24,
295+
scrollbackCapacity: 10024,
296+
},
297+
process: { alive: true, exitCode: null, pid: 123, resources: null },
298+
daemon: { pid: 456, resources: null },
299+
clients: { total: 2, attached: 2, readOnly: 0 },
300+
modes: {
301+
sgrMouse: false,
302+
cursorHidden: false,
303+
kittyKeyboard: false,
304+
kittyKeyboardFlags: [],
305+
},
306+
uptimeSeconds: 10,
307+
createdAt: "2026-07-31T00:00:00.000Z",
308+
} satisfies StatsResult;
309+
310+
const reader = new PacketReader();
311+
const packets = reader.feed(encodeStatusResponse(JSON.stringify(response)));
312+
const decoded = JSON.parse(packets[0].payload.toString()) as StatsResult;
313+
314+
expect(decoded.clients).toEqual({ total: 2, attached: 2, readOnly: 0 });
315+
expect(decoded.clients.connections).toBeUndefined();
316+
});
284317
});
285318
});

0 commit comments

Comments
 (0)