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
+13
View File
@@ -522,6 +522,19 @@ export interface SidebarContextShape {
sessionTitle: SidebarSessionTitleService
/** The host session-persistence service (optional; side chat cold resume). */
sessionPersistence: SidebarSessionPersistenceService
/**
* The client connection lifecycle (DSH 0.1.2-alpha.2+; optional so older
* hosts and test fakes simply hide the disconnect banner): the observable
* recovery state of the Remote transport (`undefined` before the first
* connection outcome) and an immediate-reconnect request.
*/
connection?: {
state: {
getSnapshot(): 'connected' | 'disconnected' | 'connecting' | undefined
subscribe(listener: () => void): () => void
}
reconnect(): void
}
/** The composer draft face (client ui-conversation, lazy `ctx.get` probe). */
conversation: SidebarConversation
/**