/** Creates a directory (and all parents) if it does not already exist. */
export declare function ensureDir(dirPath: string): void;
/**
 * Resolves a user-provided relative path ensuring it stays inside the workspace root.
 * Throws if the path is absolute, escapes via `../`, or resolves to the root itself.
 */
export declare function resolveWorkspacePath(root: string, relativePath: string): string;
/**
 * Writes content to a file atomically by first writing to a temp file in the
 * same directory, then renaming. Prevents corruption if the process crashes mid-write.
 */
export declare function writeFileAtomic(filePath: string, content: string): void;
/**
 * Executes `fn` while holding a directory-based file lock.
 * Uses mkdir for atomic acquisition; retries with backoff on contention.
 */
export declare function withFileLock<T>(filePath: string, fn: () => T, timeoutMs?: number): T;
/** Reads a JSONL file and returns parsed records. Returns [] if the file does not exist or is empty. */
export declare function readJsonlFile<T>(filePath: string): T[];
/** Appends a record as a JSON line to a JSONL file, creating the file and its parent dirs if needed. */
export declare function appendJsonlFile<T>(filePath: string, record: T): void;
/**
 * Deduplicates an array of id-keyed records by keeping the last write for each id.
 * Mirrors the append-log pattern used throughout JSONL state files.
 */
export declare function dedupeById<T extends {
    id: string;
}>(records: T[]): T[];
/** Strips undefined values from a plain object (used before JSON serialisation). */
export declare function compact<T extends Record<string, unknown>>(value: T): T;
export type WriteResult = 'written' | 'skipped';
export type FileWriterOptions = {
    force: boolean;
    /** Called with the file path after a successful write. */
    log: (filePath: string) => void;
    /** Called with the file path when a write is skipped. */
    warn: (filePath: string) => void;
};
/**
 * Thin wrapper around node:fs write operations.
 * Centralises the force/skip decision so every setup module
 * shares the same behaviour without duplicating the guard.
 */
export declare class FileWriter {
    private readonly force;
    private readonly log;
    private readonly warn;
    constructor(opts: FileWriterOptions);
    /**
     * Writes `content` to `filePath`.
     * Skips the write (and calls `warn`) when the file already exists and
     * `force` is false. Returns whether the file was actually written.
     */
    write(filePath: string, content: string): WriteResult;
}
