feat(web): state the run state on the terminal card's prompt line

The terminal card showed no run state: a running command and a settled
command that produced no output rendered the same prompt line, so whether
a command was still running had to be inferred from the absence of output.

Lead the prompt line with a StateDot in three of its states — the spinning
ring while running, red for the same exit status that renders the status
pill, green for a clean settle. That is the same indicator a tool row's
leading icon carries, so a row and its own card cannot disagree about one
command; the row/card agreement is pinned in the ui-conversation spec.
StateDot is aria-hidden, so a visually hidden text label rides beside it,
which is what the refreshed aria goldens now record.

The e2e adds what jsdom cannot compute: the dot's color resolves to the
green success token through the real theme stylesheet, and the dot precedes
the prompt label in document order.
This commit is contained in:
Chinesezjc
2026-07-28 16:41:04 +08:00
parent 540cb59585
commit f4c243c75f
18 changed files with 184 additions and 27 deletions
+12 -1
View File
@@ -120,9 +120,14 @@ function readCard(card: Element) {
text: expander.textContent,
expanded: expander.getAttribute('aria-expanded'),
},
// The run-state dot at the head of the prompt line, by its StateDot state.
runState: card.querySelector('[class*="_runState_"][data-state]')?.getAttribute('data-state') ?? null,
runStateLabel: card.querySelector('[class*="_runStateLabel_"]')?.textContent ?? null,
// Every color the ANSI parser emits resolves through a --dsw-* token, so
// the card follows the theme instead of painting literal terminal rgb.
colors: [...new Set([...card.querySelectorAll('span[style]')]
// Scoped to the output lines: the run-state dot is an inline-styled span
// too, and its geometry is not an ANSI-resolved color.
colors: [...new Set([...card.querySelectorAll('[class*="_line_"] span[style]')]
.map(span => span.getAttribute('style')))],
}
}
@@ -198,6 +203,8 @@ it('renders the keyed bash row with a resident terminal card', async () => {
"[exit code: 1]",
],
"prompt": "nested pnpm run check",
"runState": "error",
"runStateLabel": "失败",
"status": "退出码 1",
}
`)
@@ -229,6 +236,8 @@ it('the fallback row reaches the same card through its expand control', async ()
"-rw-r--r-- demo.txt",
],
"prompt": "fixture ls -la",
"runState": "done",
"runStateLabel": "已完成",
"status": null,
}
`)
@@ -318,6 +327,8 @@ it('the details panel Output section renders the same call at full height', asyn
],
"panelLines": 16,
"prompt": "nested pnpm run check",
"runState": "error",
"runStateLabel": "失败",
"status": "退出码 1",
}
`)