"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadStrategies = loadStrategies;
exports.getStrategyContent = getStrategyContent;
exports.getRegisteredScenes = getRegisteredScenes;
exports.getPhaseHints = getPhaseHints;
exports.getPlanTemplate = getPlanTemplate;
exports.getFinalReportContract = getFinalReportContract;
exports.getStrategyFilePath = getStrategyFilePath;
exports.invalidateStrategyCache = invalidateStrategyCache;
exports.loadPromptTemplate = loadPromptTemplate;
exports.loadSelectionTemplate = loadSelectionTemplate;
exports.renderTemplate = renderTemplate;
/**
 * Loads external prompt content from `backend/strategies/`:
 *
 * 1. **Scene strategies** (`*.strategy.md`): YAML frontmatter + Markdown body.
 *    Used by `sceneClassifier.ts` for matching and `claudeSystemPrompt.ts` for injection.
 *    Adding a new scene requires only a new `.strategy.md` file, no code changes.
 *
 * 2. **Prompt templates** (`*.template.md`): Markdown with optional `{{variable}}`
 *    placeholders, substituted at runtime by `renderTemplate()`.
 *    Used by `claudeSystemPrompt.ts` for role, methodology, output format,
 *    architecture guidance, and selection context sections.
 *    Adding/editing prompt content requires only template changes, no code changes.
 *
 * Both categories are cached on first load and cleared together via `invalidateStrategyCache()`.
 */
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
const STRATEGIES_DIR = path.resolve(__dirname, '../../strategies');
/** Tolerates leading `<!-- -->` blocks (e.g. SPDX/license headers) before the frontmatter. */
const FRONTMATTER_RE = /^(?:\s*<!--[\s\S]*?-->\s*)*---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
/** In dev mode, skip caching so .strategy.md / .template.md edits take effect without restart. */
const DEV_MODE = process.env.NODE_ENV !== 'production';
let cache = null;
function parseStrategyFile(filePath) {
    const raw = fs.readFileSync(filePath, 'utf-8');
    const match = raw.match(FRONTMATTER_RE);
    if (!match)
        return null;
    const frontmatter = yaml.load(match[1]);
    const content = match[2].trim();
    const compoundPatternStrings = frontmatter.compound_patterns || [];
    const compoundPatterns = compoundPatternStrings.map(p => new RegExp(p, 'i'));
    const rawHints = frontmatter.phase_hints || [];
    const phaseHints = rawHints.map(h => ({
        id: h.id || '',
        keywords: h.keywords || [],
        constraints: h.constraints || '',
        criticalTools: h.critical_tools || [],
        critical: h.critical ?? false,
    }));
    const rawPlanTemplate = frontmatter.plan_template;
    let planTemplate = null;
    if (rawPlanTemplate) {
        const aspects = rawPlanTemplate.mandatory_aspects || [];
        planTemplate = {
            mandatoryAspects: aspects.map(a => ({
                id: a.id || '',
                matchKeywords: a.match_keywords || [],
                suggestion: a.suggestion || '',
            })),
        };
    }
    const rawFinalReportContract = frontmatter.final_report_contract;
    let finalReportContract = null;
    if (rawFinalReportContract) {
        const requiredSections = rawFinalReportContract.required_sections || [];
        finalReportContract = {
            requiredSections: requiredSections
                .map(section => {
                const patterns = section.patterns || [];
                const patternGroups = Array.isArray(section.pattern_groups)
                    ? section.pattern_groups
                        .filter(group => Array.isArray(group))
                        .map(group => group.filter(item => typeof item === 'string'))
                        .filter(group => group.length > 0)
                    : [];
                return {
                    id: section.id || '',
                    label: section.label || section.id || '',
                    description: section.description || undefined,
                    patterns,
                    patternGroups,
                    required: section.required ?? true,
                };
            })
                .filter(section => section.id && section.label && (section.patterns.length > 0 || section.patternGroups.length > 0)),
        };
    }
    const rawStrategyKind = frontmatter.strategy_kind;
    const strategyKind = rawStrategyKind === 'contract_only'
        ? 'contract_only'
        : 'normal';
    return {
        scene: frontmatter.scene,
        strategyKind,
        priority: frontmatter.priority ?? 99,
        effort: frontmatter.effort ?? 'high',
        keywords: frontmatter.keywords || [],
        compoundPatterns,
        requiredCapabilities: frontmatter.required_capabilities || [],
        optionalCapabilities: frontmatter.optional_capabilities || [],
        phaseHints,
        planTemplate,
        finalReportContract,
        content,
        sourcePath: filePath,
    };
}
function loadStrategies() {
    if (cache && !DEV_MODE)
        return cache;
    cache = new Map();
    const files = fs.readdirSync(STRATEGIES_DIR)
        .filter(f => f.endsWith('.strategy.md'));
    for (const file of files) {
        const def = parseStrategyFile(path.join(STRATEGIES_DIR, file));
        if (def) {
            cache.set(def.scene, def);
        }
    }
    return cache;
}
function getStrategyContent(scene) {
    const def = loadStrategies().get(scene);
    return def?.strategyKind === 'contract_only' ? undefined : def?.content;
}
function getRegisteredScenes() {
    return Array.from(loadStrategies().values())
        .filter(def => def.strategyKind !== 'contract_only');
}
/** Get phase-level restatement hints for a scene. Returns [] if scene has no hints. */
function getPhaseHints(scene) {
    const def = loadStrategies().get(scene);
    if (def?.strategyKind === 'contract_only')
        return [];
    return def?.phaseHints || [];
}
/**
 * Get the plan template for a scene loaded from `plan_template:`
 * frontmatter. Returns `null` for unknown scenes and for scenes that
 * deliberately opted out (no `plan_template` block in their frontmatter).
 *
 * Phase 2.1 of v2.1 — strategies migrated to frontmatter take priority
 * over the legacy hardcoded `SCENE_PLAN_TEMPLATES` map; the legacy map
 * remains as a fallback in `scenePlanTemplates.ts` until every strategy
 * has migrated.
 */
