From 83dfd44eca487549d62516a0dd5dc297e5070092 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 10 Aug 2026 01:30:37 -0700 Subject: [PATCH] fix(terminal): always emit full intro art (#121501) * fix(terminal): always emit full intro art Open-time request.cols is the pre-fit boot grid (the client resizes right after open), so the 40-column gate suppressed the art on real terminals. Live-verified against a dev gateway on post-merge main. * test(terminal): align intro banner fixture --- src/gateway/terminal/intro-banner.test.ts | 8 +------- src/gateway/terminal/intro-banner.ts | 7 +++++-- src/gateway/terminal/session-manager.intro-banner.test.ts | 2 +- src/gateway/terminal/session-manager.test.ts | 2 +- src/gateway/terminal/session-manager.ts | 2 +- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/gateway/terminal/intro-banner.test.ts b/src/gateway/terminal/intro-banner.test.ts index 31d4bda1a5c6..c93ea812c1b1 100644 --- a/src/gateway/terminal/intro-banner.test.ts +++ b/src/gateway/terminal/intro-banner.test.ts @@ -22,7 +22,7 @@ const EXPECTED_ART = [ describe("composeTerminalIntroBanner", () => { it("composes the exact colored CRLF intro and resets ANSI state", () => { - const banner = composeTerminalIntroBanner(80); + const banner = composeTerminalIntroBanner(); expect(banner).toBe( `\r\n\x1b[38;5;223mWelcome to the Claw.\x1b[0m\r\n\r\n\x1b[38;5;216m${EXPECTED_ART.join("\r\n")}\r\n\r\n\x1b[0m`, @@ -31,10 +31,4 @@ describe("composeTerminalIntroBanner", () => { expect(banner.endsWith("\r\n\r\n\x1b[0m")).toBe(true); expect(banner.replaceAll("\r\n", "")).not.toContain("\n"); }); - - it("emits only the headline below 40 columns", () => { - expect(composeTerminalIntroBanner(39)).toBe( - "\r\n\x1b[38;5;223mWelcome to the Claw.\x1b[0m\r\n\r\n\x1b[0m", - ); - }); }); diff --git a/src/gateway/terminal/intro-banner.ts b/src/gateway/terminal/intro-banner.ts index 1f3e82a1876b..95b225651c9c 100644 --- a/src/gateway/terminal/intro-banner.ts +++ b/src/gateway/terminal/intro-banner.ts @@ -19,8 +19,11 @@ const TERMINAL_INTRO_ART = [ " .::•::•::", ] as const; -export function composeTerminalIntroBanner(cols: number): string { +// Always full art: open-time request.cols is the pre-fit boot grid (the client +// resizes immediately after open), so width gating keyed on it suppressed the +// art on real, wide terminals. +export function composeTerminalIntroBanner(): string { const headline = `\x1b[38;5;223mWelcome to the Claw.${RESET}`; - const art = cols >= 40 ? `\x1b[38;5;216m${TERMINAL_INTRO_ART.join("\r\n")}\r\n\r\n` : ""; + const art = `\x1b[38;5;216m${TERMINAL_INTRO_ART.join("\r\n")}\r\n\r\n`; return `\r\n${headline}\r\n\r\n${art}${RESET}`; } diff --git a/src/gateway/terminal/session-manager.intro-banner.test.ts b/src/gateway/terminal/session-manager.intro-banner.test.ts index b2a4a55f3ede..9e006cdc94c8 100644 --- a/src/gateway/terminal/session-manager.intro-banner.test.ts +++ b/src/gateway/terminal/session-manager.intro-banner.test.ts @@ -13,7 +13,7 @@ describe("TerminalSessionManager intro banner", () => { if (!operator.ok) { throw new Error("expected operator open"); } - const intro = composeTerminalIntroBanner(80); + const intro = composeTerminalIntroBanner(); expect(manager.snapshot(operator.sessionId)).toBe(intro); await vi.advanceTimersByTimeAsync(4); diff --git a/src/gateway/terminal/session-manager.test.ts b/src/gateway/terminal/session-manager.test.ts index 57e4372f50ba..316f33f868b6 100644 --- a/src/gateway/terminal/session-manager.test.ts +++ b/src/gateway/terminal/session-manager.test.ts @@ -10,7 +10,7 @@ import { } from "./session-manager.test-helpers.js"; const TERMINAL_EVENT_DATA = "terminal.data"; const TERMINAL_EVENT_EXIT = "terminal.exit"; -const OPERATOR_INTRO = composeTerminalIntroBanner(80); +const OPERATOR_INTRO = composeTerminalIntroBanner(); function deferred() { let resolve!: (value: T) => void; diff --git a/src/gateway/terminal/session-manager.ts b/src/gateway/terminal/session-manager.ts index 03d7b7c4359d..3ae482d920a2 100644 --- a/src/gateway/terminal/session-manager.ts +++ b/src/gateway/terminal/session-manager.ts @@ -269,7 +269,7 @@ export class TerminalSessionManager { this.sessions.set(session.id, session); if (request.owner.kind === "conn") { this.indexByConn(request.owner.connId, session.id); - session.output.push(composeTerminalIntroBanner(request.cols)); + session.output.push(composeTerminalIntroBanner()); } backend.onData((chunk) => {