/**
 * Three-layer config resolution engine: builtin → server → project.
 *
 * Merges config items from embedded builtins, the server-level (default
 * project's config stores), and an optional project-level layer. Each
 * returned item carries an `origin` tag and an optional `overrides` field
 * indicating which lower layer it shadows.
 */
export class ConfigCascade {
    builtins;
    serverStores;
    projectContextManager;
    constructor(builtins, serverStores, projectContextManager) {
        this.builtins = builtins;
        this.serverStores = serverStores;
        this.projectContextManager = projectContextManager;
    }
    // ── Roles ────────────────────────────────────────────────────
    resolveRoles(projectId) {
        return this.resolve(this.builtins.getRoles(), r => r.name, projectId, this.serverStores.getRoles(), ctx => ctx.roleStore.getAllLocal());
    }
    // ── Workflows ────────────────────────────────────────────────
    resolveWorkflows(projectId) {
        // Workflows are project-scoped only — they live inline in each
        // project's project.yaml::workflows block. There is no builtin or
        // server-scope layer. Without a projectId, the cascade returns [].
        // Hidden workflows (e.g. test-only fixtures injected via project
        // config) are filtered out for API/UI surfaces.
        if (!projectId)
            return [];
        const ctx = this.projectContextManager.getOrCreate(projectId);
        if (!ctx)
            return [];
        return ctx.workflowStore.getAllLocal()
            .filter(w => !w.hidden)
            .map(item => ({ item, origin: "project" }));
    }
    // ── Tools ────────────────────────────────────────────────────
    resolveTools(projectId) {
        return this.resolve(this.builtins.getTools(), t => t.name, projectId, this.serverStores.getTools(), ctx => ctx.toolManager.getLocalTools());
    }
    // ── Tool Group Policies ──────────────────────────────────────
    resolveToolGroupPolicies(projectId) {
        const merged = new Map();
        // Layer 1: builtins
        for (const [group, policy] of Object.entries(this.builtins.getToolGroupPolicies())) {
            merged.set(group, { policy, origin: "builtin" });
        }
        // Layer 2: server-level (explicit server stores)
        for (const [group, policy] of Object.entries(this.serverStores.getToolGroupPolicies())) {
            const existing = merged.get(group);
            merged.set(group, {
                policy,
                origin: "server",
                overrides: existing?.origin,
            });
        }
        // Layer 3: project-level (when a projectId is specified).
        // Without projectId, only builtins + server stores are used (system scope).
        if (projectId) {
            const projectCtx = this.projectContextManager.getOrCreate(projectId);
            if (projectCtx) {
                for (const [group, policy] of Object.entries(projectCtx.toolGroupPolicyStore.getAll())) {
                    const existing = merged.get(group);
                    merged.set(group, {
                        policy,
                        origin: "project",
                        overrides: existing?.origin,
                    });
                }
            }
        }
        return Object.fromEntries(merged);
    }
    // ── Generic resolution helper ────────────────────────────────
    /**
     * Merge three layers of config items by a unique key.
     *
     * 1. Builtins (origin "builtin")
     * 2. Server-level = standalone server stores (origin "server")
     * 3. Project-level = specified project's store, if a projectId was given (origin "project")
     *
     * Later layers shadow earlier ones. The `overrides` field records what was shadowed.
     */
    resolve(builtinItems, keyFn, projectId, serverItems, getProjectItems) {
        const merged = new Map();
        // Layer 1: builtins
        for (const item of builtinItems) {
            merged.set(keyFn(item), { item, origin: "builtin" });
        }
        // Layer 2: server-level (explicit server stores)
        for (const item of serverItems) {
            const key = keyFn(item);
            const existing = merged.get(key);
            merged.set(key, {
                item,
                origin: "server",
                overrides: existing?.origin,
            });
        }
        // Layer 3: project-level (when a projectId is specified).
        // Without projectId, only builtins + server stores are used (system scope).
        if (projectId) {
            const projectCtx = this.projectContextManager.getOrCreate(projectId);
            if (projectCtx) {
                for (const item of getProjectItems(projectCtx)) {
                    const key = keyFn(item);
                    const existing = merged.get(key);
                    merged.set(key, {
                        item,
                        origin: "project",
                        overrides: existing?.origin,
                    });
                }
            }
        }
        return [...merged.values()];
    }
}
//# sourceMappingURL=config-cascade.js.map