feat(sidechat): main-conversation Blocks, turn usage tail, reconnect banner

Rendering-layer upgrade for the Side Chat transcript (data already rides
the raw events; the mapping just stopped discarding it):

- Tool rows with a derivable structure now render the host's
  ui-primitives atoms instead of a generic double <pre>: bash calls map
  onto TerminalBlock (command from call args, output + exit pill
  recovered from the result's trailing exit marker), edit/write map onto
  DiffBlock (call-time literal replacement, refined by the result meta's
  contextual hunks), read maps onto ReadBlock (line-window meta, same
  semantic narrowing the host applies). Every narrowing declines to the
  generic row on malformed input.
- turn/end now emits a turnSummary row: token usage aggregated from
  assistant/message.usage (output summed across steps, input from the
  last request) plus the envelope-time wall duration, printed with the
  main conversation's formatTokens/formatDurationMs cadence.
- The client entry injects 'connection' (DSH 0.1.2-alpha.2+) and the
  thread view shows the host's ConnectionIndicator while the Remote
  transport is down; the reconnect control calls reconnect() and a
  disconnected -> connected transition pulls the transcript immediately
  instead of waiting for the next poll tick.

19 new locale keys propagated across zh/en and all 19 third-language
dictionaries; unit coverage in sidechat-transcript.spec and a new
sidechat-view render spec (jsdom). Real-host mount smoke: 14/14.
This commit is contained in:
Menghuan1918
2026-08-31 23:28:20 +08:00
parent d70db8fb02
commit 561ad66071
27 changed files with 1175 additions and 17 deletions
+17
View File
@@ -280,6 +280,23 @@
border-top: 1px solid var(--dsw-alias-hairline);
}
/* Host Block atoms (terminal/diff/read) inside a row body draw their own
* chrome; only a hair of breathing room is added on top. */
.sidechatRowBody > * {
margin-top: 2px;
}
/* Turn-tail metrics line: quiet, right-aligned, ink-weight only. */
.sidechatTurnSummary {
align-self: flex-end;
max-width: 88%;
padding: 0 2px;
font: var(--dsw-font-xxs-12);
font-variant-numeric: tabular-nums;
color: var(--dsw-alias-label-tertiary);
user-select: none;
}
/* Shimmer sweep text: generating (streaming row labels, creating hero). */
.sidechatShimmerText {
background-image: linear-gradient(