import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { stringify, parse } from "yaml";
/** traits/ directory at the repo root — version controlled */
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const TRAITS_DIR = path.resolve(__dirname, "../../../traits");
/**
 * File-backed trait store. Each trait is a YAML file in traits/<name>.yaml
 * at the repo root. Version controlled — edits via the UI write back
 * to the same files so they can be committed.
 */
export class TraitStore {
    traits = new Map();
    constructor() {
        fs.mkdirSync(TRAITS_DIR, { recursive: true });
        this.loadAll();
    }
    traitFilePath(name) {
        const filePath = path.join(TRAITS_DIR, `${name}.yaml`);
        const resolved = path.resolve(filePath);
        if (!resolved.startsWith(path.resolve(TRAITS_DIR))) {
            throw new Error(`Invalid trait name: path traversal detected`);
        }
        return filePath;
    }
    loadAll() {
        let entries;
        try {
            entries = fs.readdirSync(TRAITS_DIR, { withFileTypes: true });
        }
        catch {
            return;
        }
        for (const entry of entries) {
            if (!entry.isFile() || !entry.name.endsWith(".yaml"))
                continue;
            const filePath = path.join(TRAITS_DIR, entry.name);
            try {
                const raw = fs.readFileSync(filePath, "utf-8");
                const data = parse(raw);
                if (data && typeof data === "object" && data.name) {
                    this.traits.set(data.name, {
                        name: data.name,
                        label: data.label ?? data.name,
                        description: data.description ?? "",
                        promptFragment: data.promptFragment ?? "",
                        createdAt: data.createdAt ?? 0,
                        updatedAt: data.updatedAt ?? 0,
                    });
                }
            }
            catch (err) {
                console.error(`[trait-store] Failed to load ${filePath}:`, err);
            }
        }
    }
    saveOne(trait) {
        const filePath = this.traitFilePath(trait.name);
        try {
            const content = stringify({
                name: trait.name,
                label: trait.label,
                description: trait.description,
                promptFragment: trait.promptFragment,
                createdAt: trait.createdAt,
                updatedAt: trait.updatedAt,
            }, { lineWidth: 0 });
            fs.writeFileSync(filePath, content, "utf-8");
        }
        catch (err) {
            console.error(`[trait-store] Failed to save ${filePath}:`, err);
        }
    }
    put(trait) {
        this.traits.set(trait.name, trait);
        this.saveOne(trait);
    }
    get(name) {
        return this.traits.get(name);
    }
    remove(name) {
        this.traits.delete(name);
        const filePath = this.traitFilePath(name);
        try {
            fs.unlinkSync(filePath);
        }
        catch { /* ignore */ }
    }
    /** Re-read all YAML files from disk, picking up external changes */
    reload() {
        this.traits.clear();
        this.loadAll();
    }
    getAll() {
        this.reload();
        return Array.from(this.traits.values());
    }
    update(name, updates) {
        const existing = this.traits.get(name);
        if (!existing)
            return false;
        const cleaned = {};
        for (const [k, v] of Object.entries(updates)) {
            if (v !== undefined)
                cleaned[k] = v;
        }
        Object.assign(existing, cleaned, { updatedAt: Date.now() });
        this.saveOne(existing);
        return true;
    }
}
//# sourceMappingURL=trait-store.js.map