RSS Git Download  Clone
Raw Blame History 1kB 36 lines
import { AsyncLocalStorage } from 'node:async_hooks';

// AsyncLocalStorage so the orchestrator's log() callback reaches the providers
// (and through them, sub-CLI stderr/stdout). Without this, the providers can only
// write to process.stderr, which is invisible to MCP clients that don't surface it.
//
// The store value is { log, buffer } per architect() invocation. subLog() is called
// by both providers with raw chunks; we line-buffer per context, then forward whole
// lines to ctx.log so MCP notifications stay one-line-per-event.
export const logStore = new AsyncLocalStorage();

export function subLog(chunk) {
    const ctx = logStore.getStore();
    if (!ctx) {
        // Outside an architect() run (e.g. someone calling callAnthropic directly).
        process.stderr.write(chunk);
        return;
    }
    ctx.buffer += chunk;
    let nl;
    while ((nl = ctx.buffer.indexOf('\n')) !== -1) {
        const line = ctx.buffer.slice(0, nl).replace(/\r$/, '');
        ctx.buffer = ctx.buffer.slice(nl + 1);
        if (line.length) ctx.log(line);
    }
}

export function subLogFlush() {
    const ctx = logStore.getStore();
    if (!ctx) return;
    if (ctx.buffer.length > 0) {
        ctx.log(ctx.buffer);
        ctx.buffer = '';
    }
}