mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-07-09 17:19:02 +00:00
* feat(web-shell): reveal full tool detail and auto-collapse finished tools Long tool descriptions were hard-capped at 120 characters and finished tools (shell/edit/write) stayed expanded indefinitely, so commands were unreadable and the transcript filled with stale output. - Lift the 120-char description cap so the full command/path reaches the DOM; collapsed rows ellipsise via CSS (adapts to width) and a click reflows the full text into a wrapped block below the header. - Add a leading disclosure chevron; any row with detail output or a long description is now expandable. - Auto-collapse a tool to its one-line summary once it completes successfully. Running tools stay expanded (live output) and failures stay expanded (error visible); agents keep their own manual expand state. * fix(web-shell): preserve manual expand on completion; correct auto-expand comment Review feedback on #5088: - shouldAutoExpand: rewrite the comment to match the code. Only the verbose kinds (shell/edit/write/ask) auto-expand and stay expanded on failure; other kinds are collapsed by default (their summary line shows the outcome and they stay click-to-expand). Force-expanding every failed tool was rejected because tools without an expanded-detail renderer would then hide the summary line and show an empty body — i.e. hide the error. - Auto-collapse-on-completion no longer overrides an explicit user toggle: a userToggledRef latch (set on header click, reset on tool-identity change) guards the collapse effect, so a row the user expanded/collapsed keeps its state when the tool finishes. * test(web-shell): assert tool-detail relocation via DOM, not textContent Review feedback (#5088): the expand test asserted container.textContent contains the command before and after the click, which passes regardless of whether the description is relocated from the header span to the wrapped block (textContent concatenates the whole subtree). Assert the DOM move instead — the command is in a leaf <span> while collapsed and in none while expanded — so a regression dropping the relocation now fails the test.
245 lines
3.8 KiB
CSS
245 lines
3.8 KiB
CSS
.group {
|
|
margin-bottom: 12px;
|
|
margin-left: 14px;
|
|
padding: 8px 14px;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: var(--radius);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
min-width: 0;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.line {
|
|
padding: 2px 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
.lineMain {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
}
|
|
|
|
/* Leading disclosure column. Rendered (blank) for every tool row so names stay
|
|
aligned; shows ▸/▾ only when the row can expand. */
|
|
.lineToggle {
|
|
width: 12px;
|
|
flex-shrink: 0;
|
|
font-size: 10px;
|
|
line-height: 1;
|
|
color: var(--text-dimmed);
|
|
text-align: center;
|
|
user-select: none;
|
|
}
|
|
|
|
.icon {
|
|
font-size: 13px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.iconDone {
|
|
color: var(--success-color);
|
|
}
|
|
|
|
.iconError {
|
|
color: var(--error-color);
|
|
}
|
|
|
|
.iconPending {
|
|
color: var(--text-dimmed);
|
|
}
|
|
|
|
.iconSpin {
|
|
color: var(--warning-color);
|
|
display: inline-block;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
.lineName {
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
font-size: 13px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.lineArg {
|
|
color: var(--text-secondary);
|
|
font-size: 13px;
|
|
min-width: 0;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.lineElapsed {
|
|
margin-left: auto;
|
|
color: var(--text-dimmed);
|
|
font-size: 12px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.lineExpandable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.lineExpandable:hover .lineName {
|
|
color: var(--accent-color);
|
|
}
|
|
|
|
.lineChevron {
|
|
font-size: 10px;
|
|
color: var(--text-dimmed);
|
|
flex-shrink: 0;
|
|
margin-left: 6px;
|
|
}
|
|
|
|
.agentSummary {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
margin-left: 22px;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.lineOutput {
|
|
margin-left: 16px;
|
|
font-size: 12px;
|
|
color: var(--text-dimmed);
|
|
white-space: pre-wrap;
|
|
overflow-wrap: anywhere;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
/* Full, wrapped tool argument shown below the header when the row is expanded
|
|
(the header drops its single-line ellipsised copy). Aligns with the expanded
|
|
output block below it. */
|
|
.lineFullArg {
|
|
margin-left: 16px;
|
|
margin-top: 2px;
|
|
font-size: 12px;
|
|
line-height: 1.4;
|
|
color: var(--text-secondary);
|
|
font-family: var(--font-mono);
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.lineDetail {
|
|
}
|
|
|
|
.expandedBash,
|
|
.expandedRead {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.expandedOutput {
|
|
padding: 0px 0px 0 16px;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
color: var(--text-secondary);
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
overflow-x: auto;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.expandedEdit {
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.expandedWrite {
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.writeAdd {
|
|
color: var(--success-color);
|
|
}
|
|
|
|
.expandBtn {
|
|
display: block;
|
|
width: 100%;
|
|
padding: 3px 10px;
|
|
margin-top: 10px;
|
|
font-size: 11px;
|
|
font-family: var(--font-mono);
|
|
background: var(--subtle-bg);
|
|
border: none;
|
|
color: var(--text-dimmed);
|
|
cursor: pointer;
|
|
text-align: left;
|
|
}
|
|
|
|
.expandBtn:hover {
|
|
color: var(--accent-color);
|
|
background: var(--info-bg);
|
|
}
|
|
|
|
.todoList {
|
|
padding: 6px 0 4px 24px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.todoItem {
|
|
font-size: 13px;
|
|
font-family: var(--font-mono);
|
|
line-height: 1.6;
|
|
padding-left: 4px;
|
|
}
|
|
|
|
.todoDone {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.todoActive {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.todoPending {
|
|
color: var(--text-dimmed);
|
|
}
|
|
|
|
.compactGroup {
|
|
margin-bottom: 12px;
|
|
margin-left: 14px;
|
|
padding: 8px 14px;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: var(--radius);
|
|
}
|
|
|
|
.compactHeader {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 8px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.compactCount {
|
|
color: var(--text-dimmed);
|
|
font-size: 13px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.compactHint {
|
|
font-size: 12px;
|
|
color: var(--text-dimmed);
|
|
margin-top: 4px;
|
|
}
|