"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectPreFailureAlerts = detectPreFailureAlerts;
exports.predictDecisionRegret = predictDecisionRegret;
exports.getDecisionWarning = getDecisionWarning;
exports.detectComplexityTraps = detectComplexityTraps;
exports.detectScopeCreep = detectScopeCreep;
exports.predictEnergyPatterns = predictEnergyPatterns;
exports.analyzeStackCompatibility = analyzeStackCompatibility;
exports.getAllPredictions = getAllPredictions;
exports.calculateFileRisk = calculateFileRisk;
exports.estimateFeatureTime = estimateFeatureTime;
const database_1 = require("../../06-memory/database/database");
// ─── Pre-Failure Detection ───────────────────────────────────────────────────
function detectPreFailureAlerts(project) {
    (0, database_1.initializeDatabase)();
    const db = (0, database_1.getDb)();
    const alerts = [];
    const repeatBugs = db.prepare(project
        ? "SELECT description, file_path, COUNT(*) as cnt FROM behavior_events WHERE event_type = 'bug_fix' AND project = ? GROUP BY description HAVING cnt > 1 ORDER BY cnt DESC LIMIT 10"
        : "SELECT description, file_path, COUNT(*) as cnt FROM behavior_events WHERE event_type = 'bug_fix' GROUP BY description HAVING cnt > 1 ORDER BY cnt DESC LIMIT 10").all(...(project ? [project] : []));
    for (const bug of repeatBugs) {
        const confidence = Math.min(0.95, 0.5 + bug.cnt * 0.1);
        alerts.push({
            type: 'repeat_mistake',
            severity: bug.cnt >= 3 ? 'critical' : 'warning',
            message: `Repeat mistake detected: "${bug.description.slice(0, 80)}" has occurred ${bug.cnt} times`,
            evidence: `File: ${bug.file_path} | Occurrences: ${bug.cnt}`,
            suggestion: `Add a pre-commit check or lint rule to prevent this pattern. Consider adding validation before ${bug.file_path}`,
            confidence,
            file: bug.file_path,
            historicalCount: bug.cnt,
        });
    }
    const errorProneFiles = db.prepare("SELECT file_path, COUNT(*) as bug_count FROM behavior_events WHERE event_type = 'bug_fix' GROUP BY file_path HAVING bug_count >= 2 ORDER BY bug_count DESC LIMIT 10").all();
    for (const f of errorProneFiles) {
        alerts.push({
            type: 'error_prone_file',
            severity: f.bug_count >= 4 ? 'critical' : 'warning',
            message: `File "${f.file_path}" has ${f.bug_count} recorded bugs — high risk of future issues`,
            evidence: `Bug count: ${f.bug_count} across all sessions`,
            suggestion: `Consider refactoring ${f.file_path} — files with 3+ bugs tend to accumulate more. Add comprehensive tests.`,
            confidence: Math.min(0.9, 0.4 + f.bug_count * 0.1),
            file: f.file_path,
            historicalCount: f.bug_count,
        });
    }
    const noTryCatchFiles = db.prepare("SELECT file_path, description FROM behavior_events WHERE event_type = 'bug_fix' AND description LIKE '%null%' OR description LIKE '%undefined%' GROUP BY file_path HAVING COUNT(*) >= 2").all();
    for (const f of noTryCatchFiles) {
        if (!alerts.some(a => a.file === f.file_path && a.type === 'pattern_risk')) {
            alerts.push({
                type: 'pattern_risk',
                severity: 'warning',
                message: `File "${f.file_path}" has null/undefined bugs — likely missing null checks`,
                evidence: `Pattern: null/undefined errors in same file`,
                suggestion: `Add optional chaining (?.) and nullish coalescing (??) to ${f.file_path}`,
                confidence: 0.7,
                file: f.file_path,
            });
        }
    }
    return alerts.sort((a, b) => b.confidence - a.confidence);
}
// ─── Decision Regret Prediction ──────────────────────────────────────────────
function predictDecisionRegret() {
    (0, database_1.initializeDatabase)();
    const db = (0, database_1.getDb)();
    const regrets = [];
    const techDecisions = db.prepare('SELECT technology, COUNT(*) as times, SUM(CASE WHEN was_right = 0 THEN 1 ELSE 0 END) as wrong_count, SUM(CASE WHEN was_right = 1 THEN 1 ELSE 0 END) as right_count FROM decisions GROUP BY technology HAVING times >= 1 ORDER BY times DESC').all();
    for (const tech of techDecisions) {
        const regretRate = tech.times > 0 ? tech.wrong_count / tech.times : 0;
        if (regretRate >= 0.5 && tech.times >= 2) {
            regrets.push({
                technology: tech.technology,
                timesChosen: tech.times,
                timesReverted: tech.wrong_count,
                regretRate: Math.round(regretRate * 100),
                avgTimeBeforeRevert: 0,
                warning: `You chose ${tech.technology} ${tech.times} times and it was wrong ${tech.wrong_count} times (${Math.round(regretRate * 100)}% regret rate). Consider alternatives before choosing again.`,
                confidence: Math.min(0.95, 0.5 + tech.times * 0.1),
            });
        }
    }
    const allTech = db.prepare('SELECT technology, was_right, created_at FROM decisions ORDER BY created_at').all();
    const techTimeline = new Map();
    for (const d of allTech) {
        if (!techTimeline.has(d.technology))
            techTimeline.set(d.technology, []);
        techTimeline.get(d.technology).push({
            wasRight: d.was_right === null ? null : d.was_right === 1,
            date: d.created_at,
        });
    }
    for (const [tech, timeline] of techTimeline) {
        const wrongStreak = timeline.filter(t => t.wasRight === false).length;
        if (wrongStreak >= 2) {
            const existing = regrets.find(r => r.technology === tech);
            if (existing) {
                existing.warning += ` Recent trend: ${wrongStreak} consecutive wrong decisions.`;
                existing.confidence = Math.min(0.98, existing.confidence + 0.1);
            }
            else {
                regrets.push({
                    technology: tech,
                    timesChosen: timeline.length,
                    timesReverted: wrongStreak,
                    regretRate: 100,
                    avgTimeBeforeRevert: 0,
                    warning: `Consecutive wrong decisions with ${tech}: ${wrongStreak} times in a row. Strongly consider alternatives.`,
                    confidence: 0.85,
                });
            }
        }
    }
    return regrets.sort((a, b) => b.confidence - a.confidence);
}
function getDecisionWarning(technology) {
    const regrets = predictDecisionRegret();
    const match = regrets.find(r => r.technology.toLowerCase() === technology.toLowerCase());
    if (match)
        return match.warning;
    return null;
}
// ─── Complexity Trap Detection ───────────────────────────────────────────────
function detectComplexityTraps(projectDir) {
    const db = (0, database_1.getDb)();
    const traps = [];
    const bigFiles = db.prepare("SELECT file_path, description, evidence FROM behavior_events WHERE event_type = 'bug_fix' GROUP BY file_path HAVING COUNT(*) >= 3").all();
    for (const f of bigFiles) {
        traps.push({
            type: 'high_cyclomatic',
            file: f.file_path,
            currentValue: 3,
            threshold: 2,
            message: `"${f.file_path}" has 3+ bugs — this file has high complexity. Consider splitting it.`,
            suggestion: `Break ${f.file_path} into smaller, focused modules. Files with 3+ bugs are 5x more likely to accumulate more.`,
            confidence: 0.8,
        });
    }
    const sessionFiles = db.prepare("SELECT files_touched FROM sessions WHERE files_touched != '[]' ORDER BY start_time DESC LIMIT 20").all();
    const fileFrequency = new Map();
    for (const s of sessionFiles) {
        try {
            const files = JSON.parse(s.files_touched);
            for (const f of files)
                fileFrequency.set(f, (fileFrequency.get(f) || 0) + 1);
        }
        catch { /* skip */ }
    }
    for (const [file, count] of fileFrequency) {
        if (count >= 5) {
            traps.push({
                type: 'function_growing',
                file,
                currentValue: count,
                threshold: 5,
                message: `"${file}" touched in ${count} sessions — likely needs refactoring or splitting`,
                suggestion: `This file keeps appearing across sessions. Consider if it's doing too much.`,
                confidence: Math.min(0.85, 0.4 + count * 0.05),
            });
        }
    }
    return traps.sort((a, b) => b.confidence - a.confidence);
}
// ─── Scope Creep Detector ────────────────────────────────────────────────────
function detectScopeCreep(project) {
    const db = (0, database_1.getDb)();
    const creeps = [];
    const recentSessions = db.prepare(project
        ? "SELECT key_decisions, files_touched, start_time, end_time FROM sessions WHERE project = ? AND end_time IS NOT NULL ORDER BY start_time DESC LIMIT 10"
        : "SELECT key_decisions, files_touched, start_time, end_time FROM sessions WHERE end_time IS NOT NULL ORDER BY start_time DESC LIMIT 10").all(...(project ? [project] : []));
    for (const s of recentSessions) {
        try {
            const decisions = JSON.parse(s.key_decisions || '[]');
            const files = JSON.parse(s.files_touched || '[]');
            if (decisions.length === 0 || files.length === 0)
                continue;
            const startMs = new Date(s.start_time).getTime();
            const endMs = new Date(s.end_time).getTime();
            const hours = (endMs - startMs) / (1000 * 60 * 60);
            if (hours <= 0)
                continue;
            const featureName = decisions[0]?.split(':')[0] || 'unknown';
            const estimatedFiles = Math.max(1, Math.ceil(hours * 0.5));
            const overrunRatio = files.length / estimatedFiles;
            if (overrunRatio > 1.5 && files.length > 3) {
                const predictedHours = files.length * 0.5;
                creeps.push({
                    feature: featureName,
                    filesTouched: files.length,
                    estimatedFiles,
                    overrunRatio: Math.round(overrunRatio * 10) / 10,
                    predictedCompletionHours: Math.round(predictedHours * 10) / 10,
                    actualHoursSoFar: Math.round(hours * 10) / 10,
                    message: `Scope creep detected: "${featureName}" touched ${files.length} files (expected ~${estimatedFiles}). ${Math.round(overrunRatio * 100)}% overrun.`,
                    confidence: Math.min(0.9, 0.5 + (overrunRatio - 1) * 0.2),
                });
            }
        }
        catch { /* skip parse errors */ }
    }
    return creeps.sort((a, b) => b.confidence - a.confidence);
}
// ─── Energy-Based Prediction ─────────────────────────────────────────────────
function predictEnergyPatterns() {
    const db = (0, database_1.getDb)();
    const predictions = [];
    const bugByHour = db.prepare("SELECT created_at FROM behavior_events WHERE event_type = 'bug_fix'").all();
    const hourCounts = new Map();
    for (const b of bugByHour) {
        try {
            const d = new Date(b.created_at);
            if (!isNaN(d.getTime())) {
                const hour = d.getHours();
                hourCounts.set(hour, (hourCounts.get(hour) || 0) + 1);
            }
        }
        catch { /* skip */ }
    }
    if (bugByHour.length >= 3) {
        const maxBugs = Math.max(...hourCounts.values());
        const avoidHours = [...hourCounts.entries()]
            .filter(([, count]) => count >= maxBugs * 0.7)
            .map(([hour]) => hour)
            .sort((a, b) => a - b);
        if (avoidHours.length > 0 && avoidHours.length <= 6) {
            const rangeStr = avoidHours.map(h => `${h}:00-${h + 1}:00`).join(', ');
            predictions.push({
                type: 'avoid_time',
                message: `Bug introduction peaks at ${rangeStr}. Avoid complex coding during these hours.`,
                avoidTime: rangeStr,
                errorRateIncrease: Math.round((maxBugs / (bugByHour.length || 1)) * 100),
                confidence: 0.75,
            });
        }
        const sortedHours = [...hourCounts.entries()].sort((a, b) => a[1] - b[1]);
        const safeHours = sortedHours.slice(0, 3).map(([h]) => h);
        if (safeHours.length > 0) {
            predictions.push({
                type: 'optimal_time',
                message: `Your safest coding hours are ${safeHours.map(h => `${h}:00`).join(', ')} — lowest bug introduction rate.`,
                bestTime: safeHours.map(h => `${h}:00-${h + 1}:00`).join(', '),
                confidence: 0.7,
            });
        }
    }
    const sessionDurations = db.prepare("SELECT start_time, end_time FROM sessions WHERE end_time IS NOT NULL ORDER BY start_time DESC LIMIT 30").all();
    let totalMinutes = 0;
    let longSessions = 0;
    for (const s of sessionDurations) {
        const start = new Date(s.start_time).getTime();
        const end = new Date(s.end_time).getTime();
        const mins = (end - start) / (1000 * 60);
        totalMinutes += mins;
        if (mins > 180)
            longSessions++;
    }
    if (longSessions >= 2) {
        predictions.push({
            type: 'break_needed',
            message: `You've had ${longSessions} sessions over 3 hours recently. Error rate increases 2x after 3 continuous hours of coding.`,
            hoursWorked: Math.round(totalMinutes / 60),
            confidence: 0.8,
        });
    }
    if (bugByHour.length >= 5) {
        const recentBugs = bugByHour.slice(0, 5);
        const now = new Date();
        const recentDates = recentBugs.map(b => new Date(b.created_at));
        const avgGap = recentDates.reduce((sum, d, i) => {
            if (i === 0)
                return 0;
            return sum + (recentDates[i - 1].getTime() - d.getTime());
        }, 0) / (recentDates.length - 1 || 1);
        const hoursSinceLast = (now.getTime() - recentDates[0].getTime()) / (1000 * 60 * 60);
        if (hoursSinceLast < 2 && recentBugs.length >= 3) {
            predictions.push({
                type: 'energy_low',
                message: `3+ bugs in quick succession — you may be tired. Take a break before continuing.`,
                confidence: 0.7,
            });
        }
    }
    return predictions;
}
// ─── Stack Compatibility Warning ─────────────────────────────────────────────
function analyzeStackCompatibility() {
    const db = (0, database_1.getDb)();
    const warnings = [];
    const techPerformance = db.prepare('SELECT technology, COUNT(*) as times, SUM(CASE WHEN was_right = 1 THEN 1 ELSE 0 END) as right_count, SUM(CASE WHEN was_right = 0 THEN 1 ELSE 0 END) as wrong_count FROM decisions GROUP BY technology HAVING times >= 2').all();
    for (const tech of techPerformance) {
        const successRate = tech.times > 0 ? tech.right_count / tech.times : 0;
        if (successRate < 0.4 && tech.times >= 2) {
            warnings.push({
                type: 'tool_ineffective',
                technology: tech.technology,
                message: `${tech.technology} works only ${Math.round(successRate * 100)}% of the time for you (${tech.right_count}/${tech.times}). Consider alternatives.`,
                evidence: `Decisions: ${tech.times} | Success: ${tech.right_count} | Failures: ${tech.wrong_count}`,
                confidence: Math.min(0.9, 0.5 + tech.times * 0.08),
            });
        }
    }
    const migrationPatterns = db.prepare("SELECT technology, reason, was_right, created_at FROM decisions WHERE technology LIKE '%→%' OR reason LIKE '%migrate%' OR reason LIKE '%switch%' ORDER BY created_at").all();
    const techReplacements = new Map();
    for (const m of migrationPatterns) {
        const match = m.reason.match(/(\w+)\s*(?:→|to|from)\s*(\w+)/i);
        if (match) {
            const key = `${match[1]}→${match[2]}`;
            const existing = techReplacements.get(key);
            if (existing)
                existing.count++;
            else
                techReplacements.set(key, { from: match[1], to: match[2], count: 1 });
        }
    }
    for (const [, data] of techReplacements) {
        if (data.count >= 2) {
            warnings.push({
                type: 'dependency_risk',
                technology: data.from,
                message: `You've migrated away from ${data.from} ${data.count} times. Consider if ${data.to} is truly better for your use case.`,
                alternative: data.to,
                evidence: `Migration count: ${data.count}`,
                confidence: 0.75,
            });
        }
    }
    const bugsByTech = db.prepare("SELECT technology, COUNT(*) as bug_count FROM behavior_events b JOIN decisions d ON b.project = d.project WHERE b.event_type = 'bug_fix' GROUP BY d.technology ORDER BY bug_count DESC LIMIT 5").all();
    for (const t of bugsByTech) {
        if (t.bug_count >= 3) {
            const existing = warnings.find(w => w.technology === t.technology);
            if (!existing) {
                warnings.push({
                    type: 'library_mismatch',
                    technology: t.technology,
                    message: `${t.technology} is associated with ${t.bug_count} bugs in your projects. This library may not suit your coding style.`,
                    evidence: `Bug association count: ${t.bug_count}`,
                    confidence: 0.65,
                });
            }
        }
    }
    return warnings.sort((a, b) => b.confidence - a.confidence);
}
// ─── Unified Predictions ─────────────────────────────────────────────────────
function getAllPredictions(project) {
    const predictions = [];
    const now = new Date().toISOString();
    const alerts = detectPreFailureAlerts(project);
    for (const a of alerts) {
        predictions.push({
            id: `pf_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'pre_failure',
            severity: a.severity,
            title: a.type === 'repeat_mistake' ? 'Repeat Mistake Warning' : a.type === 'error_prone_file' ? 'Error-Prone File' : 'Pattern Risk',
            message: a.message,
            confidence: a.confidence,
            actionable: true,
            suggestedAction: a.suggestion,
            createdAt: now,
            project,
        });
    }
    const regrets = predictDecisionRegret();
    for (const r of regrets) {
        predictions.push({
            id: `dr_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'decision_regret',
            severity: r.regretRate >= 75 ? 'critical' : 'warning',
            title: `Decision Regret: ${r.technology}`,
            message: r.warning,
            confidence: r.confidence,
            actionable: true,
            suggestedAction: `Before choosing ${r.technology} again, consider what went wrong ${r.timesReverted} times.`,
            createdAt: now,
            project,
        });
    }
    const complexity = detectComplexityTraps();
    for (const c of complexity) {
        predictions.push({
            id: `ct_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'complexity_trap',
            severity: 'warning',
            title: 'Complexity Trap',
            message: c.message,
            confidence: c.confidence,
            actionable: true,
            suggestedAction: c.suggestion,
            createdAt: now,
            project,
        });
    }
    const scope = detectScopeCreep(project);
    for (const s of scope) {
        predictions.push({
            id: `sc_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'scope_creep',
            severity: s.overrunRatio > 2 ? 'critical' : 'warning',
            title: `Scope Creep: ${s.feature}`,
            message: s.message,
            confidence: s.confidence,
            actionable: true,
            suggestedAction: `Consider completing the original scope before expanding. ${s.feature} expected ~${s.estimatedFiles} files but touched ${s.filesTouched}.`,
            createdAt: now,
            project,
        });
    }
    const energy = predictEnergyPatterns();
    for (const e of energy) {
        predictions.push({
            id: `en_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'energy',
            severity: e.type === 'energy_low' ? 'critical' : 'info',
            title: e.type === 'optimal_time' ? 'Optimal Work Time' : e.type === 'avoid_time' ? 'High-Risk Hours' : e.type === 'break_needed' ? 'Take a Break' : 'Low Energy Detected',
            message: e.message,
            confidence: e.confidence,
            actionable: true,
            suggestedAction: e.type === 'break_needed' ? 'Step away for 15-30 minutes. Your error rate will drop.' : e.type === 'avoid_time' ? 'Schedule complex tasks outside these hours.' : undefined,
            createdAt: now,
            project,
        });
    }
    const stack = analyzeStackCompatibility();
    for (const s of stack) {
        predictions.push({
            id: `sk_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
            type: 'stack',
            severity: s.confidence >= 0.8 ? 'warning' : 'info',
            title: `Stack Warning: ${s.technology}`,
            message: s.message,
            confidence: s.confidence,
            actionable: true,
            suggestedAction: s.alternative ? `Consider using ${s.alternative} instead.` : 'Review your approach with this technology.',
            createdAt: now,
            project,
        });
    }
    return predictions.sort((a, b) => {
        const severityOrder = { critical: 3, warning: 2, info: 1 };
        const sevDiff = (severityOrder[b.severity] || 0) - (severityOrder[a.severity] || 0);
        if (sevDiff !== 0)
            return sevDiff;
        return b.confidence - a.confidence;
    });
}
// ─── Risk Score ──────────────────────────────────────────────────────────────
function calculateFileRisk(file) {
    const db = (0, database_1.getDb)();
    const factors = [];
    let score = 0;
    const bugCount = db.prepare("SELECT COUNT(*) as cnt FROM behavior_events WHERE event_type = 'bug_fix' AND file_path = ?").get(file)?.cnt || 0;
    if (bugCount > 0) {
        const weight = Math.min(40, bugCount * 10);
        score += weight;
        factors.push({ name: 'bug_history', weight, reason: `${bugCount} bugs recorded in this file` });
    }
    const recurrenceCount = db.prepare("SELECT SUM(recurrence_count) as total FROM behavior_events WHERE event_type = 'bug_fix' AND file_path = ?").get(file)?.total || 0;
    if (recurrenceCount > 0) {
        const weight = Math.min(30, recurrenceCount * 15);
        score += weight;
        factors.push({ name: 'repeat_issues', weight, reason: `${recurrenceCount} recurring issues` });
    }
    const sessionCount = db.prepare("SELECT COUNT(DISTINCT id) as cnt FROM sessions WHERE files_touched LIKE ?").get(`%${file}%`)?.cnt || 0;
    if (sessionCount >= 3) {
        const weight = Math.min(20, sessionCount * 3);
        score += weight;
        factors.push({ name: 'high_touch', weight, reason: `Touched in ${sessionCount} sessions` });
    }
    const totalBugs = db.prepare("SELECT COUNT(*) as cnt FROM behavior_events WHERE event_type = 'bug_fix'").get()?.cnt || 1;
    if (bugCount / totalBugs > 0.1) {
        const weight = 15;
        score += weight;
        factors.push({ name: 'concentration', weight, reason: `${Math.round((bugCount / totalBugs) * 100)}% of all bugs are in this file` });
    }
    score = Math.min(100, score);
    return {
        file,
        score,
        factors,
        predictions: getAllPredictions().filter(p => p.message.includes(file)),
    };
}
// ─── Time Estimate ───────────────────────────────────────────────────────────
function estimateFeatureTime(feature) {
    const db = (0, database_1.getDb)();
    const similarSessions = db.prepare("SELECT key_decisions, files_touched, start_time, end_time FROM sessions WHERE key_decisions LIKE ? AND end_time IS NOT NULL").all(`%${feature}%`);
    const pastFeatures = db.prepare("SELECT key_decisions, files_touched, start_time, end_time FROM sessions WHERE end_time IS NOT NULL AND key_decisions != '[]' ORDER BY start_time DESC LIMIT 20").all();
    const durations = [];
    const fileRatios = [];
    const basedOn = [];
    for (const s of similarSessions) {
        const start = new Date(s.start_time).getTime();
        const end = new Date(s.end_time).getTime();
        const hours = (end - start) / (1000 * 60 * 60);
        if (hours > 0 && hours < 24) {
            durations.push(hours);
            try {
                const files = JSON.parse(s.files_touched);
                fileRatios.push(files.length / Math.max(1, hours));
            }
            catch { /* skip */ }
            basedOn.push(`Similar session: ${s.key_decisions.slice(0, 60)}`);
        }
    }
    if (durations.length === 0) {
        for (const s of pastFeatures) {
            const start = new Date(s.start_time).getTime();
            const end = new Date(s.end_time).getTime();
            const hours = (end - start) / (1000 * 60 * 60);
            if (hours > 0 && hours < 24) {
                durations.push(hours);
                try {
                    const files = JSON.parse(s.files_touched);
                    fileRatios.push(files.length / Math.max(1, hours));
                }
                catch { /* skip */ }
            }
        }
        basedOn.push(`Based on ${durations.length} past sessions (no exact match)`);
    }
    if (durations.length === 0) {
        return {
            feature,
            estimatedHours: 2,
            confidence: 0.2,
            basedOn: ['No historical data available — using default estimate'],
            similarPastFeatures: 0,
        };
    }
    const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
    const sortedDurations = [...durations].sort((a, b) => a - b);
    const median = sortedDurations[Math.floor(sortedDurations.length / 2)];
    const estimated = (avgDuration + median) / 2;
    const confidence = Math.min(0.9, 0.3 + durations.length * 0.1);
    return {
        feature,
        estimatedHours: Math.round(estimated * 10) / 10,
        confidence: Math.round(confidence * 100) / 100,
        basedOn,
        similarPastFeatures: durations.length,
    };
}
//# sourceMappingURL=predictive-intelligence.js.map