/**
 * Bootstrap File Injection
 *
 * OpenClaw-inspired workspace context injection at session start.
 * Automatically loads BOOTSTRAP.md, AGENTS.md, SOUL.md, etc.
 * from .codebuddy/ (project) or ~/.codebuddy/ (global).
 *
 * Project files override global files for the same name.
 */
import * as fs from 'fs/promises';
import * as path from 'path';
import { homedir } from 'os';
import { logger } from '../utils/logger.js';
// ============================================================================
// Defaults
// ============================================================================
const DEFAULT_BOOTSTRAP_FILES = [
    'BOOTSTRAP.md',
    'AGENTS.md',
    'SOUL.md',
    'TOOLS.md',
    'IDENTITY.md',
    'USER.md',
    'HEARTBEAT.md',
];
const DEFAULT_CONFIG = {
    maxChars: 20000,
    fileNames: DEFAULT_BOOTSTRAP_FILES,
    projectDir: '.codebuddy',
    globalDir: path.join(homedir(), '.codebuddy'),
};
// ============================================================================
// Bootstrap Loader
// ============================================================================
export class BootstrapLoader {
    config;
    constructor(config = {}) {
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    /**
     * Load bootstrap files from project and global directories.
     * Project files take priority over global files for the same name.
     */
    async load(cwd) {
        const sources = [];
        const sections = [];
        let totalChars = 0;
        let truncated = false;
        for (const fileName of this.config.fileNames) {
            if (totalChars >= this.config.maxChars) {
                truncated = true;
                break;
            }
            const content = await this.loadFile(fileName, cwd);
            if (!content)
                continue;
            // Validate content safety
            if (this.containsDangerousPatterns(content.text)) {
                logger.warn(`Skipping bootstrap file ${content.source}: contains dangerous patterns`);
                continue;
            }
            const remaining = this.config.maxChars - totalChars;
            let text = content.text;
            if (text.length > remaining) {
                text = text.slice(0, remaining) + '\n\n... (truncated)';
                truncated = true;
            }
            sections.push(`## ${fileName}\n\n${text}`);
            sources.push(content.source);
            totalChars += text.length;
        }
        const combinedContent = sections.join('\n\n---\n\n');
        return {
            content: combinedContent,
            sources,
            tokenCount: totalChars,
            truncated,
        };
    }
    /**
     * Load a single bootstrap file, checking project dir first, then global.
     */
    async loadFile(fileName, cwd) {
        // Project-level (overrides global)
        const projectPath = path.join(cwd, this.config.projectDir, fileName);
        const projectContent = await this.readFileSafe(projectPath);
        if (projectContent) {
            return { text: projectContent, source: projectPath };
        }
        // Global-level
        const globalPath = path.join(this.config.globalDir, fileName);
        const globalContent = await this.readFileSafe(globalPath);
        if (globalContent) {
            return { text: globalContent, source: globalPath };
        }
        return null;
    }
    async readFileSafe(filePath) {
        try {
            const content = await fs.readFile(filePath, 'utf-8');
            return content.trim() || null;
        }
        catch {
            return null;
        }
    }
    /**
     * Basic security validation for bootstrap content.
     * Rejects files with common dangerous patterns.
     */
    containsDangerousPatterns(content) {
        const patterns = [
            /\beval\s*\(/,
            /\bnew\s+Function\s*\(/,
            /\brequire\s*\(\s*['"]child_process['"]\s*\)/,
            /\bexec(?:Sync)?\s*\(/,
            /\bspawn(?:Sync)?\s*\(/,
            /<script\b/i,
        ];
        return patterns.some(p => p.test(content));
    }
}
//# sourceMappingURL=bootstrap-loader.js.map