agent-ui: real fixed-width icon column for terminal rows
Replaces the first-character-glyph + negative-text-indent trick (which let a wide emoji or a leading disclosure caret knock the icon out of column) with a genuine icon cell. terminal.js: row() / details() / detailsDiff() take an optional `icon` that goes in a fixed-width `.row-glyph` element (inline-block, 1.4em). Details summaries wrap their text in a `.summary-text` span; the disclosure caret moves to `.summary-text::before` so it leads the text, not the icon — keeping the icon in the shared column. terminal.css carries the cell + caret rules. app.js passes the per-tool emoji as `icon` for the flat tool-use row and every expandable tool summary (Write/Edit/send/ask/answer/bash) plus the 💭 thinking row, instead of string-prefixing it. A details `🖥️` now lines up under a flat row's `🧠` regardless of emoji width. Doc: terminal-rendering.md layout contract updated. Closes #1844.
This commit is contained in:
parent
0c48caff1e
commit
1c47bd4333
4 changed files with 106 additions and 50 deletions
|
|
@ -1439,8 +1439,8 @@ window.marked = marked;
|
|||
// Used by send / ask / answer tool_use renderers and by `recv`
|
||||
// tool_result so message-bearing rows show their content inline
|
||||
// without an extra click.
|
||||
function detailsOpenMd(api, cls, summary, body) {
|
||||
const d = api.details(cls, summary, '');
|
||||
function detailsOpenMd(api, cls, summary, body, icon) {
|
||||
const d = api.details(cls, summary, '', icon);
|
||||
d.open = true;
|
||||
const pre = d.querySelector('pre.tool-body');
|
||||
if (pre) {
|
||||
|
|
@ -1592,13 +1592,13 @@ window.marked = marked;
|
|||
+ '\n'
|
||||
+ newLines.map(l => '+ ' + l).join('\n');
|
||||
}
|
||||
// Summaries on expandable rows omit the row's directional glyph
|
||||
// (`→`) — the disclosure marker (`▸/▾`) from CSS sits in the
|
||||
// prefix column for every row kind, and the row's cyan colour
|
||||
// already signals "outbound tool".
|
||||
const summary = toolIcon(name) + ' ' + name + ' ' + path + ' · '
|
||||
// The tool icon goes in the shared `.row-glyph` cell (4th arg) so it
|
||||
// lines up with flat-row icons; the summary text carries no
|
||||
// directional `→` (the row's cyan colour signals "outbound tool" and
|
||||
// the CSS disclosure caret leads the text).
|
||||
const summary = name + ' ' + path + ' · '
|
||||
+ (minus ? '-' + minus + ' ' : '') + '+' + plus;
|
||||
return api.detailsDiff('tool-use', summary, body);
|
||||
return api.detailsDiff('tool-use', summary, body, toolIcon(name));
|
||||
}
|
||||
// Message-bearing tools render default-open with a markdown body so
|
||||
// the operator sees the content without an extra click. send / ask
|
||||
|
|
@ -1608,16 +1608,16 @@ window.marked = marked;
|
|||
const body = String(input.body || '');
|
||||
const lines = body.split('\n').length;
|
||||
return detailsOpenMd(api, 'tool-use',
|
||||
toolIcon(name) + ' send → ' + to + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
body);
|
||||
'send → ' + to + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
body, toolIcon(name));
|
||||
}
|
||||
if (name === 'mcp__hyperhive__ask') {
|
||||
const to = input.to || 'operator';
|
||||
const q = String(input.question || '');
|
||||
const lines = q.split('\n').length;
|
||||
const d = detailsOpenMd(api, 'tool-use',
|
||||
toolIcon(name) + ' ask → ' + to + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
q);
|
||||
'ask → ' + to + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
q, toolIcon(name));
|
||||
// When the ask targets the operator, mount an inline answer
|
||||
// slot in the live terminal — see docs/web-ui.md::Per-agent
|
||||
// page (Ask → operator inline-answer binding) for the slot
|
||||
|
|
@ -1646,8 +1646,8 @@ window.marked = marked;
|
|||
const a = String(input.answer || '');
|
||||
const lines = a.split('\n').length;
|
||||
return detailsOpenMd(api, 'tool-use',
|
||||
toolIcon(name) + ' answer #' + id + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
a);
|
||||
'answer #' + id + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
a, toolIcon(name));
|
||||
}
|
||||
// Bash task runner — show full command in an expandable pre block so
|
||||
// multi-line scripts are readable. Summary uses the first line so the
|
||||
|
|
@ -1655,8 +1655,8 @@ window.marked = marked;
|
|||
if (name === 'mcp__bash__run') {
|
||||
const cmd = String(input.cmd || '');
|
||||
const firstLine = cmd.split('\n')[0];
|
||||
const summary = toolIcon(name) + ' run* $ ' + trim(firstLine.trim(), 72);
|
||||
return api.details('tool-use', summary, '$ ' + cmd);
|
||||
const summary = 'run* $ ' + trim(firstLine.trim(), 72);
|
||||
return api.details('tool-use', summary, '$ ' + cmd, toolIcon(name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1803,12 +1803,12 @@ window.marked = marked;
|
|||
}
|
||||
else if (c.type === 'thinking') {
|
||||
const txt = (c.thinking || c.text || '').trim();
|
||||
api.row('thinking', txt ? '💭 ' + txt : '💭 thinking …');
|
||||
api.row('thinking', txt || 'thinking …', '💭');
|
||||
}
|
||||
else if (c.type === 'tool_use') {
|
||||
if (c.id && c.name) toolNameById.set(c.id, c.name);
|
||||
if (!renderRichToolUse(c, api)) {
|
||||
api.row('tool-use', toolIcon(c.name) + ' ' + fmtToolUse(c));
|
||||
api.row('tool-use', fmtToolUse(c), toolIcon(c.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue