/**
 * Migration marker file I/O — ensures the boot-time v0.2.0 re-layout is
 * idempotent and race-safe.
 *
 * Layout:
 *   {rootDir}/.migration/v0.2.0       — completion marker (JSON body)
 *   {rootDir}/.migration/v0.2.0.tmp   — in-flight lock (O_EXCL / `wx` flag)
 *
 * Atomicity contract (Convention #8):
 *  - `writeMarker` goes through write-tmp-rename so readers never see a
 *    partially serialized body.
 *  - `acquireMigrationLock` uses the `wx` flag (O_CREAT | O_EXCL) so
 *    concurrent boots detect each other rather than overwriting. Loser
 *    cooperates (see filesystem.ts — waits and re-checks the main marker).
 *  - `readMarker` tolerates missing / corrupt files: missing → null,
 *    corrupt JSON → null (not throw). The migrator treats either as "run
 *    again"; a corrupt marker is safer to retry than to honor as valid.
 */
import type { ProjectId } from '../../types/session/ids.js';
/**
 * Marker payload. `migratedThreads` preserves the legacy → new mapping so
 * later tooling (e.g. `namzu sdk migrate-ids`) can cross-reference.
 */
export interface MigrationMarker {
    version: string;
    at: Date;
    migratedThreads: readonly {
        legacyThreadId: string;
        newProjectId: ProjectId;
    }[];
}
/**
 * Read a marker file. Returns `null` when the file is absent OR when the
 * contents fail JSON.parse — corruption is treated as "migration did not
 * complete cleanly", so the caller re-runs rather than honoring stale data.
 */
export declare function readMarker(path: string): Promise<MigrationMarker | null>;
/**
 * Write a marker atomically via write-tmp-rename. Parent directory is
 * created on demand so callers do not have to mkdir separately.
 */
export declare function writeMarker(path: string, marker: MigrationMarker): Promise<void>;
/**
 * Acquire an exclusive lock by creating `tmpPath` with the `wx` flag.
 * EEXIST means another process is mid-migration — callers must treat that
 * as "wait and re-check the main marker" rather than overwriting.
 *
 * Returns on success; throws the raw `NodeJS.ErrnoException` on EEXIST or
 * any other FS failure so the caller can branch on `code`.
 */
export declare function acquireMigrationLock(tmpPath: string): Promise<void>;
/**
 * Release the lock. Missing file is tolerated — lock release is idempotent
 * by design so crashed mid-migrations do not wedge subsequent boots.
 */
export declare function releaseMigrationLock(tmpPath: string): Promise<void>;
//# sourceMappingURL=marker.d.ts.map