"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunLock = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
class RunLock {
    storageDir;
    constructor(storageDir) {
        this.storageDir = storageDir;
    }
    acquire(runId) {
        const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
        try {
            (0, fs_1.mkdirSync)(lockDir); // mkdir is atomic across all OS
            (0, fs_1.writeFileSync)((0, path_1.join)(lockDir, 'pid'), String(process.pid));
            return true;
        }
        catch {
            return this.tryRecoverStaleLock(runId);
        }
    }
    release(runId) {
        const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
        try {
            (0, fs_1.rmSync)(lockDir, { recursive: true });
        }
        catch { /* ignore */ }
    }
    // Note: TOCTOU race between release() and acquireFresh() — another process
    // could acquire between these calls. acquireFresh() returns false in that case.
    // Safe for single-process MCP server. Multi-process use would need flock().
    tryRecoverStaleLock(runId) {
        const pidFile = (0, path_1.join)(this.storageDir, runId, '.lock', 'pid');
        try {
            const pid = parseInt((0, fs_1.readFileSync)(pidFile, 'utf-8').trim(), 10);
            process.kill(pid, 0); // Check if alive — throws ESRCH if dead
            return false; // Process alive → genuine contention
        }
        catch (err) {
            const e = err;
            if (e.code === 'ESRCH' || e.code === 'ENOENT') {
                // Dead process or missing pid file → stale lock
                this.release(runId);
                return this.acquireFresh(runId);
            }
            return false;
        }
    }
    acquireFresh(runId) {
        const lockDir = (0, path_1.join)(this.storageDir, runId, '.lock');
        try {
            (0, fs_1.mkdirSync)(lockDir);
            (0, fs_1.writeFileSync)((0, path_1.join)(lockDir, 'pid'), String(process.pid));
            return true;
        }
        catch {
            return false;
        }
    }
}
exports.RunLock = RunLock;
//# sourceMappingURL=run-lock.js.map