Adds a transcript surface for a Structured-view session alongside the existing xterm attach view: a WS /api/structured/:id connection (structured.ts) mounted by ConnectionPool whenever a session's `view` is `"Structured"`, and pure per-row/rail renderers (structuredRender.ts, structuredDiff.ts) covering all eight transcript row kinds. Hierarchy follows the design reference (artifact 88ecd690): the approval is the only lifted, card-like element; a user turn is a tinted block with an accent rail; agent prose is plain text; tool calls are compact bordered rows expanding to output or a coloured, horizontally-scrolling diff computed from ACP's full old/new text. The client renders `reduced_state` and rows exactly as received, with no raw-event folding or turn tracking of its own. Extracted attach.ts's pane-header title building into paneTitle.ts and its connection interface into pane.ts (PaneConnection) so both connection kinds share one contract and one header.
37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
// Pane header title: name/command echoing the sidebar card, shared by the
|
|
// xterm attach view (attach.ts) and the structured transcript view
|
|
// (structured.ts) so both panes read identically.
|
|
|
|
import { escapeHtml } from "./html.js";
|
|
import { splitCommand, toolIconSvg } from "./toolIcon.js";
|
|
import type { SessionView, Uuid } from "./types.js";
|
|
|
|
/** What a pane header shows about its session. Falls back to a short session
|
|
* id when the session isn't known yet. */
|
|
export interface AttachInfo {
|
|
name: string;
|
|
command: string;
|
|
/** Which connection kind to mount (#140). Absent/`"Terminal"` mounts the
|
|
* xterm attach; `"Structured"` mounts the transcript view. */
|
|
view?: SessionView;
|
|
}
|
|
|
|
function commandFragment(command: string): string {
|
|
const { tool, program } = splitCommand(command);
|
|
const icon = tool ? toolIconSvg(tool) : null;
|
|
const text = icon ? "" : program;
|
|
return `<span class="at-cmd">${icon ?? ""}${text ? escapeHtml(text) : ""}</span>`;
|
|
}
|
|
|
|
export function paneTitleHtml(sessionId: Uuid, info?: AttachInfo): string {
|
|
return info
|
|
? `<span class="at-name">${escapeHtml(info.name)}</span>` +
|
|
(info.command && info.command !== info.name ? commandFragment(info.command) : "")
|
|
: `session <span class="sid">${escapeHtml(sessionId.slice(0, 8))}</span>`;
|
|
}
|
|
|
|
/** Attribute-safe (`title="..."`) form of the same identity. */
|
|
export function paneTitleAttr(sessionId: Uuid, info?: AttachInfo): string {
|
|
return escapeHtml(info ? `${info.name} · ${info.command} (${sessionId})` : sessionId);
|
|
}
|