mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-05 08:58:34 +00:00
Capture file edit snapshots through runner tool lifecycle hooks and render unified diffs in the WebUI with folding and truncation controls.
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
import { parsePatch } from "diff";
|
|
|
|
import type { UIFileDiff } from "@/lib/types";
|
|
|
|
export interface RenderableFileDiffLine {
|
|
kind: "context" | "add" | "delete";
|
|
old_lineno?: number | null;
|
|
new_lineno?: number | null;
|
|
content: string;
|
|
}
|
|
|
|
export interface RenderableFileDiffHunk {
|
|
old_start: number;
|
|
old_lines: number;
|
|
new_start: number;
|
|
new_lines: number;
|
|
lines: RenderableFileDiffLine[];
|
|
}
|
|
|
|
export interface RenderableFileDiff {
|
|
hunks: RenderableFileDiffHunk[];
|
|
}
|
|
|
|
export function hasRenderableFileDiff(diff?: UIFileDiff): boolean {
|
|
if (!diff) return false;
|
|
return typeof diff.text === "string" && diff.text.trim().length > 0;
|
|
}
|
|
|
|
export function parseRenderableFileDiff(diff: UIFileDiff): RenderableFileDiff {
|
|
if (typeof diff.text === "string" && diff.text.trim().length > 0) {
|
|
return parseUnifiedDiffText(diff.text);
|
|
}
|
|
return { hunks: [] };
|
|
}
|
|
|
|
function parseUnifiedDiffText(text: string): RenderableFileDiff {
|
|
let files: ReturnType<typeof parsePatch>;
|
|
try {
|
|
files = parsePatch(text);
|
|
} catch {
|
|
return { hunks: [] };
|
|
}
|
|
return {
|
|
hunks: files.flatMap((file) =>
|
|
file.hunks.map((hunk) => {
|
|
let oldLineno = hunk.oldStart;
|
|
let newLineno = hunk.newStart;
|
|
const lines: RenderableFileDiffLine[] = [];
|
|
|
|
for (const rawLine of hunk.lines) {
|
|
if (rawLine.startsWith("\\")) continue;
|
|
const marker = rawLine[0];
|
|
const content = rawLine.slice(1);
|
|
if (marker === "+") {
|
|
lines.push({
|
|
kind: "add",
|
|
old_lineno: null,
|
|
new_lineno: newLineno,
|
|
content,
|
|
});
|
|
newLineno += 1;
|
|
continue;
|
|
}
|
|
if (marker === "-") {
|
|
lines.push({
|
|
kind: "delete",
|
|
old_lineno: oldLineno,
|
|
new_lineno: null,
|
|
content,
|
|
});
|
|
oldLineno += 1;
|
|
continue;
|
|
}
|
|
lines.push({
|
|
kind: "context",
|
|
old_lineno: oldLineno,
|
|
new_lineno: newLineno,
|
|
content: marker === " " ? content : rawLine,
|
|
});
|
|
oldLineno += 1;
|
|
newLineno += 1;
|
|
}
|
|
|
|
return {
|
|
old_start: hunk.oldStart,
|
|
old_lines: hunk.oldLines,
|
|
new_start: hunk.newStart,
|
|
new_lines: hunk.newLines,
|
|
lines,
|
|
};
|
|
}),
|
|
),
|
|
};
|
|
}
|