/**
 * stopGate.ts — UnjustifiedStopGate server infrastructure (PR0a).
 *
 * Provides the read-side API surface that the stop-hook router consumes.
 * Runtime mode persists to disk so shadow-mode rollout survives server
 * restarts; per-session hot-path state remains process-local and is
 * repopulated by hook events.
 *
 * Spec: docs/specs/context-death-pitfall-prevention.md
 *
 * PR0a deliverables:
 * - Hot-path batched state assembly: {mode, killSwitch, autonomousActive,
 *   compactionInFlight, sessionStartTs}
 * - Kill-switch local fast-path (set/clear/get)
 * - Compaction probe (P0.6): /tmp/claude-session-<id>/compacting OR
 *   compaction-recovery.sh mtime within 60s
 * - Version contract constants for /health
 *
 * Threat model: drift-correction, NOT security boundary. See spec §
 * "Threat model".
 */
export declare const GATE_ROUTE_VERSION = 1;
export declare const GATE_ROUTE_MINIMUM_VERSION = 1;
export type GateMode = 'off' | 'shadow' | 'enforce';
export declare function configureStopGateState(opts?: {
    modeFilePath?: string;
    defaultMode?: GateMode;
}): GateMode;
export declare function getMode(): GateMode;
export declare function setMode(mode: GateMode): void;
export declare function getKillSwitch(): boolean;
/**
 * Set kill-switch state in-memory. Returns the prior value so the caller
 * can detect no-op flips for telemetry.
 *
 * PR0a does NOT propagate to the machine registry — that fanout lands in
 * PR4 alongside the CLI. The server can be killed via the local fast-path
 * endpoint immediately; remote machines catch up later.
 */
export declare function setKillSwitch(value: boolean): boolean;
/**
 * Record the SessionStart timestamp for a session id. Idempotent:
 * subsequent calls for the same id are no-ops (first SessionStart wins —
 * we track the original session boundary, not later resumes).
 *
 * Called by the /hooks/events handler when a SessionStart event arrives.
 */
export declare function recordSessionStart(sessionId: string, timestampMs: number): void;
export declare function getSessionStartTs(sessionId: string): number | null;
/**
 * Test-only reset. Production code must not call this.
 */
export declare function _resetForTests(): void;
export interface CompactionProbeOptions {
    /** Session id used to look up the per-session marker file. */
    sessionId?: string;
    /** Path to compaction-recovery.sh (for mtime heuristic). Defaults to
     *  the agent-local hook path. Tests inject a tmp path. */
    recoveryScriptPath?: string;
    /** Override "now" for tests. */
    now?: number;
}
export declare function compactionInFlight(opts?: CompactionProbeOptions): boolean;
export interface HotPathState {
    mode: GateMode;
    killSwitch: boolean;
    autonomousActive: boolean;
    compactionInFlight: boolean;
    sessionStartTs: number | null;
    routeVersion: number;
    /**
     * green-pr-automerge-enforcement Layer 2: present only when the ending
     * session's branch matches a fresh, armed green-PR snapshot candidate. The
     * hook acts on it MODE-INDEPENDENTLY (one-shot block). NO variant carries a
     * runnable merge command (round-6) — the watcher being armed is exactly the
     * state where manual merging is recreated manual work.
     */
    greenPrBlock?: GreenPrBlock | null;
}
export interface GreenPrBlock {
    pr: number;
    message: string;
    variant: 'mergeable' | 'protected-paths' | 'disarmed';
}
/** A minimal projection of the watcher's last-tick snapshot for Layer 2. */
export interface GreenPrSnapshotForBlock {
    at: number;
    entries: Array<{
        pr: number;
        headRefName: string;
        kind: 'mergeable' | 'protected-paths';
    }>;
}
/**
 * Compute the Layer-2 greenPrBlock for an ending session. Pure + testable.
 * Blocks ONLY when: the snapshot is fresh (≤ 2× tickIntervalMs), the session's
 * branch matches a candidate, and not suppressed by killSwitch/compaction. When
 * the watcher is DISARMED, the matching entry yields the do-not-merge variant
 * (never the merge coaching). No variant contains a runnable command.
 */
export declare function computeGreenPrBlock(args: {
    snapshot: GreenPrSnapshotForBlock | null;
    sessionBranch: string | null;
    armed: boolean;
    killSwitch: boolean;
    compactionInFlight: boolean;
    tickIntervalMs: number;
    now: number;
}): GreenPrBlock | null;
/**
 * Resolve a session's current git branch from its cwd, handling the linked-
 * worktree case where `.git` is a FILE (`gitdir: <path>`) not a directory
 * (instar-dev builds live in worktrees). Two tiny reads, no git spawn,
 * fail-open (null → never blocks). Pure over the injected fs reader.
 */
export declare function resolveBranchFromCwd(cwd: string, readFile: (p: string) => string, exists: (p: string) => boolean): string | null;
export interface HotPathInputs {
    sessionId?: string;
    /** Whether the current agent is in autonomous mode. PR0a reads it from
     *  the autonomous-state.local.md file convention; PR3 may use a
     *  finer-grained source. Pass an explicit boolean to override (tests). */
    autonomousActiveOverride?: boolean;
    autonomousStateFile?: string;
    recoveryScriptPath?: string;
    now?: number;
    /**
     * GAP-B (autonomous-run-registration-guarantee D2): the topic this
     * session serves, resolved SERVER-SIDE by inverting
     * `.instar/topic-session-registry.json`'s `topicToSession` map on the
     * session's tmux name (the same inversion the bash stop hook uses). When
     * present, readAutonomousActive checks the CANONICAL per-topic
     * registration `.instar/autonomous/<topicId>.local.md` FIRST.
     *
     * Unresolved (a registry-lookup miss) → undefined. The read then falls
     * back to BOTH legacy single-file paths — NEVER a silent
     * autonomousActive:false (no-silent-fallbacks ratchet).
     */
    topicId?: string | number;
    /**
     * Agent home root the relative autonomous-state paths resolve against.
     * Defaults to process.cwd() (the agent home the server runs in). Tests
     * inject a tmp dir. The per-topic file lives at
     * `<stateRoot>/.instar/autonomous/<topicId>.local.md`; the two legacy
     * single-files at `<stateRoot>/.instar/autonomous-state.local.md` and
     * `<stateRoot>/.claude/autonomous-state.local.md`.
     */
    stateRoot?: string;
}
/**
 * GAP-B D2 — resolve the topic a session serves SERVER-SIDE, mirroring the
 * bash stop hook's inversion of `topic-session-registry.json`'s
 * `topicToSession` (topic→tmux) map keyed on the session's tmux name.
 *
 * The stop-gate hot-path receives the Claude session UUID, not the tmux
 * name, so the caller resolves UUID→tmux first (via the session manager's
 * claudeSessionId record) and passes the tmux name here. Pure + fail-open:
 * any read/parse error → null (the read then uses the legacy fallbacks; a
 * null is the explicit unresolved-topic case, never a silent false).
 *
 * @param registryPath absolute path to topic-session-registry.json
 * @param tmuxSession  the session's tmux name (the registry value to invert on)
 */
export declare function resolveTopicForTmux(registryPath: string, tmuxSession: string | null | undefined, readFile?: (p: string) => string): string | null;
export declare function getHotPathState(opts?: HotPathInputs): HotPathState;
//# sourceMappingURL=stopGate.d.ts.map