/**
 * @file `ProcessLockManager` — the class that owns active locks, touch timers,
 *   and the exit-handler registration. Provides `acquire` / `release` /
 *   `withLock`. Co-located with the touch and staleness helpers because they
 *   share private state (`activeLocks` + `touchTimers`).
 *
 *   ## Why directories instead of files?
 *
 *   This implementation uses `mkdir()` to create lock directories (not files)
 *   because:
 *
 *   1. **Atomic guarantee**: `mkdir()` is guaranteed atomic across ALL
 *      filesystems, including NFS. Only ONE process can successfully create the
 *      directory. If it exists, `mkdir()` fails with EEXIST instantly with no
 *      race conditions.
 *   2. **File-based locking issues**:
 *
 *   - `writeFile()` with `flag: 'wx'` - atomicity can fail on NFS
 *   - `open()` with `O_EXCL` - not guaranteed atomic on older NFS
 *   - Traditional lockfiles - can have race conditions on network filesystems
 *
 *   3. **Simplicity**: No need to write/read file content, track PIDs, or manage
 *      file descriptors. Just create/delete directory and check mtime.
 *   4. **Historical precedent**: Well-known Unix locking pattern used by package
 *      managers for decades. Git uses similar approach for `.git/index.lock`.
 *
 *   ## The mtime trick
 *
 *   We periodically update the lock directory's mtime (modification time) by
 *   "touching" it to signal "I'm still actively working". This prevents other
 *   processes from treating the lock as stale and removing it. **The lock
 *   directory remains empty** - it's just a sentinel that signals "locked". The
 *   mtime is the only data needed to track lock freshness.
 *
 *   ## npm npx compatibility
 *
 *   This implementation matches npm npx's concurrency.lock approach:
 *
 *   - Lock created via `mkdir(path.join(installDir, 'concurrency.lock'))`
 *   - 5-second stale timeout (if mtime is older than 5s, lock is stale)
 *   - 2-second touching interval (updates mtime every 2s to keep lock fresh)
 *   - Automatic cleanup on process exit
 */
import type { ProcessLockOptions } from './lock-types';
/**
 * Process lock manager with stale detection and exit cleanup. Provides
 * cross-platform inter-process synchronization using file-system based locks.
 */
export declare class ProcessLockManager {
    private activeLocks;
    private touchTimers;
    private exitHandlerRegistered;
    /**
     * Ensure process exit handler is registered for cleanup. Registers a handler
     * that cleans up all active locks when the process exits.
     */
    private ensureExitHandler;
    /**
     * Touch a lock file to update its mtime. This prevents the lock from being
     * detected as stale during long operations.
     *
     * @param lockPath - Path to the lock directory.
     */
    private touchLock;
    /**
     * Start periodic touching of a lock file. Aligned with npm npx strategy to
     * prevent false stale detection.
     *
     * @param lockPath - Path to the lock directory.
     * @param intervalMs - Touch interval in milliseconds.
     */
    private startTouchTimer;
    /**
     * Stop periodic touching of a lock file.
     *
     * @param lockPath - Path to the lock directory.
     */
    private stopTouchTimer;
    /**
     * Check if a lock is stale based on mtime. Uses second-level granularity to
     * avoid APFS floating-point precision issues. Aligned with npm's npx locking
     * strategy.
     *
     * @param lockPath - Path to the lock directory.
     * @param staleMs - Stale timeout in milliseconds.
     *
     * @returns True if lock exists and is stale
     */
    private isStale;
    /**
     * Acquire a lock using mkdir for atomic operation. Handles stale locks and
     * includes exit cleanup.
     *
     * This method attempts to create a lock directory atomically. If the lock
     * already exists, it checks if it's stale and removes it before retrying.
     * Uses exponential backoff with jitter for retry attempts.
     *
     * @example
     *   ;```typescript
     *   const release = await processLock.acquire('/tmp/my-lock')
     *   try {
     *     // Critical section
     *   } finally {
     *     release()
     *   }
     *   ```
     *
     * @param lockPath - Path to the lock directory.
     * @param options - Lock acquisition options.
     *
     * @returns Release function to unlock
     *
     * @throws Error if lock cannot be acquired after all retries
     */
    acquire(lockPath: string, options?: ProcessLockOptions): Promise<() => void>;
    /**
     * Release a lock and remove from tracking. Stops periodic touching and
     * removes the lock directory.
     *
     * @example
     *   ;```typescript
     *   processLock.release('/tmp/my-lock')
     *   ```
     *
     * @param lockPath - Path to the lock directory.
     */
    release(lockPath: string): void;
    /**
     * Execute a function with exclusive lock protection. Automatically handles
     * lock acquisition, execution, and cleanup.
     *
     * This is the recommended way to use process locks, as it guarantees cleanup
     * even if the callback throws an error.
     *
     * @example
     *   ;```typescript
     *   const result = await processLock.withLock('/tmp/my-lock', async () => {
     *     // Critical section
     *     return someValue
     *   })
     *   ```
     *
     * @param lockPath - Path to the lock directory.
     * @param fn - Function to execute while holding the lock.
     * @param options - Lock acquisition options.
     *
     * @returns Result of the callback function
     *
     * @throws Error from callback or lock acquisition failure
     */
    withLock<T>(lockPath: string, fn: () => Promise<T>, options?: ProcessLockOptions): Promise<T>;
}
