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: diff --git a/src/logger.ts b/src/logger.ts index 0eaef81..4b91ed3 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -12,9 +12,11 @@ interface ThrottleState { const throttles = new Map(); let silent = false; let _logClient: any = null; +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 { @@ -51,7 +53,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 +61,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);