Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
15 changes: 13 additions & 2 deletions src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ interface ThrottleState {
const throttles = new Map<string, ThrottleState>();
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 {
Expand Down Expand Up @@ -51,17 +53,26 @@ 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({
body: { service: key, level: appLevel, message: msg, extra: data },
}).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);
Expand Down
Loading