diff --git a/packages/server/src/client/daemon-client.ts b/packages/server/src/client/daemon-client.ts index df9ed4945..f927f3fa6 100644 --- a/packages/server/src/client/daemon-client.ts +++ b/packages/server/src/client/daemon-client.ts @@ -2613,7 +2613,7 @@ export class DaemonClient { timeout: 10000, options: { skipQueue: true }, }); - if (!payload.error) { + if (payload.error === null) { this.setTerminalSlot(terminalId, payload.slot); } return payload; diff --git a/packages/server/src/server/daemon-e2e/terminal.e2e.test.ts b/packages/server/src/server/daemon-e2e/terminal.e2e.test.ts index 4b044fabd..73f3b5410 100644 --- a/packages/server/src/server/daemon-e2e/terminal.e2e.test.ts +++ b/packages/server/src/server/daemon-e2e/terminal.e2e.test.ts @@ -404,6 +404,11 @@ async function subscribeRawTerminal( if (message.message.type !== "subscribe_terminal_response") { throw new Error("Expected subscribe_terminal_response"); } + if (message.message.payload.error !== null) { + throw new Error( + `Expected successful subscribe_terminal_response: ${message.message.payload.error}`, + ); + } expect(message.message.payload).not.toHaveProperty("state"); return message.message.payload.slot; } diff --git a/packages/server/src/server/session.ts b/packages/server/src/server/session.ts index 3d2979c1c..a68bcf37d 100644 --- a/packages/server/src/server/session.ts +++ b/packages/server/src/server/session.ts @@ -7661,7 +7661,6 @@ export class Session { type: "subscribe_terminal_response", payload: { terminalId: msg.terminalId, - slot: 0, error: "Terminal manager not available", requestId: msg.requestId, }, @@ -7675,7 +7674,6 @@ export class Session { type: "subscribe_terminal_response", payload: { terminalId: msg.terminalId, - slot: 0, error: "Terminal not found", requestId: msg.requestId, }, @@ -7686,11 +7684,17 @@ export class Session { const slot = this.bindActiveTerminalStream(session); if (slot === null) { + this.sessionLogger.warn( + { + terminalId: msg.terminalId, + activeTerminalStreamCount: this.activeTerminalStreams.size, + }, + "Terminal stream slot exhaustion", + ); this.emit({ type: "subscribe_terminal_response", payload: { terminalId: msg.terminalId, - slot: 0, error: "No terminal stream slots available", requestId: msg.requestId, }, diff --git a/packages/server/src/shared/messages.ts b/packages/server/src/shared/messages.ts index f96199bae..ee51e0b2a 100644 --- a/packages/server/src/shared/messages.ts +++ b/packages/server/src/shared/messages.ts @@ -2161,12 +2161,19 @@ export const CreateTerminalResponseSchema = z.object({ export const SubscribeTerminalResponseSchema = z.object({ type: z.literal("subscribe_terminal_response"), - payload: z.object({ - terminalId: z.string(), - slot: z.number().int().min(0).max(255), - error: z.string().nullable(), - requestId: z.string(), - }), + payload: z.union([ + z.object({ + terminalId: z.string(), + slot: z.number().int().min(0).max(255), + error: z.null(), + requestId: z.string(), + }), + z.object({ + terminalId: z.string(), + error: z.string(), + requestId: z.string(), + }), + ]), }); export const KillTerminalResponseSchema = z.object({ diff --git a/packages/server/src/shared/terminal-stream-protocol.ts b/packages/server/src/shared/terminal-stream-protocol.ts index 33461f367..6970b9620 100644 --- a/packages/server/src/shared/terminal-stream-protocol.ts +++ b/packages/server/src/shared/terminal-stream-protocol.ts @@ -84,7 +84,7 @@ export function decodeTerminalStreamFrame(bytes: Uint8Array): TerminalStreamFram } return { opcode, - slot: bytes[1] ?? 0, + slot: bytes[1], payload: bytes.subarray(2), }; }