/**
 * Read-only provider for built-in (factory default) config shipped with Bobbit.
 *
 * At build time, `scripts/copy-defaults.mjs` copies `defaults/` →
 * `dist/server/defaults/`. This class reads those defaults at runtime so
 * they serve as the lowest-priority layer in the config cascade.
 *
 * All results are cached after first load. Call `reload()` to re-read.
 */
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { parse } from "yaml";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
import { normalizeGrantPolicy, validateModelString, validateThinkingLevel } from "./role-store.js";
export class BuiltinConfigProvider {
    builtinsDir;
    // Lazy caches — null means "not loaded yet"
    _roles = null;
    _tools = null;
    _toolGroupPolicies = null;
    constructor(builtinsDir) {
        // Default: dist/server/agent/ → ../defaults → dist/server/defaults/
        this.builtinsDir = builtinsDir ?? path.join(__dirname, "..", "defaults");
    }
    // ── Public getters ──────────────────────────────────────────
    getRoles() {
        if (!this._roles)
            this._roles = this.loadRoles();
        return this._roles;
    }
    /**
     * Workflows are project-scoped only; this method exists for shape compat
     * with the cascade and may be removed once `ServerStores` drops it.
     */
    getWorkflows() {
        return [];
    }
    getTools() {
        if (!this._tools)
            this._tools = this.loadTools();
        return this._tools;
    }
    getToolGroupPolicies() {
        if (!this._toolGroupPolicies)
            this._toolGroupPolicies = this.loadToolGroupPolicies();
        return this._toolGroupPolicies;
    }
    /** Clear all caches so the next getter call re-reads from disk. */
    reload() {
        this._roles = null;
        this._tools = null;
        this._toolGroupPolicies = null;
    }
    // ── Private loaders (mirror the existing store parsing logic) ─
    loadRoles() {
        const dir = path.join(this.builtinsDir, "roles");
        const roles = [];
        for (const entry of this.readYamlDir(dir)) {
            try {
                const data = parse(entry.content);
                if (!data?.name)
                    continue;
                let toolPolicies;
                if (data.toolPolicies && typeof data.toolPolicies === "object") {
                    toolPolicies = {};
                    for (const [k, v] of Object.entries(data.toolPolicies)) {
                        if (typeof v === "string")
                            toolPolicies[k] = normalizeGrantPolicy(v);
                    }
                    if (Object.keys(toolPolicies).length === 0)
                        toolPolicies = undefined;
                }
                roles.push({
                    name: data.name,
                    label: data.label ?? data.name,
                    promptTemplate: data.promptTemplate ?? "",
                    accessory: data.accessory ?? "none",
                    toolPolicies,
                    model: validateModelString(data.model),
                    thinkingLevel: validateThinkingLevel(data.thinkingLevel),
                    createdAt: data.createdAt ?? 0,
                    updatedAt: data.updatedAt ?? 0,
                });
            }
            catch (err) {
                console.error(`[builtin-config] Failed to parse role ${entry.file}:`, err);
            }
        }
        return roles;
    }
    loadTools() {
        const toolsDir = path.join(this.builtinsDir, "tools");
        const tools = [];
        const seen = new Set();
        let entries;
        try {
            entries = fs.readdirSync(toolsDir, { withFileTypes: true });
        }
        catch {
            return tools;
        }
        // First pass: grouped subdirectories (tools/<group>/*.yaml)
        for (const entry of entries) {
            if (!entry.isDirectory())
                continue;
            const groupPath = path.join(toolsDir, entry.name);
            try {
                const files = fs.readdirSync(groupPath, { withFileTypes: true });
                for (const file of files) {
                    if (!file.isFile() || !file.name.endsWith(".yaml"))
                        continue;
                    try {
                        const raw = fs.readFileSync(path.join(groupPath, file.name), "utf-8");
                        const data = parse(raw);
                        if (!data?.name || seen.has(data.name))
                            continue;
                        seen.add(data.name);
                        tools.push({
                            name: data.name,
                            description: data.description || "",
                            group: data.group || entry.name,
                            docs: data.docs,
                            detail_docs: data.detail_docs,
                            hasRenderer: !!data.renderer,
                            rendererFile: data.renderer,
                            grantPolicy: data.grantPolicy,
                            params: Array.isArray(data.params) ? data.params.filter((p) => typeof p === "string") : undefined,
                        });
                    }
                    catch (err) {
                        console.error(`[builtin-config] Failed to parse tool ${file.name}:`, err);
                    }
                }
            }
            catch { /* skip unreadable group dir */ }
        }
        // Second pass: flat files (tools/*.yaml)
        for (const entry of entries) {
            if (!entry.isFile() || !entry.name.endsWith(".yaml"))
                continue;
            try {
                const raw = fs.readFileSync(path.join(toolsDir, entry.name), "utf-8");
                const data = parse(raw);
                if (!data?.name || seen.has(data.name))
                    continue;
                seen.add(data.name);
                tools.push({
                    name: data.name,
                    description: data.description || "",
                    group: data.group || "Other",
                    docs: data.docs,
                    detail_docs: data.detail_docs,
                    hasRenderer: !!data.renderer,
                    rendererFile: data.renderer,
                    grantPolicy: data.grantPolicy,
                    params: Array.isArray(data.params) ? data.params.filter((p) => typeof p === "string") : undefined,
                });
            }
            catch (err) {
                console.error(`[builtin-config] Failed to parse tool ${entry.name}:`, err);
            }
        }
        return tools;
    }
    loadToolGroupPolicies() {
        const filePath = path.join(this.builtinsDir, "tool-group-policies.yaml");
        try {
            const raw = fs.readFileSync(filePath, "utf-8");
            const data = parse(raw);
            if (!data || typeof data !== "object")
                return {};
            const result = {};
            const validPolicies = new Set(["allow", "ask", "never", "always-ask", "ask-once", "never-ask", "always-allow"]);
            for (const [key, value] of Object.entries(data)) {
                if (typeof value === "string" && validPolicies.has(value)) {
                    result[key] = normalizeGrantPolicy(value);
                }
            }
            return result;
        }
        catch {
            return {};
        }
    }
    // ── Helpers ──────────────────────────────────────────────────
    /** Read all .yaml files from a flat directory. */
    readYamlDir(dir) {
        const results = [];
        try {
            const entries = fs.readdirSync(dir, { withFileTypes: true });
            for (const entry of entries) {
                if (!entry.isFile() || !entry.name.endsWith(".yaml"))
                    continue;
                try {
                    results.push({
                        file: entry.name,
                        content: fs.readFileSync(path.join(dir, entry.name), "utf-8"),
                    });
                }
                catch { /* skip unreadable files */ }
            }
        }
        catch { /* directory doesn't exist */ }
        return results;
    }
}
//# sourceMappingURL=builtin-config.js.map