/** * Minimal JSON-lines logger for the runner process. * * The runner logs to stdout so the provisioner (story 06) and the * integration tests can read a structured stream. The sink is injectable * so in-process tests can capture every emitted line and assert * credential-leak absence (spec §15): nothing in this module — and by * convention nothing passed to it — may ever contain a secret. Callers * log event names and safe fields only, never raw protocol payloads. */ export type LogSink = (line: string) => void; export interface Logger { info(event: string, fields?: Record): void; error(event: string, fields?: Record): void; } const stdoutSink: LogSink = (line) => { process.stdout.write(`${line}\n`); }; export function createLogger(sink: LogSink = stdoutSink): Logger { const emit = ( level: "info" | "error", event: string, fields?: Record, ) => { sink(JSON.stringify({ level, event, ...fields })); }; return { info: (event, fields) => emit("info", event, fields), error: (event, fields) => emit("error", event, fields), }; }