reporters/tui¶
Source: src/reporters/tui.ts
Formatting for the pi TUI, with no pi-tui in sight.
This file turns a {@link RunSnapshot} into strings and rows; the extension
draws them. Nothing here holds state - the picture is picture.ts, folded
once for every reader - so a line is tested by calling the function that
makes it, never by scraping a terminal.
callLine¶
function
export function callLine(call: ToolCall): string { /* … */ }
A call as a row lists it: {@link formatToolCall}, and when it came back an
error, ✗ first and pi’s words after, so a call pi refused never reads as
one that ran: ✗ write notes.txt · Tool write not found.
currentActivity¶
function
export function currentActivity(snapshot: SubagentSnapshot): string { /* … */ }
What a subagent is doing right now, in a few words.
The last tool call while it works; its verdict once it is done. This is the “minimal information” of the widget - enough to know it is alive and on the right track, not enough to read instead of the transcript.
detailLine¶
function
export function detailLine(snapshot: SubagentSnapshot, now?: number): string { /* … */ }
provider/model · ↑12k ↓209 · 12.4s, the tokens once its first turn has ended.
formatToolCall¶
function
export function formatToolCall(name: string, args: unknown): string { /* … */ }
Formats a tool call the way the pi TUI shows built-in tools.
$ cmd, read ~/path:1-10, grep /pat/ in ~/path - shapes a pi user
already reads without thinking. Anything unknown degrades to name arg=value
rather than dumping raw JSON at them.
progressLine¶
function
export function progressLine(snapshot: RunSnapshot): string { /* … */ }
2/3 done, 1 running - what a parallel run looks like while it runs.
standingOf¶
function
export function standingOf(snapshot: SubagentSnapshot): Standing { /* … */ }
Reads how a subagent stands off its snapshot.
The one place ok and status are folded into a word, so that a widget, a
card, a table and a console cannot each decide differently what a finished
failure looks like - they did, and one of them drew a tick on it.
statusColour¶
function
export function statusColour(standing: Standing): "error" | "success" | "warning" | "accent" { /* … */ }
The theme colour a standing is drawn in, by the name pi’s theme knows it under.
statusIcon¶
function
export function statusIcon(standing: Standing): string { /* … */ }
● while it lives, ✓ once it succeeded, ✗ once it failed.
summaryTable¶
function
export function summaryTable(snapshot: RunSnapshot, wallMs: number): string[] { /* … */ }
The end-of-workflow table: one line per subagent, total at the bottom.
wallMs is passed in because a snapshot cannot know it: on a fan-out the
elapsed time is not the sum of the branches, and that difference is the
whole point of the number.
A delegated subagent is indented under the one that asked for it, and the total is still the sum of every row: what ruins a run is what the tree cost altogether, never what one leaf of it cost.
WidgetRow¶
type
export type WidgetRow =
| {
kind: "activity";
icon: string;
status: Standing;
id: string;
activity: string;
/** Model, tokens and time, when they belong on this line rather than under it. */
detail?: string;
depth: number;
}
| { kind: "detail"; text: string; depth: number };
A dot per subagent, above the prompt - the Claude Code shape.
Two lines while it works: the dot with what it is doing, then a dimmed line with model, tokens and time. One line once it is over, because the second line of a finished subagent held its last tool call, which nobody needs any more; its numbers move up beside the tick instead. A fan-out of three took seven lines from the first dot to the last, and now shrinks as it finishes.
Colour is not applied here; the caller wraps the lines, because a colour code depends on a theme this file must not know about. It gets {@link widgetRows} instead, which says what each line is.
widgetRows¶
function
export function widgetRows(snapshot: RunSnapshot): WidgetRow[] { /* … */ }
The widget, as rows that say what they are.
Layout without colour, so it can be asserted on without a terminal. depth
is how far under a root the subagent sits; the caller turns it into indent,
because how wide a level is drawn is a decision about a terminal.