/** * Line-level diff used for the edit-approval preview. * * Pure functions only: no I/O, no framework imports — unit-testable in * isolation. The diff is computed with jsdiff's `structuredPatch` — the same * reference implementation the harness's write/edit result cards use * (`@deepseek-ai/dsh-tool-fs`), with the same 3-line context window — so the * approval preview and the post-approval result card derive from the same * algorithm. Each unified-diff hunk line carries its own role (` ` context, * `-` removed, `+` added), which this module maps onto the `+`/`-`/` ` * prefixed lines shown in the approval panel headline, with exact 1-based * line numbers from the hunk start lines and a `⋯` gap row between hunks. * * @module dsh-edit-approval/diff */ export type DiffLineType = 'add' | 'remove' | 'context' | 'gap'; /** One aligned line of the diff. */ export interface DiffLine { readonly type: DiffLineType; readonly text: string; /** 1-based original line number; present on remove/context lines. */ readonly oldLine?: number; /** 1-based new line number; present on add/context lines. */ readonly newLine?: number; } /** * A `gap` line marks the unchanged run between two separate hunks (rendered * as `⋯`). jsdiff already merges hunks whose context windows would overlap, * so a gap row appears only where lines are genuinely skipped. */ /** * Context lines shown on each side of an applied hunk. Mirrors * `@deepseek-ai/dsh-tool-fs`'s `DIFF_CONTEXT`, so the preview's context * window matches the harness diff card exactly. */ export declare const DIFF_CONTEXT = 3; /** * Compute a line-level diff between two texts. Line roles and 1-based line * numbers come straight from the unified-diff hunks (`oldStart`/`newStart` * per hunk), so they are exact rather than derived. Identical texts yield an * empty diff (no hunks); a trailing-newline-only change yields a real * `-`/`+` pair instead of a phantom empty line. */ export declare function computeLineDiff(oldText: string, newText: string): DiffLine[]; /** Default prefix markers: add is green (`+`), remove is red (`-`), context grey (` `), hunk gap (`⋯`). */ export declare const DEFAULT_PREFIX: Readonly>; export interface DiffRenderOptions { /** Per-type prefix; missing types fall back to {@link DEFAULT_PREFIX}. */ readonly prefix?: Readonly>>; /** Cap on emitted lines; the tail is summarized with "… N more lines". 0 = no cap. */ readonly maxLines?: number; /** Prefix 1-based line numbers (old for removals, new for additions, both for context). */ readonly lineNumbers?: boolean; } /** * Render a diff as multi-line text for the approval reason. Long diffs are * capped (default 500 lines) so the panel stays scannable; the approval * panel body scrolls, so a large edit is still reviewable in parts. */ export declare function renderDiff(diff: readonly DiffLine[], options?: DiffRenderOptions): string; /** Number of changed lines (additions + removals); context and gap rows do not count. */ export declare function countChangedLines(diff: readonly DiffLine[]): number; /** Count of added lines, for the summary header. */ export declare function countInsertions(diff: readonly DiffLine[]): number; /** Count of removed lines, for the summary header. */ export declare function countDeletions(diff: readonly DiffLine[]): number;