import * as fs from 'fs';
export declare function sleepSync(ms: number): void;
/**
 * Ensures the target file (and its parent directory) exist so proper-lockfile
 * can create a sibling .lock directory. Created with flag 'wx' so concurrent
 * creation races are safe (EEXIST is swallowed).
 */
export declare function ensureLockTarget(filePath: string, initialContent?: string, dirMode?: number): void;
/**
 * Writes content to filePath via a temp file + rename so readers never see a
 * partial write. On POSIX, rename(2) is atomic.
 */
export declare function atomicWriteFileSync(filePath: string, content: string, options?: fs.WriteFileOptions): void;
/**
 * Convenience wrapper around {@link atomicWriteFileSync} for the common case of
 * writing pretty-printed JSON (RUSH-2840). Same tmp-then-rename mechanics, same
 * caller responsibility to ensure the parent directory exists first — this adds
 * only the `JSON.stringify`.
 */
export declare function atomicWriteJsonSync(filePath: string, data: unknown): void;
/**
 * Acquires an exclusive proper-lockfile lock on filePath, runs fn, then
 * releases the lock. Retries with capped linear back-off until either the lock
 * is acquired or LOCK_ACQUIRE_TIMEOUT_MS elapses. Breaks stale locks older than
 * LOCK_STALE_MS, so a crashed holder never blocks past the stale window.
 *
 * `fn` is handed a `heartbeat()` it can call during a long, fully SYNCHRONOUS
 * critical section. proper-lockfile keeps a held lock "alive" by refreshing its
 * lockfile mtime on a `setTimeout` every `stale/2` — but that timer only fires
 * when the event loop gets a turn. A synchronous hold that outruns `stale`
 * (e.g. the scrypt-bound rotation loop in filestore.ts, ~16s on a real store)
 * never yields, so the timer cannot run: the lock ages past `stale` mid-hold and a
 * peer contending for it treats the live holder as crashed, breaks the lock, and
 * interleaves — corrupting the invariant the lock exists to protect, with no crash
 * involved. `heartbeat()` drives the same refresh synchronously (bumps the lockfile
 * mtime), so a long sync holder stays fresh while the short `stale` window still
 * detects a genuinely crashed holder within LOCK_STALE_MS. Callers whose critical
 * section is short (a single read-modify-write) can ignore it.
 */
export interface FileLockOptions {
    staleMs?: number;
    acquireTimeoutMs?: number;
}
export declare function withFileLock<T>(filePath: string, fn: (heartbeat: () => void) => T, opts?: FileLockOptions): T;
/**
 * Async counterpart of {@link withFileLock} for callers on the daemon's shared
 * event loop (PHNX-3695). The sync version retries acquisition with
 * {@link sleepSync} (`Atomics.wait`), which HALTS the thread for up to
 * {@link LOCK_ACQUIRE_TIMEOUT_MS} on contention — on a daemon tick that freezes
 * every service and the browser IPC server. This variant awaits proper-lockfile's
 * async `lock()` and yields with a real timer between retries, so the loop keeps
 * turning while a peer holds the lock. Same stale-break, same acquire budget,
 * same compromised-lock surfacing.
 */
export declare function withFileLockAsync<T>(filePath: string, fn: (heartbeat: () => void) => Promise<T> | T, opts?: FileLockOptions): Promise<T>;
