/**
 * Read-before-edit gate for the WIRED facade tool layer.
 *
 * This is the product-side half of the read-edit-gate feature. The framework's
 * `capabilities/files/read-state-gate.ts` carries the same discipline, but the
 * product wires the `read` / `edit` / `write` factories exported from
 * `indusagi/agent` (i.e. these `facade/bot/actions/` factories), so the gate had
 * to live here too to actually take effect.
 *
 * When — and ONLY when — a host passes a {@link ReadStateHandle} via the tool's
 * options bag, the file tools enforce a small discipline borrowed from
 * interactive coding agents:
 *
 *   1. A file may not be edited or overwritten until it has been *read* in this
 *      session (so the model is never blindly clobbering content it has not
 *      seen). Brand-new files (those that do not yet exist on disk) are exempt
 *      from the write tool's gate.
 *   2. A file may not be mutated if it has drifted on disk since that read — its
 *      modification time or byte size advanced past what was recorded — because
 *      that usually means a human or a linter changed it underneath us.
 *
 * After every successful read (and every successful mutation) the recorded state
 * is refreshed from the fresh on-disk stat, so the next gate check compares
 * against the latest known-good snapshot.
 *
 * The whole mechanism is *additive*: with no handle present, every helper here
 * is a no-op and the tools behave exactly as they did before. The handle is
 * duck-typed so the host and these factories agree on shape without a
 * cross-package type import.
 */
/** A single recorded read: the on-disk shape captured at read time. */
export interface ReadStateRecord {
    /** File modification time in ms, floored to a whole millisecond. */
    mtimeMs: number;
    /** File byte size at read time. */
    size: number;
    /** Optional content hash; unused by the default gate but reserved for hosts. */
    contentHash?: string;
    /** When the read was recorded; the gate mirrors this to `mtimeMs`. */
    readAt: number;
}
/**
 * Duck-typed store the host injects to drive the gate. Any object exposing this
 * shape (e.g. a `Map`-backed wrapper) works; nothing is imported across packages.
 */
export interface ReadStateHandle {
    get(path: string): ReadStateRecord | undefined;
    set(path: string, rec: ReadStateRecord): void;
    has(path: string): boolean;
}
/** The two byte-stable refusal messages the gate emits. */
export declare const READ_BEFORE_EDIT_MESSAGE = "File has not been read yet. Read it first before writing to it.";
export declare const MODIFIED_SINCE_READ_MESSAGE = "File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.";
/**
 * Record (or refresh) the read state for `absPath` from a fresh stat.
 *
 * No-op when no handle is present. The mtime is floored to a whole millisecond
 * so a sub-ms clock skew between read and a later compare can never spuriously
 * trip the staleness check. `readAt` mirrors the floored mtime — no wall-clock
 * call is made. A failed stat is swallowed: state-keeping is best-effort and
 * must never mask the real operation's outcome.
 */
export declare function recordReadState(handle: ReadStateHandle | undefined, absPath: string): void;
/** Outcome of a gate check: either cleared, or refused with a message. */
export type GateOutcome = {
    ok: true;
} | {
    ok: false;
    message: string;
};
/**
 * Enforce the read-before-edit + staleness gate ahead of a mutation.
 *
 * With no handle present this always clears (the gate is opt-in). With a handle:
 *   - refuse when `absPath` has no recorded read this session;
 *   - refuse when the on-disk modification time or byte size has advanced past
 *     the recorded read.
 *
 * The on-disk mtime is floored the same way the recorded mtime is, so the
 * comparison is apples-to-apples. A stat failure (e.g. the file vanished) clears
 * the gate so the underlying tool can surface its own, more specific error.
 */
export declare function enforceReadGate(handle: ReadStateHandle | undefined, absPath: string): GateOutcome;
