From 8c6f468d933506326f268ddff4246147fc0b84b3 Mon Sep 17 00:00:00 2001 From: James Foster Date: Thu, 27 Aug 2026 11:26:54 -0700 Subject: [PATCH] Ask the client library not to narrate every login Each GciTsLogin wrote a line to the process's real stdout -- gcits login: session 0xb4b518000 lgc 0xb4b518008 rpc gem processId 84970 -- with a matching one at logout, from inside the C library. In the extension host that is only noise in a log, but the GemDB Shell's stdout IS the user's terminal, so it landed between the banner and the first prompt; `gemdb -c` output that a script pipes somewhere is the same hazard. GciTsLogin's loginFlags argument was passing 0. It now passes GCI_LOGIN_QUIET (0x10, from the engine's include/gci.ht). The constant is declared in session.ts rather than gci/gciConstants.ts because that directory is vendored from Jasper byte-for-byte and carries no login flags at all. One call site, and the flag turns out to cover the session's whole lifecycle: the logout line goes too. repl.test.ts asserts the shell's pty transcript contains no 'gcits', which is the one place the noise is visible to a user rather than to a log. Confirmed it fails without the flag, printing the two lines above. The whole integration run went from dozens of these lines to zero. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 9 +++++++++ src/__integration__/repl.test.ts | 5 +++++ src/session.ts | 19 ++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68b1ae3..01dd900 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- **The GemDB Shell no longer prints the database client's own chatter.** + Opening a shell wrote a line like + `gcits login: session 0x… lgc 0x… rpc gem processId 4726` onto your terminal + between the banner and the first prompt, with a matching one on exit — the + client library narrating itself. Every session GemDB opens now asks it not + to. + ## [1.2.0] - 2026-08-27 A notebook is a unit of work again: each one gets its own database session, and diff --git a/src/__integration__/repl.test.ts b/src/__integration__/repl.test.ts index 034e3c2..073c59d 100644 --- a/src/__integration__/repl.test.ts +++ b/src/__integration__/repl.test.ts @@ -162,6 +162,11 @@ send "exit()\\r" expect(ran.transcript).toContain('42'); expect(ran.transcript).toContain('marco polo'); expect(ran.transcript).toContain('KeyboardInterrupt'); + // The client library narrates every login and logout on stdout unless the + // session asks it not to (GCI_LOGIN_QUIET, session.ts). This is the one + // place that shows: the shell's stdout is the user's terminal, so the + // chatter would land between the banner and the first prompt. + expect(ran.transcript).not.toContain('gcits'); expect(ran.code).toBe(0); expect(isRunning()).toBe(true); // the shell brought the stone up itself }); diff --git a/src/session.ts b/src/session.ts index b495a1e..663ce95 100644 --- a/src/session.ts +++ b/src/session.ts @@ -48,6 +48,23 @@ export class SessionLimitError extends SessionError {} */ const SESSION_LIMIT_ERRORS = new Set([4039, 4041, 4050]); +/** + * `GCI_LOGIN_QUIET` — stop the client library narrating each login on stdout. + * + * Without it every login writes a line like + * `gcits login: session 0x… lgc 0x… rpc gem processId 4726` (and a matching + * one at logout) to the process's real stdout, from inside the C library. In + * the extension host that is merely noise in the log; in a GemDB Shell it is + * printed straight onto the user's terminal, and in `gemdb -c` it lands in + * output a script may be piping somewhere. + * + * Defined here rather than in `gci/gciConstants.ts` because that directory is + * vendored from Jasper byte-for-byte and carries no login flags at all. The + * value is from the engine's own `include/gci.ht` (`GCI_LOGIN_QUIET = 0x10`, + * in the flag enum `GciTsLogin`'s `loginFlags` takes). + */ +const GCI_LOGIN_QUIET = 0x10; + /** What kind of user interface a session belongs to. */ export type SessionKind = 'notebook' | 'shell' | 'extension'; @@ -400,7 +417,7 @@ export class GciSession { gemNrs(), DB_USER, DB_PASSWORD, - 0, + GCI_LOGIN_QUIET, 0, ); if (!result.session) {