// 行级 diff(LCS)—— 用于 prompt 控制面"选某版 vs 当前激活版"的差异预览。 // 纯函数、无依赖,便于单测。 export type DiffOp = "eq" | "add" | "del"; export interface DiffLine { op: DiffOp; // eq=两侧相同 / add=仅在 b(新增)/ del=仅在 a(删除) text: string; } // lineDiff(a, b):把 a → b 的逐行变化展开。基于最长公共子序列。 export function lineDiff(a: string, b: string): DiffLine[] { const al = a.split("\n"); const bl = b.split("\n"); const n = al.length; const m = bl.length; // LCS 长度表:lcs[i][j] = al[i:] 与 bl[j:] 的最长公共子序列长度。 const lcs: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0)); for (let i = n - 1; i >= 0; i--) { for (let j = m - 1; j >= 0; j--) { lcs[i][j] = al[i] === bl[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]); } } // 回溯:相同→eq;否则按 LCS 走向决定 del(消耗 a)还是 add(消耗 b)。 const out: DiffLine[] = []; let i = 0; let j = 0; while (i < n && j < m) { if (al[i] === bl[j]) { out.push({ op: "eq", text: al[i] }); i++; j++; } else if (lcs[i + 1][j] >= lcs[i][j + 1]) { out.push({ op: "del", text: al[i] }); i++; } else { out.push({ op: "add", text: bl[j] }); j++; } } while (i < n) out.push({ op: "del", text: al[i++] }); while (j < m) out.push({ op: "add", text: bl[j++] }); return out; } // diffStat:统计新增/删除行数(给 UI 角标"+3 -1")。 export function diffStat(lines: DiffLine[]): { add: number; del: number } { let add = 0; let del = 0; for (const l of lines) { if (l.op === "add") add++; else if (l.op === "del") del++; } return { add, del }; }