/**
 * CodexRolloutParser — pure parser for Codex CLI persisted "rollout" files.
 *
 * Codex writes one rollout JSONL per session at
 * `$CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl`. Unlike the
 * streaming `--json` exec vocabulary (`turn.completed` etc., handled by
 * `openai-codex/observability/eventNormalizer.ts`), the PERSISTED rollout
 * uses a different shape — empirically (Codex CLI 0.133.0, 2026-05-23):
 *
 *   {"type":"session_meta","payload":{"id":"<uuid>","timestamp":"...","cwd":"...","model_provider":"openai",...}}
 *   {"type":"turn_context","payload":{"model":"gpt-5.2","cwd":"...",...}}
 *   {"type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{...},"last_token_usage":{...}},"rate_limits":{...}}}
 *
 * `total_token_usage` is CUMULATIVE for the session, so the LAST token_count
 * event holds the session total — we take that rather than summing per-turn
 * `last_token_usage` (which would double-count re-sent cached context).
 *
 * This module is intentionally pure (no I/O) so it is trivially unit-testable
 * against a captured rollout fixture. The TokenLedger owns persistence; the
 * poller owns the filesystem walk + per-agent cwd attribution.
 *
 * Drift risk: medium — Codex CLI may rename `token_count`/`total_token_usage`
 * across versions. A returned `null` (no usable usage) degrades to "this
 * session contributes nothing", never a crash. A canary should assert the
 * recognised shape after Codex upgrades.
 */
function num(v) {
    const n = Number(v);
    return Number.isFinite(n) ? n : 0;
}
/**
 * Parse the full contents of a Codex rollout JSONL file. Returns null when the
 * file carries no session id or no usage reading (an empty/aborted session).
 * Tolerant of malformed lines (skipped) and trailing partial writes.
 */
export function parseCodexRollout(content) {
    if (!content)
        return null;
    let sessionId = '';
    let cwd = null;
    let model = null;
    let planType = null;
    let firstTs = 0;
    let tokenCountEvents = 0;
    let latestTotal = null;
    let latestPrimaryPct = null;
    let latestSecondaryPct = null;
    for (const raw of content.split('\n')) {
        const line = raw.trim();
        if (!line || line[0] !== '{')
            continue;
        let d;
        try {
            d = JSON.parse(line);
        }
        catch {
            continue;
        }
        const type = d['type'];
        const payload = (d['payload'] ?? {});
        if (type === 'session_meta') {
            if (typeof payload['id'] === 'string')
                sessionId = payload['id'];
            if (typeof payload['cwd'] === 'string')
                cwd = payload['cwd'];
            const tsStr = payload['timestamp'];
            if (typeof tsStr === 'string') {
                const ms = Date.parse(tsStr);
                if (!Number.isNaN(ms))
                    firstTs = ms;
            }
        }
        else if (type === 'turn_context') {
            if (typeof payload['model'] === 'string')
                model = payload['model'];
            if (typeof payload['cwd'] === 'string')
                cwd = payload['cwd'];
        }
        else if (type === 'event_msg' && payload['type'] === 'token_count') {
            const info = (payload['info'] ?? {});
            const total = info['total_token_usage'];
            if (total && typeof total === 'object') {
                latestTotal = total;
                tokenCountEvents += 1;
            }
            const rl = (payload['rate_limits'] ?? {});
            if (typeof rl['plan_type'] === 'string')
                planType = rl['plan_type'];
            const primary = rl['primary'];
            const secondary = rl['secondary'];
            if (primary && primary['used_percent'] != null)
                latestPrimaryPct = num(primary['used_percent']);
            if (secondary && secondary['used_percent'] != null)
                latestSecondaryPct = num(secondary['used_percent']);
        }
    }
    if (!sessionId || !latestTotal)
        return null;
    return {
        sessionId,
        cwd,
        model,
        planType,
        inputTokens: num(latestTotal['input_tokens']),
        cachedInputTokens: num(latestTotal['cached_input_tokens']),
        outputTokens: num(latestTotal['output_tokens']),
        reasoningOutputTokens: num(latestTotal['reasoning_output_tokens']),
        totalTokens: num(latestTotal['total_tokens']),
        primaryUsedPercent: latestPrimaryPct,
        secondaryUsedPercent: latestSecondaryPct,
        firstTs,
        tokenCountEvents,
    };
}
//# sourceMappingURL=CodexRolloutParser.js.map