From 424e54b6c66a41951540082dc601495bf3f42c3b Mon Sep 17 00:00:00 2001 From: 4 Bytes Robby Date: Sat, 20 Jun 2026 00:50:11 +0200 Subject: [PATCH 1/3] fix: suppress console output in plugin mode, keep only startup message #172 --- src/logger.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index 0eaef81..42fc8ac 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -12,6 +12,7 @@ interface ThrottleState { const throttles = new Map(); let silent = false; let _logClient: any = null; +let _startupLogged = false; export function setLogClient(client: any): void { _logClient = client; @@ -51,7 +52,7 @@ export function log( const payload = data ? ` ${JSON.stringify(data)}` : ""; const line = `${prefix} ${msg}${payload}`; - // App.log output (plugin mode) — additional structured channel + // App.log output (plugin mode) — primary structured channel if (_logClient) { const appLevel = level === "warn" ? "warn" : level === "error" ? "error" : level === "debug" ? "debug" : "info"; _logClient.app?.log({ @@ -59,9 +60,18 @@ export function log( }).catch(() => {}); // Debug messages go ONLY to app.log — skip console if (level === "debug") return; + // In plugin mode, console output is ONLY valid for the initial startup "init" message. + // All other logging goes through app.log() to avoid breaking the terminal UI. + if (_startupLogged) return; + if (key === "init") { + _startupLogged = true; + // Fall through to console output for the startup message only + } else { + return; + } } - // Console output — preserved for user visibility (info/warn/error) + // Console output — startup message (plugin mode), or all messages (CLI / standalone mode) if (level === "error") console.error(line); else if (level === "warn") console.warn(line); else if (!silent) console.log(line); From dc6ef01152552d17d09f46a0c3dde0604ab2a522 Mon Sep 17 00:00:00 2001 From: 4 Bytes Robby Date: Sat, 20 Jun 2026 00:52:49 +0200 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20add=20console=20logging=20rule=20?= =?UTF-8?q?=E2=80=94=20app().log=20only,=20console=20for=20startup=20only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index 8cad0cb..6933edc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,7 @@ For local dev guidance, see `AGENTS.local.md` (gitignored, machine-specific). - License: Apache-2.0 - ESM, Bun-targeted, strict TypeScript - **Token budget enforced: every tool description measured, no redundant alias tools** +- **Console logging:** Plugins MUST use `_client?.app?.log()` for all logging in plugin mode — `console.log` / `console.warn` / `console.error` is ONLY permitted for the initial startup `"init"` message. Console output in plugin mode breaks the terminal UI. ## Architecture "One brain, three internal engines." Modular internally: From 8f443860a81d65f6b5dded056b625f3967a69278 Mon Sep 17 00:00:00 2001 From: 4 Bytes Robby Date: Tue, 23 Jun 2026 09:04:35 +0200 Subject: [PATCH 3/3] fix: reset _startupLogged gate when swapping log clients #172 --- src/logger.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/logger.ts b/src/logger.ts index 42fc8ac..4b91ed3 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -16,6 +16,7 @@ let _startupLogged = false; export function setLogClient(client: any): void { _logClient = client; + _startupLogged = false; // reset gate so startup message fires on the new client } function shouldLog(key: string, intervalMs: number = 60000): boolean {