agent terminal: inline +/- diffs on Write and Edit tool calls

Write and Edit tool_use rows used to render as the bare file path. now
they're collapsed <details> blocks with the actual change inside —
Write shows every content line prefixed '+', Edit shows old_string as
'-' lines then new_string as '+' lines. summary carries the file path
+ counts ('→  Edit /foo · -3 +5'). lines colored via diff-add /
diff-del / diff-ctx; click to expand the full body.

renderFileWriteEdit returns null for any other tool so the existing
flat-row path (fmtToolUse) is untouched.
This commit is contained in:
müde 2026-05-15 20:23:22 +02:00
parent 2413d664a1
commit bc87ff80d2
3 changed files with 80 additions and 10 deletions

View file

@ -514,6 +514,63 @@
default: return name + ' ' + trim(JSON.stringify(input), 200);
}
}
// Build a tool_use row for Write/Edit as a collapsed <details>
// showing the actual change. Returns null for any other tool so
// the caller falls back to the flat-row path.
// Write: every input.content line is "+".
// Edit: old_string lines as "-", new_string lines as "+".
// Not a true diff algorithm — claude's Edit blocks are already a
// contiguous old/new pair, so a literal -/+ rendering is honest.
function renderFileWriteEdit(c) {
const name = c.name || '';
const input = c.input || {};
if (name !== 'Write' && name !== 'Edit') return null;
const path = input.file_path || '?';
let body;
let plus = 0;
let minus = 0;
if (name === 'Write') {
const content = String(input.content || '');
const lines = content.split('\n');
plus = lines.length;
body = lines.map(l => '+ ' + l).join('\n');
} else {
const oldLines = String(input.old_string || '').split('\n');
const newLines = String(input.new_string || '').split('\n');
minus = oldLines.length;
plus = newLines.length;
body = oldLines.map(l => '- ' + l).join('\n')
+ '\n'
+ newLines.map(l => '+ ' + l).join('\n');
}
const summary = '→ ' + name + ' ' + path + ' · '
+ (minus ? '-' + minus + ' ' : '') + '+' + plus;
return detailsDiff('tool-use', summary, body);
}
function detailsDiff(cls, summary, body) {
clearPlaceholder();
const d = document.createElement('details');
d.className = 'row ' + (cls || '') + (currentNoAnim ? ' no-anim' : '');
const s = document.createElement('summary');
s.textContent = summary;
d.appendChild(s);
const pre = document.createElement('pre');
pre.className = 'tool-body diff-body';
// Color each line by its leading +/-.
for (const line of body.split('\n')) {
const span = document.createElement('span');
if (line.startsWith('+ ')) span.className = 'diff-add';
else if (line.startsWith('- ')) span.className = 'diff-del';
else span.className = 'diff-ctx';
span.textContent = line + '\n';
pre.appendChild(span);
}
d.appendChild(pre);
log.appendChild(d);
afterAppend();
return d;
}
function renderToolResult(c) {
const txt = Array.isArray(c.content)
? c.content.map(p => p.text || '').join('')
@ -547,7 +604,13 @@
const txt = (c.thinking || c.text || '').trim();
row('thinking', txt ? '· ' + txt : '· thinking …');
}
else if (c.type === 'tool_use') row('tool-use', '→ ' + fmtToolUse(c));
else if (c.type === 'tool_use') {
// Write/Edit get a collapsed +/- diff body; everything
// else stays as the flat row produced by fmtToolUse.
if (!renderFileWriteEdit(c)) {
row('tool-use', '→ ' + fmtToolUse(c));
}
}
}
return;
}