/** * Pure line-diff engine for file mutation tools (fs.edit / write / append / …). * Produces Cursor/Claude-style hunks with configurable context and size caps. */ export type DiffOp = "context" | "add" | "del"; export interface DiffLine { readonly op: DiffOp; readonly text: string; /** 1-based line in the old file; undefined for pure adds */ readonly oldLine?: number | undefined; /** 1-based line in the new file; undefined for pure dels */ readonly newLine?: number | undefined; } export interface DiffHunk { readonly oldStart: number; readonly newStart: number; readonly lines: readonly DiffLine[]; } export type FileChangeKind = "create" | "edit" | "overwrite" | "append" | "delete"; export interface FileChangeStats { readonly oldLines: number; readonly newLines: number; readonly added: number; readonly removed: number; } export interface DeletedSegment { /** 1-based line in the new file after which these deletions sit (0 = before first) */ readonly atNewLine: number; readonly oldStart: number; readonly lines: readonly string[]; } export interface FileChange { readonly path: string; readonly basename: string; readonly kind: FileChangeKind; readonly stats: FileChangeStats; /** Chat preview hunks (context=1, capped). */ readonly previewHunks: readonly DiffHunk[]; /** * Full after-content for the modal. Omitted when too large (use snapshotPath) * or for deletes (after is empty). */ readonly afterText?: string | undefined; /** New-file line numbers that are pure additions. */ readonly addedNewLines: readonly number[]; /** Deleted segments for full-file modal rendering. */ readonly deletedAt: readonly DeletedSegment[]; /** Optional on-disk JSON snapshot for large files. */ readonly snapshotPath?: string | undefined; /** True when content was treated as binary / non-diffable. */ readonly binary?: boolean | undefined; /** True when diff was collapsed due to size caps. */ readonly truncated?: boolean | undefined; } /** Max lines on either side before falling back to whole-file replace. */ export declare const DIFF_MAX_LINES = 20000; /** Max UTF-8 bytes on either side for full LCS. */ export declare const DIFF_MAX_BYTES = 1000000; /** * Max afterText kept inline on FileChange (else snapshot only). * Kept modest so transcript tool cards from writeMany scaffolds do not pin * multi‑MB file bodies in the TUI process for the whole session. */ export declare const INLINE_AFTER_MAX_BYTES = 48000; /** Max diff body lines in chat preview. */ export declare const PREVIEW_MAX_DIFF_LINES = 40; /** Context lines around each change for chat. */ export declare const PREVIEW_CONTEXT = 1; export declare function splitLines(text: string): string[]; export declare function looksBinary(text: string): boolean; /** * Myers O(ND) line diff → list of ops over the full file (no hunk grouping). * Falls back to whole-file replace when sizes exceed caps. */ export declare function computeLineOps(oldLines: readonly string[], newLines: readonly string[]): DiffLine[]; /** * Group full-file ops into unified hunks with `context` lines of surrounding * unchanged content. Adjacent change regions within `context*2` merge. */ export declare function groupHunks(ops: readonly DiffLine[], context?: number): DiffHunk[]; /** Cap total preview lines across hunks; drop tail hunks with a sentinel. */ export declare function capPreviewHunks(hunks: readonly DiffHunk[], maxLines?: number): { hunks: DiffHunk[]; truncated: boolean; omittedLines: number; }; export interface BuildFileChangeOptions { readonly path: string; readonly before: string; readonly after: string; readonly kind: FileChangeKind; readonly context?: number | undefined; readonly previewMaxLines?: number | undefined; /** When set, afterText is omitted from the in-memory object. */ readonly snapshotPath?: string | undefined; } /** * Build a UI-ready FileChange from before/after text. */ export declare function buildFileChange(opts: BuildFileChangeOptions): FileChange; /** Infer kind from before/after when the caller only knows the tool. */ export declare function inferChangeKind(before: string | undefined, after: string, toolHint?: "append" | "delete" | "edit" | "write"): FileChangeKind; /** * Render preview hunks as plain text (for spool / export / classic REPL). * Uses unified +/- prefixes; no ANSI. */ export declare function formatUnifiedPreview(change: FileChange, options?: { maxLines?: number; }): string; /** * Full modal body lines: after-file order with deleted segments injected. * Each entry carries a display line number (new-file) and op for coloring. */ export interface ModalDiffLine { readonly lineNo: number | undefined; readonly text: string; readonly op: DiffOp; /** For dels, old line number when known */ readonly oldLineNo?: number | undefined; } export declare function buildModalLines(change: FileChange): ModalDiffLine[]; /** Human verb for status titles. */ export declare function changeVerb(kind: FileChangeKind, status: "running" | "ok" | "failed"): string; /** Map tool name + optional kind to a display title basename. */ export declare function fileToolTitle(toolName: string, status: "queued" | "running" | "ok" | "failed" | "blocked", pathOrDisplay: string, kind?: FileChangeKind | undefined): { title: string; pathLine: string | undefined; }; export declare function isFileMutationTool(name: string): boolean;