function getPlanTemplate(scene) {
    const def = loadStrategies().get(scene);
    if (def?.strategyKind === 'contract_only')
        return null;
    return def?.planTemplate ?? null;
}
/**
 * Get the scene-owned final report completeness contract. Returns null for
 * scenes that have no declarative contract yet.
 */
function getFinalReportContract(scene) {
    return loadStrategies().get(scene)?.finalReportContract ?? null;
}
/**
 * Resolve the absolute path of the `*.strategy.md` file backing a scene.
 * Returns `undefined` for unknown scenes. Use this instead of `${scene}.strategy.md`
 * — file basenames may use hyphens (`touch-tracking.strategy.md`) where
 * the scene id uses underscores (`touch_tracking`).
 */
function getStrategyFilePath(scene) {
    return loadStrategies().get(scene)?.sourcePath;
}
/** Clear cached strategies and templates — useful for dev/test reloads. */
function invalidateStrategyCache() {
    cache = null;
    templateCache.clear();
}
// ---------------------------------------------------------------------------
// Prompt & selection context templates ({{variable}} substitution)
// ---------------------------------------------------------------------------
const templateCache = new Map();
/**
 * Load a prompt template from `backend/strategies/<name>.template.md`.
 * Templates use `{{variable}}` placeholders that callers substitute at runtime via `renderTemplate()`.
 * Static templates (no variables) can be used directly as-is.
 *
 * Results are cached in `templateCache` and cleared by `invalidateStrategyCache()`.
 */
function loadPromptTemplate(name) {
    if (templateCache.has(name) && !DEV_MODE)
        return templateCache.get(name);
    const filePath = path.join(STRATEGIES_DIR, `${name}.template.md`);
    if (!fs.existsSync(filePath))
        return undefined;
    const content = fs.readFileSync(filePath, 'utf-8').trim();
    templateCache.set(name, content);
    return content;
}
/**
 * Load a selection context template from `backend/strategies/selection-<kind>.template.md`.
 * Delegates to `loadPromptTemplate()` with the `selection-` prefix.
 */
function loadSelectionTemplate(kind) {
    return loadPromptTemplate(`selection-${kind}`);
}
/**
 * Substitute `{{key}}` placeholders in a template string with provided values.
 */
function renderTemplate(template, vars) {
    return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
        const val = vars[key];
        return val !== undefined ? String(val) : `{{${key}}}`;
    });
}
//# sourceMappingURL=strategyLoader.js.map