summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllen Hutchison <[email protected]>2025-08-05 16:11:21 -0700
committerGitHub <[email protected]>2025-08-05 23:11:21 +0000
commit2141b39c3d713a19f2dd8012a76c2ff8b7c30a5e (patch)
treeee04d073a117daefe131e1cccf36d9ff08b7aa87
parent268627469b384ba3fa8dfe2e05b5186248013070 (diff)
feat(cli): route non-interactive output to stderr (#5624)
-rw-r--r--packages/cli/src/nonInteractiveCli.test.ts1
-rw-r--r--packages/cli/src/nonInteractiveCli.ts36
-rw-r--r--packages/cli/src/ui/utils/ConsolePatcher.ts27
3 files changed, 41 insertions, 23 deletions
diff --git a/packages/cli/src/nonInteractiveCli.test.ts b/packages/cli/src/nonInteractiveCli.test.ts
index 938eb4e7..3e4ce037 100644
--- a/packages/cli/src/nonInteractiveCli.test.ts
+++ b/packages/cli/src/nonInteractiveCli.test.ts
@@ -70,6 +70,7 @@ describe('runNonInteractive', () => {
getIdeMode: vi.fn().mockReturnValue(false),
getFullContext: vi.fn().mockReturnValue(false),
getContentGeneratorConfig: vi.fn().mockReturnValue({}),
+ getDebugMode: vi.fn().mockReturnValue(false),
} as unknown as Config;
});
diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts
index 8e573134..8b056a28 100644
--- a/packages/cli/src/nonInteractiveCli.ts
+++ b/packages/cli/src/nonInteractiveCli.ts
@@ -17,28 +17,37 @@ import {
import { Content, Part, FunctionCall } from '@google/genai';
import { parseAndFormatApiError } from './ui/utils/errorParsing.js';
+import { ConsolePatcher } from './ui/utils/ConsolePatcher.js';
export async function runNonInteractive(
config: Config,
input: string,
prompt_id: string,
): Promise<void> {
- await config.initialize();
- // Handle EPIPE errors when the output is piped to a command that closes early.
- process.stdout.on('error', (err: NodeJS.ErrnoException) => {
- if (err.code === 'EPIPE') {
- // Exit gracefully if the pipe is closed.
- process.exit(0);
- }
+ const consolePatcher = new ConsolePatcher({
+ stderr: true,
+ debugMode: config.getDebugMode(),
});
- const geminiClient = config.getGeminiClient();
- const toolRegistry: ToolRegistry = await config.getToolRegistry();
-
- const abortController = new AbortController();
- let currentMessages: Content[] = [{ role: 'user', parts: [{ text: input }] }];
- let turnCount = 0;
try {
+ await config.initialize();
+ consolePatcher.patch();
+ // Handle EPIPE errors when the output is piped to a command that closes early.
+ process.stdout.on('error', (err: NodeJS.ErrnoException) => {
+ if (err.code === 'EPIPE') {
+ // Exit gracefully if the pipe is closed.
+ process.exit(0);
+ }
+ });
+
+ const geminiClient = config.getGeminiClient();
+ const toolRegistry: ToolRegistry = await config.getToolRegistry();
+
+ const abortController = new AbortController();
+ let currentMessages: Content[] = [
+ { role: 'user', parts: [{ text: input }] },
+ ];
+ let turnCount = 0;
while (true) {
turnCount++;
if (
@@ -133,6 +142,7 @@ export async function runNonInteractive(
);
process.exit(1);
} finally {
+ consolePatcher.cleanup();
if (isTelemetrySdkInitialized()) {
await shutdownTelemetry();
}
diff --git a/packages/cli/src/ui/utils/ConsolePatcher.ts b/packages/cli/src/ui/utils/ConsolePatcher.ts
index 10be3bc7..a429698d 100644
--- a/packages/cli/src/ui/utils/ConsolePatcher.ts
+++ b/packages/cli/src/ui/utils/ConsolePatcher.ts
@@ -8,8 +8,9 @@ import util from 'util';
import { ConsoleMessageItem } from '../types.js';
interface ConsolePatcherParams {
- onNewMessage: (message: Omit<ConsoleMessageItem, 'id'>) => void;
+ onNewMessage?: (message: Omit<ConsoleMessageItem, 'id'>) => void;
debugMode: boolean;
+ stderr?: boolean;
}
export class ConsolePatcher {
@@ -46,16 +47,22 @@ export class ConsolePatcher {
originalMethod: (...args: unknown[]) => void,
) =>
(...args: unknown[]) => {
- if (this.params.debugMode) {
- originalMethod.apply(console, args);
- }
+ if (this.params.stderr) {
+ if (type !== 'debug' || this.params.debugMode) {
+ this.originalConsoleError(this.formatArgs(args));
+ }
+ } else {
+ if (this.params.debugMode) {
+ originalMethod.apply(console, args);
+ }
- if (type !== 'debug' || this.params.debugMode) {
- this.params.onNewMessage({
- type,
- content: this.formatArgs(args),
- count: 1,
- });
+ if (type !== 'debug' || this.params.debugMode) {
+ this.params.onNewMessage?.({
+ type,
+ content: this.formatArgs(args),
+ count: 1,
+ });
+ }
}
};
}