From 2e466bd4cb13f4ef5d4d39dc0019871a9a1a519f Mon Sep 17 00:00:00 2001 From: Cynthia Long Date: Mon, 16 Mar 2026 23:36:20 +0000 Subject: [PATCH] fix(cli): conditionally suppress console output in headless and non-interactive modes --- packages/cli/src/gemini.tsx | 2 +- packages/cli/src/nonInteractiveCli.ts | 4 +++- .../cli/src/ui/utils/ConsolePatcher.test.ts | 20 +++++++++++++++++++ packages/cli/src/ui/utils/ConsolePatcher.ts | 6 +++++- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/gemini.tsx b/packages/cli/src/gemini.tsx index da1377254a..971e21d99b 100644 --- a/packages/cli/src/gemini.tsx +++ b/packages/cli/src/gemini.tsx @@ -272,7 +272,7 @@ export async function main() { const isDebugMode = cliConfig.isDebugMode(argv); const consolePatcher = new ConsolePatcher({ stderr: true, - suppressConsoleOutput: isHeadlessMode() ? true : false, + suppressConsoleOutput: isHeadlessMode() && !isDebugMode, debugMode: isDebugMode, onNewMessage: (msg) => { coreEvents.emitConsoleLog(msg.type, msg.content); diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts index 4c53913fdc..592b73e16d 100644 --- a/packages/cli/src/nonInteractiveCli.ts +++ b/packages/cli/src/nonInteractiveCli.ts @@ -27,6 +27,7 @@ import { CoreEvent, createWorkingStdio, recordToolCallInteractions, + isHeadlessMode, ToolErrorType, Scheduler, ROOT_SCHEDULER_ID, @@ -63,9 +64,10 @@ export async function runNonInteractive({ resumedSessionData, }: RunNonInteractiveParams): Promise { return promptIdContext.run(prompt_id, async () => { + const suppressConsoleOutput = isHeadlessMode() && !config.getDebugMode(); const consolePatcher = new ConsolePatcher({ stderr: true, - suppressConsoleOutput: true, + suppressConsoleOutput, debugMode: config.getDebugMode(), onNewMessage: (msg) => { coreEvents.emitConsoleLog(msg.type, msg.content); diff --git a/packages/cli/src/ui/utils/ConsolePatcher.test.ts b/packages/cli/src/ui/utils/ConsolePatcher.test.ts index 152c3eaf5b..2c5c0b6601 100644 --- a/packages/cli/src/ui/utils/ConsolePatcher.test.ts +++ b/packages/cli/src/ui/utils/ConsolePatcher.test.ts @@ -43,6 +43,26 @@ describe('ConsolePatcher', () => { console.error = originalError; }); + it('should NOT suppress console.error even when suppressConsoleOutput is true', () => { + const originalError = console.error; + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + patcher = new ConsolePatcher({ + debugMode: false, + suppressConsoleOutput: true, + stderr: true, + }); + patcher.patch(); + + console.error('test error'); + + expect(errorSpy).toHaveBeenCalled(); + + patcher.cleanup(); + errorSpy.mockRestore(); + console.error = originalError; + }); + it('should NOT suppress output when suppressConsoleOutput is true but debugMode is true', () => { const originalError = console.error; const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); diff --git a/packages/cli/src/ui/utils/ConsolePatcher.ts b/packages/cli/src/ui/utils/ConsolePatcher.ts index 2da3b4e612..f1aa83b8e8 100644 --- a/packages/cli/src/ui/utils/ConsolePatcher.ts +++ b/packages/cli/src/ui/utils/ConsolePatcher.ts @@ -50,7 +50,11 @@ export class ConsolePatcher { private patchConsoleMethod = (type: 'log' | 'warn' | 'error' | 'debug' | 'info') => (...args: unknown[]) => { - if (this.params.suppressConsoleOutput && !this.params.debugMode) { + if ( + this.params.suppressConsoleOutput && + !this.params.debugMode && + type !== 'error' + ) { return; }