// engine/spec-observability/tracker.ts — SpecUsageTracker (SPEC-158)
// Records spec access events fire-and-forget — zero latency impact on callers.
import { recordSpecAccess } from '../../storage/spec-observability-store.js';
// ---------------------------------------------------------------------------
// Spec ID extraction helpers
// ---------------------------------------------------------------------------
const SPEC_ID_PATTERN = /\bSPEC-\d+\b/gi;
/**
 * Extract all SPEC-NNN identifiers mentioned in a string.
 * Returns an empty array when none found.
 */
export function extractSpecIds(text) {
    const matches = text.match(SPEC_ID_PATTERN);
    if (!matches) {
        return [];
    }
    // Normalise to uppercase and deduplicate
    return [...new Set(matches.map((m) => m.toUpperCase()))];
}
/**
 * Extract an AC reference like "AC-3" or "AC3" from a string.
 * Returns the first match or undefined.
 */
export function extractAcRef(text) {
    const match = /\bAC[-\s]?(\d+)\b/i.exec(text);
    return match ? `AC-${match[1]}` : undefined;
}
// ---------------------------------------------------------------------------
// Public tracker API
// ---------------------------------------------------------------------------
/**
 * Record that `toolName` accessed `specId` (and optionally `acRef`).
 * Fire-and-forget — errors are suppressed to avoid disrupting the caller.
 */
export function trackSpecAccess(projectId, toolName, specId, acRef) {
    const event = {
        specId: specId.toUpperCase(),
        toolName,
        timestamp: new Date().toISOString(),
        ...(acRef !== undefined ? { acRef } : {}),
    };
    recordSpecAccess(projectId, event).catch((err) => {
        console.error('[Planu] spec-observability: failed to record event', err);
    });
}
/**
 * Inspect a tool call's args object and record usage events for any SPEC-NNN
 * identifiers found in string fields. Designed to be called from safe-handler
 * or tool wrappers without any performance impact.
 */
export function trackFromArgs(projectId, toolName, args) {
    if (args === null || typeof args !== 'object') {
        return;
    }
    const record = args;
    // Fast-path: if specId is directly provided
    if (typeof record.specId === 'string' && record.specId.length > 0) {
        const specId = record.specId.toUpperCase();
        const acRef = typeof record.acRef === 'string' ? record.acRef : undefined;
        trackSpecAccess(projectId, toolName, specId, acRef);
        return;
    }
    // Fallback: scan string values for SPEC-NNN patterns
    for (const value of Object.values(record)) {
        if (typeof value !== 'string') {
            continue;
        }
        const ids = extractSpecIds(value);
        for (const id of ids) {
            trackSpecAccess(projectId, toolName, id);
        }
        if (ids.length > 0) {
            return;
        } // Only scan until we find at least one match
    }
}
//# sourceMappingURL=tracker.js.map