fix(cli): route plugin logs to stderr during --json output

This commit is contained in:
Charles Dusek
2026-03-22 14:21:56 -05:00
committed by Peter Steinberger
parent 46a455d9e3
commit 0e1da034c2
4 changed files with 115 additions and 8 deletions

View File

@@ -1,5 +1,6 @@
import { Command } from "commander";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { loggingState } from "../../logging/state.js";
import { setCommandJsonMode } from "./json-mode.js";
const setVerboseMock = vi.fn();
@@ -58,6 +59,7 @@ let originalProcessArgv: string[];
let originalProcessTitle: string;
let originalNodeNoWarnings: string | undefined;
let originalHideBanner: string | undefined;
let originalForceStderr: boolean;
beforeAll(async () => {
({ registerPreActionHooks } = await import("./preaction.js"));
@@ -76,6 +78,8 @@ beforeEach(() => {
originalProcessTitle = process.title;
originalNodeNoWarnings = process.env.NODE_NO_WARNINGS;
originalHideBanner = process.env.OPENCLAW_HIDE_BANNER;
originalForceStderr = loggingState.forceConsoleToStderr;
loggingState.forceConsoleToStderr = false;
delete process.env.NODE_NO_WARNINGS;
delete process.env.OPENCLAW_HIDE_BANNER;
});
@@ -83,6 +87,7 @@ beforeEach(() => {
afterEach(() => {
process.argv = originalProcessArgv;
process.title = originalProcessTitle;
loggingState.forceConsoleToStderr = originalForceStderr;
if (originalNodeNoWarnings === undefined) {
delete process.env.NODE_NO_WARNINGS;
} else {
@@ -340,6 +345,39 @@ describe("registerPreActionHooks", () => {
expect(ensureConfigReadyMock).not.toHaveBeenCalled();
});
it("routes logs to stderr during plugin loading in --json mode and restores after", async () => {
let stderrDuringPluginLoad = false;
ensurePluginRegistryLoadedMock.mockImplementation(() => {
stderrDuringPluginLoad = loggingState.forceConsoleToStderr;
});
await runPreAction({
parseArgv: ["agents"],
processArgv: ["node", "openclaw", "agents", "--json"],
});
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalled();
expect(stderrDuringPluginLoad).toBe(true);
// Flag must be restored after plugin loading completes
expect(loggingState.forceConsoleToStderr).toBe(false);
});
it("does not route logs to stderr during plugin loading without --json", async () => {
let stderrDuringPluginLoad = false;
ensurePluginRegistryLoadedMock.mockImplementation(() => {
stderrDuringPluginLoad = loggingState.forceConsoleToStderr;
});
await runPreAction({
parseArgv: ["agents"],
processArgv: ["node", "openclaw", "agents"],
});
expect(ensurePluginRegistryLoadedMock).toHaveBeenCalled();
expect(stderrDuringPluginLoad).toBe(false);
expect(loggingState.forceConsoleToStderr).toBe(false);
});
beforeAll(() => {
program = buildProgram();
const hooks = (