/**
 * The read-before-edit gate (shared by `read`, `edit`, and `write`).
 *
 * This is the framework half of the read-edit-gate feature. When — and ONLY
 * when — a host has stashed a {@link ReadStateHandle} on
 * `ctx.framework[READ_STATE_HANDLE_KEY]`, 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).
 *   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. Nothing imports
 * from the product — the handle is duck-typed and the key is a shared string
 * literal, so the framework consumer and the product injector agree on shape
 * without a cross-package type import.
 */
import type { ReadStateHandle, ToolContext } from "../kernel";
/** 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.";
/**
 * Pull the read-state handle off the context, if one was injected.
 *
 * Returns `undefined` whenever the framework bag, the key, or a well-formed
 * handle is absent — the gate then degrades to a no-op. The handle is validated
 * structurally (it must expose `get` / `set` / `has`) so a malformed injection
 * can never throw mid-mutation; it simply disables the gate.
 */
export declare function getReadStateHandle(ctx: ToolContext): ReadStateHandle | undefined;
/**
 * Record (or refresh) the read state for `absPath` from a fresh stat.
 *
 * No-op when no handle is present. Stats are taken through the kernel `fs` seam
 * — its `modifiedMs` field 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. A failed stat is swallowed: state-keeping is best-effort and must never
 * mask the real operation's outcome.
 */
export declare function recordReadState(ctx: ToolContext, absPath: string, handle: ReadStateHandle | undefined): Promise<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 stat is read through the kernel `fs` seam and 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(ctx: ToolContext, absPath: string, handle: ReadStateHandle | undefined): Promise<GateOutcome>;
