agentic-qe
Version: 
Agentic Quality Engineering Fleet System - AI-driven quality management platform
123 lines • 4.41 kB
JavaScript
;
/**
 * Quality Trends Command
 * Show quality metrics trends over time
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.trends = void 0;
const Logger_1 = require("../../../utils/Logger");
var TrendDirection;
(function (TrendDirection) {
    TrendDirection["IMPROVING"] = "improving";
    TrendDirection["DECLINING"] = "declining";
    TrendDirection["STABLE"] = "stable";
})(TrendDirection || (TrendDirection = {}));
async function trends(options) {
    const logger = Logger_1.Logger.getInstance();
    const timeRange = options.timeRange || '30d';
    try {
        // Calculate time window
        const timeWindow = parseTimeRange(timeRange);
        const startTime = new Date(Date.now() - timeWindow);
        // Fetch metrics from database
        const metricsData = await options.database.all(`
      SELECT metric_name, metric_value, timestamp
      FROM metrics
      WHERE timestamp > ?
      ORDER BY metric_name, timestamp
    `, [startTime.toISOString()]);
        // Group by metric name
        const metricGroups = {};
        for (const row of metricsData) {
            if (!metricGroups[row.metric_name]) {
                metricGroups[row.metric_name] = [];
            }
            metricGroups[row.metric_name].push({
                timestamp: row.timestamp,
                value: row.metric_value
            });
        }
        // Calculate trends
        const metrics = [];
        const trendDirections = {};
        for (const [name, values] of Object.entries(metricGroups)) {
            const average = values.reduce((sum, point) => sum + point.value, 0) / values.length;
            const trend = calculateTrend(values);
            metrics.push({
                name,
                values,
                average: parseFloat(average.toFixed(2)),
                trend
            });
            trendDirections[name] = trend;
        }
        // Identify significant changes
        const significantChanges = identifySignificantChanges(metrics);
        logger.info(`Analyzed ${metrics.length} metrics over ${timeRange}`);
        return {
            success: true,
            metrics,
            timeRange,
            trends: trendDirections,
            significantChanges
        };
    }
    catch (error) {
        logger.error('Failed to analyze trends:', error);
        throw error;
    }
}
exports.trends = trends;
function parseTimeRange(range) {
    const value = parseInt(range);
    const unit = range.slice(-1);
    switch (unit) {
        case 'h': return value * 60 * 60 * 1000;
        case 'd': return value * 24 * 60 * 60 * 1000;
        case 'w': return value * 7 * 24 * 60 * 60 * 1000;
        default: return 30 * 24 * 60 * 60 * 1000; // Default 30 days
    }
}
function calculateTrend(values) {
    if (values.length < 2)
        return TrendDirection.STABLE;
    // Calculate linear regression slope
    const n = values.length;
    let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
    values.forEach((point, i) => {
        sumX += i;
        sumY += point.value;
        sumXY += i * point.value;
        sumX2 += i * i;
    });
    const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
    // Threshold for significance
    const avgValue = sumY / n;
    const threshold = avgValue * 0.05; // 5% change
    if (Math.abs(slope) < threshold)
        return TrendDirection.STABLE;
    return slope > 0 ? TrendDirection.IMPROVING : TrendDirection.DECLINING;
}
function identifySignificantChanges(metrics) {
    const changes = [];
    for (const metric of metrics) {
        if (metric.values.length < 2)
            continue;
        // Check for significant jumps
        for (let i = 1; i < metric.values.length; i++) {
            const prev = metric.values[i - 1].value;
            const current = metric.values[i].value;
            const change = ((current - prev) / prev) * 100;
            if (Math.abs(change) > 20) { // 20% change is significant
                changes.push({
                    metric: metric.name,
                    change: parseFloat(change.toFixed(2)),
                    significance: Math.min(Math.abs(change) / 100, 1),
                    timestamp: metric.values[i].timestamp
                });
            }
        }
    }
    return changes.sort((a, b) => b.significance - a.significance).slice(0, 10);
}
//# sourceMappingURL=trends.js.map