"use strict";
// Promise Ledger — tracks commitments the agent makes to the user.
//
// When the agent says "I'll remind you", "I'll check this", "I'll monitor",
// etc., a promise is recorded. The obligation checker verifies fulfilment
// and flags breaches. Storage: .harness/promises.jsonl (append-only).
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectCommitments = detectCommitments;
exports.createPromise = createPromise;
exports.listPromises = listPromises;
exports.updatePromise = updatePromise;
exports.checkObligations = checkObligations;
exports.fulfilPromise = fulfilPromise;
exports.failPromise = failPromise;
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
const readline = __importStar(require("readline"));
const fs_1 = require("fs");
const atomicFile_1 = require("../persistence/atomicFile");
// ─── Commitment detection ───────────────────────────────────────────
const COMMITMENT_PATTERNS = [
    /I(?:['\u2019]ll| will)\s+remind\s+you/i,
    /I(?:['\u2019]ll| will)\s+check\s+(?:this|that|on|in)\s+(?:every|daily|weekly|each|tomorrow|regularly|periodically)/i,
    /I(?:['\u2019]ll| will)\s+monitor\s+(?:this|that|it|the|your)/i,
    /I(?:['\u2019]ll| will)\s+send\s+you\s+(?:a\s+)?(?:reminder|report|update|notification|summary|alert)/i,
    /I(?:['\u2019]ll| will)\s+follow\s+up\s+(?:on|with|about|tomorrow|next|later)/i,
    /I(?:['\u2019]ll| will)\s+schedule\s+(?:a\s+)?(?:\w+\s+)?(?:check|reminder|job|task|scan|review|run)/i,
    /I(?:['\u2019]ll| will)\s+set\s+up\s+(?:a\s+)?(?:recurring|daily|weekly|scheduled|automated)/i,
    /I(?:['\u2019]ll| will)\s+(?:keep|continue)\s+(?:tracking|watching|monitoring)/i,
    /I(?:['\u2019]ll| will)\s+notify\s+you\s+(?:when|if|about|every)/i,
    /I(?:['\u2019]ll| will)\s+(?:send|deliver)\s+(?:a\s+)?(?:daily|weekly|regular)\s+(?:report|update|summary)/i,
    /I(?:['\u2019]ll| will)\s+update\s+you\s+(?:when|if|every|daily|weekly|regularly)/i,
    /I(?:['\u2019]ll| will)\s+run\s+(?:this|that|it|the)\s+(?:every|daily|weekly|each)/i,
];
/** Detect commitment language in assistant text. Returns matched phrases. */
function detectCommitments(text) {
    const found = [];
    for (const pattern of COMMITMENT_PATTERNS) {
        const m = text.match(pattern);
        if (m) {
            // Grab surrounding context (up to 80 chars after match)
            const start = m.index ?? 0;
            const end = Math.min(start + m[0].length + 80, text.length);
            const nextPeriod = text.indexOf('.', start);
            const snippet = text.slice(start, nextPeriod > start && nextPeriod < end ? nextPeriod + 1 : end).trim();
            found.push(snippet);
        }
    }
    return found;
}
// ─── Persistence ────────────────────────────────────────────────────
function ledgerPath(projectDir) {
    return path.join(projectDir, '.harness', 'promises.jsonl');
}
async function createPromise(projectDir, commitment, options) {
    const now = new Date().toISOString();
    const promise = {
        promise_id: crypto.randomUUID(),
        commitment,
        service_id: options?.service_id,
        schedule_id: options?.schedule_id,
        capability_required: options?.capability_required,
        status: 'pending',
        next_due_at: options?.next_due_at,
        failure_count: 0,
        fallback_message: options?.fallback_message,
        session_id: options?.session_id,
        created_at: now,
        updated_at: now,
    };
    const fp = ledgerPath(projectDir);
    await fs.mkdir(path.dirname(fp), { recursive: true });
    await (0, atomicFile_1.withFileLock)(fp, () => fs.appendFile(fp, JSON.stringify(promise) + '\n', 'utf-8'));
    return promise;
}
async function listPromises(projectDir, filter) {
    const fp = ledgerPath(projectDir);
    try {
        await fs.access(fp);
    }
    catch {
        return [];
    }
    // Build latest state from append-only log (last write wins per promise_id)
    const map = new Map();
    const rl = readline.createInterface({ input: (0, fs_1.createReadStream)(fp, 'utf-8'), crlfDelay: Infinity });
    for await (const line of rl) {
        if (!line.trim())
            continue;
        try {
            const p = JSON.parse(line);
            map.set(p.promise_id, p);
        }
        catch { /* skip corrupt lines */ }
    }
    let results = Array.from(map.values());
    if (filter?.status)
        results = results.filter((p) => p.status === filter.status);
    if (filter?.service_id)
        results = results.filter((p) => p.service_id === filter.service_id);
    return results.sort((a, b) => a.created_at.localeCompare(b.created_at));
}
async function updatePromise(projectDir, promise_id, updates) {
    const fp = ledgerPath(projectDir);
    return (0, atomicFile_1.withFileLock)(fp, async () => {
        const all = await listPromises(projectDir);
        const existing = all.find((p) => p.promise_id === promise_id);
        if (!existing)
            return null;
        const updated = {
            ...existing,
            ...updates,
            updated_at: new Date().toISOString(),
        };
        await fs.appendFile(fp, JSON.stringify(updated) + '\n', 'utf-8');
        return updated;
    });
}
// ─── Obligation checker ─────────────────────────────────────────────
async function checkObligations(projectDir, availableCapabilities) {
    const all = await listPromises(projectDir);
    const now = new Date();
    const breaches = [];
    for (const p of all) {
        if (p.status !== 'pending')
            continue;
        // Overdue check
        if (p.next_due_at && new Date(p.next_due_at) < now) {
            breaches.push({
                promise_id: p.promise_id,
                breach_type: 'overdue',
                detail: `Promise "${p.commitment}" was due at ${p.next_due_at}`,
                timestamp: now.toISOString(),
            });
        }
        // Capability check
        if (p.capability_required && availableCapabilities && !availableCapabilities.has(p.capability_required)) {
            breaches.push({
                promise_id: p.promise_id,
                breach_type: 'capability_missing',
                detail: `Capability "${p.capability_required}" required but not available`,
                timestamp: now.toISOString(),
            });
        }
        // Repeated failure check
        if (p.failure_count >= 3) {
            breaches.push({
                promise_id: p.promise_id,
                breach_type: 'repeated_failure',
                detail: `Promise "${p.commitment}" has failed ${p.failure_count} times`,
                timestamp: now.toISOString(),
            });
        }
    }
    return {
        total: all.length,
        pending: all.filter((p) => p.status === 'pending').length,
        fulfilled: all.filter((p) => p.status === 'fulfilled').length,
        failed: all.filter((p) => p.status === 'failed').length,
        expired: all.filter((p) => p.status === 'expired').length,
        breaches,
    };
}
/** Fulfilment shortcut: mark a promise as fulfilled now. */
async function fulfilPromise(projectDir, promise_id) {
    return updatePromise(projectDir, promise_id, {
        status: 'fulfilled',
        last_fulfilled_at: new Date().toISOString(),
    });
}
/** Failure shortcut: increment failure count, optionally mark as failed. */
async function failPromise(projectDir, promise_id, markFailed = false) {
    const all = await listPromises(projectDir);
    const existing = all.find((p) => p.promise_id === promise_id);
    if (!existing)
        return null;
    return updatePromise(projectDir, promise_id, {
        failure_count: existing.failure_count + 1,
        status: markFailed ? 'failed' : existing.status,
    });
}
//# sourceMappingURL=promiseLedger.js.map