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:
parent
2413d664a1
commit
bc87ff80d2
3 changed files with 80 additions and 10 deletions
9
TODO.md
9
TODO.md
|
|
@ -42,15 +42,6 @@ Pick anything from here when relevant. Cross-cutting design notes live in
|
||||||
`GET /api/state` (`status: "thinking" | "idle" | "compacting" |
|
`GET /api/state` (`status: "thinking" | "idle" | "compacting" |
|
||||||
"napping"`). JS just renders. Drops the
|
"napping"`). JS just renders. Drops the
|
||||||
derive-from-events-and-pray code path.
|
derive-from-events-and-pray code path.
|
||||||
- **Terminal: inline diffs for Write/Edit.** Today a `Write` /
|
|
||||||
`Edit` tool-use row just shows the file path. Render the actual
|
|
||||||
change inline in the terminal: for `Edit`, a small `+`/`-`
|
|
||||||
per-line diff between `input.old_string` and `input.new_string`;
|
|
||||||
for `Write`, the first few lines of `input.content` (it's all
|
|
||||||
"+"). Keep collapsed by default (`<details>` like the existing
|
|
||||||
tool_result rollups), expand to full diff on click. Color via
|
|
||||||
the same `.diff-add` / `.diff-del` classes the dashboard
|
|
||||||
approval diff already uses.
|
|
||||||
- **Terminal: `/model` slash command.** Operator-typeable model
|
- **Terminal: `/model` slash command.** Operator-typeable model
|
||||||
override from the terminal. Depends on the model-override work
|
override from the terminal. Depends on the model-override work
|
||||||
above; once an override mechanism exists, wire a `/model <name>`
|
above; once an override mechanism exists, wire a `/model <name>`
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,22 @@ details.row > summary::before {
|
||||||
}
|
}
|
||||||
details.row[open] > summary::before { content: '▾ '; }
|
details.row[open] > summary::before { content: '▾ '; }
|
||||||
details.row.tool-result-block > summary { color: var(--muted); }
|
details.row.tool-result-block > summary { color: var(--muted); }
|
||||||
|
/* Inline diff body for Write / Edit tool_use rows: same shape as
|
||||||
|
tool-body but each line is wrapped in a span with diff-add /
|
||||||
|
diff-del / diff-ctx so + / - lines are colored. */
|
||||||
|
details.row > pre.diff-body {
|
||||||
|
margin: 0.3em 0 0.4em 1.2em;
|
||||||
|
padding: 0.4em 0.6em;
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
border-left: 2px solid var(--purple-dim);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
max-height: 22em;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
details.row > pre.diff-body .diff-add { color: var(--green); }
|
||||||
|
details.row > pre.diff-body .diff-del { color: var(--red); }
|
||||||
|
details.row > pre.diff-body .diff-ctx { color: var(--fg); }
|
||||||
details.row > pre.tool-body {
|
details.row > pre.tool-body {
|
||||||
margin: 0.3em 0 0.4em 1.2em;
|
margin: 0.3em 0 0.4em 1.2em;
|
||||||
padding: 0.4em 0.6em;
|
padding: 0.4em 0.6em;
|
||||||
|
|
|
||||||
|
|
@ -514,6 +514,63 @@
|
||||||
default: return name + ' ' + trim(JSON.stringify(input), 200);
|
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) {
|
function renderToolResult(c) {
|
||||||
const txt = Array.isArray(c.content)
|
const txt = Array.isArray(c.content)
|
||||||
? c.content.map(p => p.text || '').join('')
|
? c.content.map(p => p.text || '').join('')
|
||||||
|
|
@ -547,7 +604,13 @@
|
||||||
const txt = (c.thinking || c.text || '').trim();
|
const txt = (c.thinking || c.text || '').trim();
|
||||||
row('thinking', txt ? '· ' + txt : '· thinking …');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue