import { type GitRunner } from './project.js';
import type { SpikeAssignment } from './auto-pm.js';
/** The first line of a placeholder sibling: the claim, naming the agent that holds it. */
export declare const SPIKE_LOCK_PREFIX = "PENDING:";
/**
 * How old a PENDING lock must be before it is presumed dead and released. Generous against the
 * slowest live path — spiking and planning can take hours, on top of a cloud queue — because a
 * lock released under a live agent re-opens the double-work window the lock exists to close,
 * while a dead agent's ticket only waits one interval longer. This is a bug-recovery mechanism
 * that ideally never fires (#1364 review), so erring long costs nearly nothing.
 */
export declare const SPIKE_LOCK_STALE_MS: number;
/** Whether a sibling's content is a PENDING placeholder rather than a real spike or plan. */
export declare function isSpikeLock(md: string): boolean;
/** What a lock file holds: the claim line and nothing else, so the check above stays trivial. */
export declare function spikeLockContent(agentId: string): string;
/** The commit a batch of locks lands as. Names the count so the history reads as what happened. */
export declare function lockMessage(count: number): string;
/** The commit a release lands as. */
export declare function releaseMessage(count: number): string;
/** Injectable seams so both operations are unit-testable off disk, git, and GitHub. */
export interface SpikeLockDeps {
    git?: GitRunner;
    /** Write one lock file (default `fs.writeFile`). */
    write?: (path: string, content: string) => Promise<void>;
    /** Read one sibling (default `fs.readFile`); a rejection reads as "not a lock". */
    read?: (path: string) => Promise<string>;
    /** Delete one lock file (default `fs.rm`). */
    remove?: (path: string) => Promise<void>;
    /** List `tickets/` (default `fs.readdir`); a rejection reads as an empty directory. */
    list?: (dir: string) => Promise<string[]>;
    /**
     * Whether any open PR touches `file` (#1313's read, reused): a finished agent's PR carries the
     * real sibling, so an open one keeps the lock however old it is. `undefined` means the answer
     * could not be read, which also keeps the lock — releasing on a `gh` hiccup would re-open the
     * double-work window over a network blip.
     */
    prTouches?: (cwd: string, file: string) => Promise<boolean | undefined>;
    /** Clock, injectable for tests. */
    now?: () => number;
    /** Override {@link SPIKE_LOCK_STALE_MS}. */
    staleMs?: number;
    /** Progress line. */
    log?: (message: string) => void;
}
/**
 * Claim `assignments`' tickets for their agents: write both placeholder siblings per ticket,
 * commit the whole batch in one pathspec-scoped commit, and push it to origin's default branch
 * ({@link pushLockCommit}). Resolves the subset actually locked — a ticket whose sibling appeared since the candidates
 * were enumerated is skipped, not overwritten: an existing file is someone's claim or someone's
 * work, and either outranks this batch.
 *
 * A batch whose commit failed is rolled back (the written files removed) and resolves `[]`:
 * uncommitted placeholders in the user's checkout would be noise git blames on nobody. A batch
 * whose *push* failed is kept and resolved as locked — the commit still guards every run forked
 * from this checkout, which is the common case, and the sweep should not stand a healthy local
 * fan-out down over a network blip. The push is what closes the cross-machine window (#1320), so
 * its failure is logged rather than swallowed.
 *
 * Never throws: this runs on a background tick with nothing to catch it.
 */
export declare function acquireSpikeLocks(cwd: string, assignments: readonly SpikeAssignment[], deps?: SpikeLockDeps): Promise<SpikeAssignment[]>;
/**
 * Release the PENDING locks whose agents are presumed dead, so a crashed spike does not brick its
 * ticket forever. A lock is stale exactly when all three hold (#1327's rule): its content is still
 * the placeholder, no open PR touches it (a finished agent's PR carries the real sibling — the
 * #1313 claim takes over from here), and its last commit is older than {@link SPIKE_LOCK_STALE_MS}.
 * An *uncommitted* placeholder is left alone: it is a batch being acquired right now, or a commit
 * failure {@link acquireSpikeLocks} already rolled back.
 *
 * Deletions land as one pathspec-scoped commit, pushed best-effort like the acquisition.
 * Resolves the released tickets' filenames. Never throws.
 */
export declare function releaseStaleSpikeLocks(cwd: string, deps?: SpikeLockDeps): Promise<string[]>;
//# sourceMappingURL=spike-locks.d.ts.map