export declare const MERGE3_VERSION = "text3/0.4.0"; /** A maximal changed segment: base lines [start,end) are replaced by `lines`. */ interface Hunk { start: number; end: number; lines: string[]; side: number; } /** One side's rendering of a contended base span (for policy/human to choose among). */ export interface ConflictOption { /** Variant indices that produced this exact text (agreement collapses duplicates). */ sides: number[]; text: string; } /** A base span multiple variants changed incompatibly. Positions are in MERGED lines. */ export interface ConflictRegion { baseStart: number; baseEnd: number; base: string; options: ConflictOption[]; /** Line offset of this region within `merged` (where `base` text was emitted). */ mergedStart: number; } export interface Merge3Result { /** True iff every change composed without an unresolved overlap. */ clean: boolean; /** * The merged text. Non-conflicting changes are applied. For each ConflictRegion the * BASE text is emitted (so `merged` is always a valid, replayable file); the reducer * substitutes the policy/human-chosen option per region to form the final blob. */ merged: string; conflicts: ConflictRegion[]; /** Set when line-merge was unsafe (binary / oversized): result is atomic, not merged. */ atomic?: boolean; } export interface Merge3Opts { /** * What `merged` emits for an unresolved conflict region: * "base" (default) — original base text, so a caller can substitute a chosen option * later (used when surfacing a Conflict object). * "first" — the lowest-side-index option (e.g. the accumulated "ours" content when * applying one op's patch onto current). `clean` is still false. */ onConflict?: "base" | "first"; /** * Pick the winner of a contended region (docs/22 §3.1). Returns an index into * `region.options`, or `null` when it cannot decide. * * A decided region is NOT a conflict: its chosen text goes into `merged` and it is left * out of `conflicts`. `null` — or anything that is not a valid option index — falls back * to `onConflict` and keeps the region in `conflicts`, so "policy could not decide * either" stays a first-class outcome that reaches a human. * * This module never computes what to pick and never learns why: variant indices are the * only thing it hands over. Injecting the choice is what keeps a trust ladder, evidence * and code ownership out of a text merger while still letting them decide region * content — the same discipline that keeps this file blind to what language it merges. */ arbitrate?: (region: ConflictRegion) => number | null; } /** * Merge `variants` (each a full file content) over `base`. `variants` MUST already be * in the caller's canonical order (e.g. lamport, oid) — the merge is deterministic in * that order. Variants identical to base contribute nothing. */ export declare function merge3(base: string, variants: string[], opts?: Merge3Opts): Merge3Result; /** * How many lines of `a` survive into `b` — the length of their longest common * subsequence of lines. * * Derived from `diffHunks` instead of adding a second algorithm: in that edit script every * line of `a` is either matched (producing no hunk) or consumed inside some hunk's * `[start, end)` span, so the LCS length is `a.length` minus the total span the hunks * cover. Exposed for the capture path's rename similarity (docs/19 §3.1), and as * language-blind as the rest of this module — it compares lines and nothing else. */ export declare function lcsLineLength(a: string[], b: string[]): number; /** * Line-level diff (LCS) → maximal changed segments. Each Hunk replaces base[start:end) * with `lines`. Unchanged lines produce no hunk. Deterministic. */ export declare function diffHunks(a: string[], b: string[]): Omit[]; export {}; //# sourceMappingURL=merge3.d.ts.map