Skip to content

Commit 3b14c8c

Browse files
committed
fix: intercept plugin console output to prevent TUI corruption
Plugins and their dependencies using console.log/warn/error write directly to stdout, corrupting the TUI display. The logLevel config only controls OpenCode's own slog-based logging. This intercepts global console before loading plugins and routes all output through the structured Log system (service: plugin:console), which respects the configured logLevel. Fixes #19108
1 parent 4167e25 commit 3b14c8c

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

packages/opencode/src/plugin/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ import { makeRunPromise } from "@/effect/run-service"
1919
export namespace Plugin {
2020
const log = Log.create({ service: "plugin" })
2121

22+
// Intercept global console to prevent plugins from corrupting TUI output.
23+
// Plugin console.log/warn/error calls are routed through the structured
24+
// Log system, respecting the configured logLevel.
25+
const pluginConsole = Log.create({ service: "plugin:console" })
26+
27+
function interceptConsole() {
28+
const format = (...args: unknown[]) =>
29+
args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" ")
30+
console.log = (...args: unknown[]) => pluginConsole.info(format(...args))
31+
console.info = (...args: unknown[]) => pluginConsole.info(format(...args))
32+
console.warn = (...args: unknown[]) => pluginConsole.warn(format(...args))
33+
console.error = (...args: unknown[]) => pluginConsole.error(format(...args))
34+
console.debug = (...args: unknown[]) => pluginConsole.debug(format(...args))
35+
}
36+
2237
type State = {
2338
hooks: Hooks[]
2439
}
@@ -80,6 +95,9 @@ export namespace Plugin {
8095
$: Bun.$,
8196
}
8297

98+
// Intercept console before loading any plugins to prevent TUI corruption
99+
interceptConsole()
100+
83101
for (const plugin of INTERNAL_PLUGINS) {
84102
log.info("loading internal plugin", { name: plugin.name })
85103
const init = await plugin(input).catch((err) => {

0 commit comments

Comments
 (0)