import type { CodebaseIndex } from '../types.js';
import type { TestRecognizer } from '../tests.js';
import type { EntityRecord, LineageEvent, LineageHead } from './types.js';
import type { EntityIndex } from './store.js';
import type { OccEntityQuery, OccEntityRef } from './api-types.js';
/** An entity as it exists in the working tree right now, joined to its history. */
export interface LiveEntity {
    record: EntityRecord;
    ref: OccEntityRef;
}
export interface LiveEntityIndex {
    all: LiveEntity[];
    byNodeId: Map<string, LiveEntity>;
    byLineageId: Map<string, LiveEntity>;
    byName: Map<string, LiveEntity[]>;
    byQualifiedName: Map<string, LiveEntity[]>;
    byPath: Map<string, LiveEntity[]>;
    /**
     * Lineage ids that more than one live entity claimed. `byLineageId` keeps the
     * first declaration on the rare collision; recording the id lets a handle
     * lookup surface the collision as a diagnostic instead of a silent first
     * pick. Optional so index values built by earlier releases stay assignable.
     */
    lineageIdCollisions?: Set<string>;
}
export interface BuildLiveEntitiesInput {
    index: CodebaseIndex;
    entityIndex: EntityIndex;
    repoIdentity: string;
    recognizer: TestRecognizer;
    /**
     * Data-format documents and their current text.
     *
     * These are not in the code index — their extensions are deliberately absent
     * from `CODE_EXTENSIONS` so the code graph is unaffected — so the session
     * discovers and reads them separately and hands them in here.
     */
    formatFiles?: ReadonlyMap<string, string>;
    /**
     * Paths git reports as untracked.
     *
     * The only evidence that distinguishes "git has never seen this" from "the
     * index never reached it". Without it, a bounded index reports its own limits
     * as facts about the working tree.
     */
    untracked?: ReadonlySet<string>;
    /** True when the index that produced `entityIndex` hit a bound. */
    truncated?: boolean;
}
/**
 * Project the current index into entity space and attach each entity's lineage.
 *
 * This is the join between two different notions of "the code": the graph
 * index, which knows about edges and node ids in the working tree, and the
 * lineage index, which knows what each entity has been through. `entityStateKey`
 * is the key on both sides.
 */
export declare function buildLiveEntities(input: BuildLiveEntitiesInput): LiveEntityIndex;
/**
 * A stable id for something git has never seen.
 *
 * Derived from the entity's current position rather than from a birth commit,
 * because there is no birth commit yet. It is reproducible within a working
 * tree, and `provisional` marks it so nothing mistakes it for history.
 */
export declare function provisionalLineageId(repoIdentity: string, record: EntityRecord): string;
export declare function normalizeRelativePath(value: string): string;
/**
 * Does this entity's file fall under the requested path?
 *
 * One rule covers both a file and a directory, with no stat and no trailing
 * slash convention: a path matches itself, or anything beneath it. An exact file
 * path therefore still matches only that file, because no path can begin with
 * `src/reader.ts/` — while `src/services` matches every entity in the subtree,
 * which is the natural first question to ask about an unfamiliar one.
 */
export declare function matchesPathScope(entityPath: string, wanted: string): boolean;
/** Normalize a caller-supplied path scope; a trailing slash carries no extra meaning. */
export declare function normalizePathScope(value: string): string;
export type ResolveEntityOutcome = {
    status: 'resolved';
    entity: LiveEntity;
} | {
    status: 'not_found';
    candidates: OccEntityRef[];
    message: string;
} | {
    status: 'ambiguous';
    candidates: OccEntityRef[];
    message: string;
};
/**
 * Resolve a query to exactly one entity, or refuse.
 *
 * A qualified name is tried before a bare one, so `Cache.get` never competes
 * with a free function named `get`. When more than one entity survives, the
 * result is `ambiguous` with every candidate listed: silently taking the first
 * would make the answer depend on file iteration order, and the caller would
 * have no way to know it happened.
 */
export declare function resolveEntity(query: OccEntityQuery, live: LiveEntityIndex): ResolveEntityOutcome;
/**
 * Why a lineage handle failed to resolve, graded by evidence.
 *
 * `version-mismatch` needs no lookup — the id's prefix names a different
 * `ENTITY_LINEAGE_ID_VERSION`, so every stored handle of that generation is
 * stale by construction. `deleted` is a proved end: the lineage's last recorded
 * event is a deletion, independent of any baseline. `absent` means the index
 * knows the lineage but the supplied entity view no longer contains it — a
 * working-tree deletion or a bounded-index visibility gap, which must never be
 * upgraded to `deleted`. `outside-window` means the id is well-formed for this
 * version but unknown here: another repository, or history beyond the walk.
 */
export type ResolveLineageHandleOutcome = {
    status: 'resolved';
    entity: LiveEntity;
    collision?: boolean;
} | {
    status: 'not_found';
    reason: 'version-mismatch' | 'deleted' | 'absent' | 'outside-window';
    message: string;
    /** The proved deletion event, present only for `reason: 'deleted'`. */
    deletionEvent?: LineageEvent;
    /** The lineage's head record, present for `reason: 'absent'` when the index still holds one. */
    head?: LineageHead;
};
/**
 * Resolve a durable lineage id against one entity view.
 *
 * The view is whichever `LiveEntityIndex` answers the caller's question — the
 * working tree for live hashes, a committed projection for lineage-lane facts.
 * A lineage id maps to at most one entity by construction (`byLineageId` keeps
 * the first declaration on the rare collision, and `collision` reports when
 * that happened), so unlike name resolution there is no ambiguous arm.
 */
export declare function resolveEntityHandle(lineageId: string, view: LiveEntityIndex, entityIndex: EntityIndex): ResolveLineageHandleOutcome;
