import { type GitObjectHeader } from '../../git/objects.js';
import type { GitCommitFileChange, GitRange, GitRangeMode, GitTreeEntry } from '../../git/types.js';
import { type EntityBounds, type EntityCommitRecord, type EntityCounters, type EntityRepoIdentity } from './types.js';
export interface EntityGitOptions {
    repoRoot: string;
    signal?: AbortSignal;
    counters?: EntityCounters;
}
/**
 * Every git call in this subsystem goes through these two wrappers so the
 * invocation counter cannot drift from reality — a test asserting "git calls
 * stay bounded" is only meaningful if no call can bypass the counter.
 */
declare function countedGit(args: readonly string[], options: EntityGitOptions): Promise<import("../../git/client.js").RunGitResult>;
export declare function readEntityRepoIdentity(options: EntityGitOptions): Promise<EntityRepoIdentity>;
export declare function repoIdentityKey(identity: EntityRepoIdentity): string;
export interface ResolveEntityDiffRangeOptions extends EntityGitOptions {
    base?: string;
    head?: string;
    staged?: boolean;
    rangeMode?: GitRangeMode;
}
/** Resolve every entity-diff endpoint with replacement refs, grafts, and lazy fetches disabled. */
export declare function resolveEntityDiffRange(options: ResolveEntityDiffRangeOptions): Promise<GitRange>;
/**
 * Build an entity raw-diff range exclusively from the immutable objects that
 * range resolution captured. No Git-version branch and no symbolic name can
 * change the answer after this point.
 */
export declare function buildEntityDiffRangeArgs(range: GitRange): string[];
export declare function resolveCommit(ref: string, options: EntityGitOptions): Promise<string | undefined>;
export declare function isAncestorCommit(ancestor: string, descendant: string, options: EntityGitOptions): Promise<boolean>;
export interface CommitWindow {
    commits: EntityCommitRecord[];
    /** Changed paths and their blob ids, per commit sha. */
    changesByCommit: Map<string, GitCommitFileChange[]>;
    truncated: boolean;
}
export interface WalkCommitWindowOptions extends EntityGitOptions {
    /** Exclusive lower bound; omit to walk from the beginning of history. */
    sinceCommit?: string;
    head?: string;
    bounds: EntityBounds;
    /**
     * Where this walk's numbering starts, so an extended index stays ordered.
     *
     * `order` is the only cheap way to ask whether one recorded event precedes
     * another; an incremental walk that restarted at zero would give a commit from
     * today the same order as one from the first week, and every comparison across
     * the two walks would silently invert.
     */
    orderOffset?: number;
}
/**
 * Read a whole commit window in **one** git invocation.
 *
 * `git log --raw` emits both the commit records and each commit's raw diff —
 * including pre- and post-image blob ids and rename detection — in a single
 * stream. Doing this per commit with `diff-tree` instead would spawn one
 * process per commit, which on a real history is tens of thousands of forks
 * and dominates the wall clock.
 */
export declare function walkCommitWindow(options: WalkCommitWindowOptions): Promise<CommitWindow>;
export declare function parseCommitWindow(buffer: Buffer, bounds: EntityBounds, orderOffset?: number): CommitWindow;
export interface WalkFileHistoryOptions extends EntityGitOptions {
    relativePath: string;
    /** Where to start looking back from; defaults to HEAD. */
    startRef?: string;
    /** How many commits touching this path to examine. */
    limit: number;
}
/**
 * The commits that touched one path, newest first, following renames.
 *
 * This is the plumbing behind attribution outside the indexed window. `--raw`
 * carries both pre- and post-image blob ids, so the whole walk can be evaluated
 * from one invocation plus one batched blob read — the alternative, resolving
 * `<commit>:<path>` per commit, is a process per commit for the same bytes.
 *
 * `--follow` is what lets it cross a rename, and it is the reason the pathspec
 * is a single path: git supports the option no other way.
 *
 * The returned `order` numbers this walk alone, newest first, and has nothing to
 * do with the index's own commit ordering.
 */
export declare function walkFileHistory(options: WalkFileHistoryOptions): Promise<CommitWindow>;
export type BlobHeader = GitObjectHeader;
/**
 * Sizes first, contents second.
 *
 * `--batch-check` is tiny and lets oversized blobs be dropped *before* they are
 * read, and lets the content pass be packed to an exact byte budget instead of
 * guessing how much a batch will return.
 */
export declare function readBlobHeaders(oids: readonly string[], options: EntityGitOptions): Promise<Map<string, BlobHeader>>;
/**
 * Read blob contents in byte-budgeted batches.
 *
 * The response stream is `<oid> <type> <size>\n<content>\n`; content is taken
 * by its declared byte length and never by scanning for a delimiter, because a
 * blob may contain anything including the delimiter itself.
 */
export declare function readBlobs(oids: readonly string[], headers: ReadonlyMap<string, BlobHeader>, options: EntityGitOptions & {
    maxBatchBytes: number;
}): Promise<Map<string, Buffer>>;
export declare function parseBatchStream(buffer: Buffer, into: Map<string, Buffer>): void;
/**
 * One diff's changed paths, with the blob id on each side.
 *
 * `--raw` is what makes entity diff cheap: it reports both pre- and post-image
 * blob ids alongside rename detection, so each side can be fetched by content
 * address instead of by re-resolving `<ref>:<path>` per file. A worktree
 * comparison reports an all-zero post-image, meaning "read it from disk".
 */
export declare function readRawDiff(rangeArgs: readonly string[], options: EntityGitOptions & {
    paths?: readonly string[];
}): Promise<GitCommitFileChange[]>;
/** Every blob in a tree, for snapshotting a ref that is not a commit boundary. */
export declare function listTreeBlobs(ref: string, options: EntityGitOptions): Promise<GitTreeEntry[]>;
/**
 * Blobs staged in the index. Entries at a nonzero stage are unmerged, and are
 * skipped rather than guessed at — picking a conflict side would silently
 * invent a state the developer never had.
 */
export declare function listIndexBlobs(options: EntityGitOptions): Promise<{
    entries: GitTreeEntry[];
    unmerged: string[];
}>;
export { countedGit as runEntityGit };
