import { HookRegistry } from "./hooks.js";
import { createFileAwarenessTracker } from "./file-awareness.js";
import { PromptRegistry } from "./prompts.js";
import { ToolRegistry } from "./tools.js";
function normalizeActiveSkills(activeSkills) {
    const seen = new Set();
    const normalized = [];
    for (const value of activeSkills ?? []) {
        const name = value.trim();
        if (name.length === 0 || seen.has(name)) {
            continue;
        }
        seen.add(name);
        normalized.push(name);
    }
    return normalized;
}
export class RunContext {
    messages = [];
    tools = new ToolRegistry();
    prompts = new PromptRegistry();
    hooks = new HookRegistry();
    session = new Map();
    mcpServers = [];
    activeSkills;
    fileAwareness;
    abortController = new AbortController();
    childRuns = new Set();
    #logger;
    #disposeHooks = [];
    #disposing;
    #disposed = false;
    constructor(options = {}) {
        this.activeSkills = normalizeActiveSkills(options.activeSkills);
        this.#logger = options.logger ?? console;
        this.fileAwareness =
            options.fileAwareness ?? createFileAwarenessTracker(options.cwd ?? process.cwd());
    }
    get logger() {
        return this.#logger;
    }
    registerDisposeHook(hook) {
        this.#disposeHooks.push(hook);
    }
    trackChildRun(childRun) {
        this.childRuns.add(childRun);
        void childRun.then(() => {
            this.childRuns.delete(childRun);
        }, () => {
            this.childRuns.delete(childRun);
        });
        return childRun;
    }
    getChildRunCount() {
        return this.childRuns.size;
    }
    async dispose() {
        if (this.#disposed) {
            return;
        }
        if (this.#disposing) {
            return this.#disposing;
        }
        this.#disposing = this.#disposeInternal();
        try {
            await this.#disposing;
            this.#disposed = true;
            this.#disposeHooks.length = 0;
            this.childRuns.clear();
        }
        finally {
            this.#disposing = undefined;
        }
    }
    async #disposeInternal() {
        if (!this.abortController.signal.aborted) {
            this.abortController.abort();
        }
        const errors = [];
        const failedHooks = [];
        for (let index = this.#disposeHooks.length - 1; index >= 0; index -= 1) {
            const hook = this.#disposeHooks[index];
            if (!hook) {
                continue;
            }
            try {
                await hook();
            }
            catch (error) {
                errors.push(error);
                failedHooks.unshift(hook);
                this.#logger.error("Dispose hook failed.", error);
            }
        }
        this.#disposeHooks.splice(0, this.#disposeHooks.length, ...failedHooks);
        if (errors.length > 0) {
            throw new AggregateError(errors, "RunContext disposal failed.");
        }
    }
}
export function createRunContext(options) {
    return new RunContext(options);
}
