mona-agent / apps /desktop /src /log.js
mo
feat: enterprise capability expansion — app control, browser control, background execution
fce80d1
Raw History Blame Contribute Delete
1.58 kB
// Structured logger with event emission for TUI consumption.
// Levels: debug < info < warn < error
// In headless mode, writes to stderr (keeps stdout clean for piping).
// In TUI mode, emits events consumed by the dashboard.
import { EventEmitter } from 'node:events';
const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
const COLORS = { debug: '\x1b[90m', info: '\x1b[36m', warn: '\x1b[33m', error: '\x1b[31m' };
const RESET = '\x1b[0m';
const ICONS = { debug: '·', info: '●', warn: '', error: '' };
class Logger extends EventEmitter {
#level = LEVELS.info;
#quiet = false;
setLevel(level) {
this.#level = LEVELS[level] ?? LEVELS.info;
}
/** Suppress console output (TUI mode — events only). */
quiet(on = true) {
this.#quiet = on;
}
#log(level, msg, meta) {
if (LEVELS[level] < this.#level) return;
const ts = new Date();
const entry = {
ts,
time: ts.toLocaleTimeString('en-GB', { hour12: false }),
level,
icon: ICONS[level],
msg,
meta,
};
this.emit('entry', entry);
if (!this.#quiet) {
const prefix = `${COLORS[level]}${ICONS[level]}${RESET}`;
const metaStr = meta ? ` ${COLORS.debug}${JSON.stringify(meta)}${RESET}` : '';
process.stderr.write(` ${entry.time} ${prefix} ${msg}${metaStr}\n`);
}
}
debug(msg, meta) { this.#log('debug', msg, meta); }
info(msg, meta) { this.#log('info', msg, meta); }
warn(msg, meta) { this.#log('warn', msg, meta); }
error(msg, meta) { this.#log('error', msg, meta); }
}
export const log = new Logger();