/**
 * Bulkhead — bound concurrent execution of an async operation.
 *
 * Sprint-468. Wrap a function so at most `maxConcurrent` invocations
 * are active at once; additional calls queue up to `maxQueued` before
 * rejecting with BulkheadFullError. Prevents a slow backend from
 * exhausting the agent's event loop or memory.
 *
 * Usage:
 *   const safeArchive = bulkhead(brain.archiveKnowledge.bind(brain), {
 *     name: "brain.archive",
 *     maxConcurrent: 5,
 *     maxQueued: 50,
 *   });
 */
export class BulkheadFullError extends Error {
    bulkheadName;
    constructor(bulkheadName, queueDepth) {
        super(`Bulkhead "${bulkheadName}" full — queue depth ${queueDepth} reached.`);
        this.name = "BulkheadFullError";
        this.bulkheadName = bulkheadName;
    }
}
export function bulkhead(fn, options) {
    const maxConcurrent = options.maxConcurrent ?? 5;
    const maxQueued = options.maxQueued ?? 50;
    let active = 0;
    const queue = [];
    const acquire = () => {
        if (active < maxConcurrent) {
            active += 1;
            return Promise.resolve();
        }
        if (queue.length >= maxQueued) {
            return Promise.reject(new BulkheadFullError(options.name, queue.length));
        }
        return new Promise((resolve) => {
            queue.push(() => {
                active += 1;
                resolve();
            });
        });
    };
    const release = () => {
        active -= 1;
        const next = queue.shift();
        if (next)
            next();
    };
    async function run(...args) {
        await acquire();
        try {
            return await fn(...args);
        }
        finally {
            release();
        }
    }
    const wrapper = run;
    Object.defineProperty(wrapper, "stats", {
        get: () => ({ active, queued: queue.length }),
    });
    return wrapper;
}
//# sourceMappingURL=bulkhead.js.map