/** Line-based diff (LCS) producing a compact unified-style summary. Good enough for page-change inspection. */ export interface LineDiff { added: string[]; removed: string[]; addedCount: number; removedCount: number; ratio: number } export function diffLines(oldText: string, newText: string, maxLines = 400): LineDiff { const a = oldText.split("\n").map((s) => s.trim()).filter(Boolean); const b = newText.split("\n").map((s) => s.trim()).filter(Boolean); const setA = new Map(); const setB = new Map(); for (const l of a) setA.set(l, (setA.get(l) ?? 0) + 1); for (const l of b) setB.set(l, (setB.get(l) ?? 0) + 1); const removed: string[] = []; const added: string[] = []; for (const [l, n] of setA) { const m = setB.get(l) ?? 0; for (let i = 0; i < n - m; i++) removed.push(l); } for (const [l, n] of setB) { const m = setA.get(l) ?? 0; for (let i = 0; i < n - m; i++) added.push(l); } const total = Math.max(1, a.length + b.length); return { added: added.slice(0, maxLines), removed: removed.slice(0, maxLines), addedCount: added.length, removedCount: removed.length, ratio: (added.length + removed.length) / total }; }