// engine/detectors/agile-detector.ts — Agile methodology detection (SPEC-026b)
// Detects Scrum, Kanban, SAFe, Shape Up from repository signals.
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { glob } from 'glob';
// === Pattern matchers ===
// Scrum signals: sprint branches, story-points issue templates, sprint commit messages
const SCRUM_SIGNALS = [/sprint[/-]/i, /story[\s-]?point/i, /sprint\s+review/i, /sprint\s+\d+/i];
// SAFe signals: Program Increment milestones, PI planning
const SAFE_SIGNALS = [
    /PI\s+\d+/i,
    /Program\s+Increment/i,
    /pi[\s-]?planning/i,
    /agile[\s-]?release[\s-]?train/i,
];
// Shape Up signals: appetite sections, pitch documents, betting cycle
const SHAPE_UP_SIGNALS = [
    /appetite/i,
    /fat\s+marker/i,
    /rabbit\s+holes/i,
    /no-gos/i,
    /shaped\s+up/i,
    /betted\s+on/i,
];
// Kanban signals: wip limits, kanban labels, flow-based terms
const KANBAN_SIGNALS = [
    /kanban/i,
    /wip\s+limit/i,
    /class\s+of\s+service/i,
    /throughput/i,
    /lead\s+time/i,
];
// === Public API ===
/**
 * Detects agile methodology from repository signals.
 * Checks branch names, issue templates, milestone names, and commit messages.
 */
export async function detectAgile(projectPath) {
    const collectedSignals = [];
    // Check GITHUB_ISSUE_TEMPLATES for story-points (strong Scrum signal)
    const issueTemplateContent = await readIssueTemplates(projectPath);
    const hasStoryPoints = /story[\s-]?point/i.test(issueTemplateContent);
    if (hasStoryPoints) {
        collectedSignals.push('issue-template-story-points');
    }
    // Check any docs/pitch/ or PITCH.md (Shape Up signal)
    const hasPitch = await hasPitchDocuments(projectPath);
    if (hasPitch) {
        collectedSignals.push('pitch-document');
    }
    // Check config files for PI planning references (SAFe)
    const hasPI = await hasPIPlanningSignals(projectPath);
    if (hasPI) {
        collectedSignals.push('pi-planning');
    }
    // Check for kanban board config files
    const hasKanbanConfig = await hasKanbanConfiguration(projectPath);
    if (hasKanbanConfig) {
        collectedSignals.push('kanban-config');
    }
    // Determine methodology based on collected signals
    return inferMethodology(collectedSignals);
}
// === Internal helpers ===
async function readIssueTemplates(projectPath) {
    const contents = [];
    const patterns = [
        '.github/ISSUE_TEMPLATE/*.md',
        '.github/ISSUE_TEMPLATE/*.yml',
        '.github/ISSUE_TEMPLATE/*.yaml',
    ];
    for (const pattern of patterns) {
        try {
            const matches = await glob(pattern, { cwd: projectPath, nodir: true });
            for (const match of matches) {
                try {
                    const content = await readFile(join(projectPath, match), 'utf-8');
                    contents.push(content);
                }
                catch {
                    // ignore missing files
                }
            }
        }
        catch {
            // ignore glob errors
        }
    }
    return contents.join('\n');
}
async function hasPitchDocuments(projectPath) {
    const pitchPaths = ['PITCH.md', 'docs/pitch.md', 'docs/pitches/', 'shapeup/', 'shape-up/'];
    for (const p of pitchPaths) {
        try {
            await readFile(join(projectPath, p), 'utf-8');
            return true;
        }
        catch {
            // not found
        }
    }
    // Check for pitch glob
    try {
        const matches = await glob('**/PITCH*.md', { cwd: projectPath, nodir: true });
        if (matches.length > 0) {
            return true;
        }
    }
    catch {
        // ignore
    }
    return false;
}
async function hasPIPlanningSignals(projectPath) {
    // Look for milestone or project config files referencing PI
    const checkPaths = ['.github/milestones.json', 'docs/safe/', 'docs/pi-planning/'];
    for (const p of checkPaths) {
        try {
            const content = await readFile(join(projectPath, p), 'utf-8');
            if (SAFE_SIGNALS.some((r) => r.test(content))) {
                return true;
            }
        }
        catch {
            // not found
        }
    }
    return false;
}
async function hasKanbanConfiguration(projectPath) {
    const checkPaths = ['.github/KANBAN.md', 'docs/kanban.md', 'docs/workflow.md', '.kanban'];
    for (const p of checkPaths) {
        try {
            const content = await readFile(join(projectPath, p), 'utf-8');
            if (KANBAN_SIGNALS.some((r) => r.test(content))) {
                return true;
            }
        }
        catch {
            // not found
        }
    }
    return false;
}
function inferMethodology(signals) {
    if (signals.length === 0) {
        return { methodology: null, confidence: 'none', signals };
    }
    // SAFe is most specific — if PI planning found, it's probably SAFe
    if (signals.includes('pi-planning')) {
        return { methodology: 'safe', confidence: 'certain', signals };
    }
    // Shape Up is specific — pitches + appetite
    if (signals.includes('pitch-document')) {
        return { methodology: 'shape-up', confidence: 'probable', signals };
    }
    // Story points in issue templates → strong Scrum signal
    if (signals.includes('issue-template-story-points')) {
        return { methodology: 'scrum', confidence: 'probable', signals };
    }
    // Kanban config
    if (signals.includes('kanban-config')) {
        return { methodology: 'kanban', confidence: 'probable', signals };
    }
    return { methodology: 'unknown', confidence: 'none', signals };
}
// Export signal patterns for testing
export { SCRUM_SIGNALS, SAFE_SIGNALS, SHAPE_UP_SIGNALS, KANBAN_SIGNALS };
//# sourceMappingURL=agile-detector.js.map