The web app7 of 12
The Terminal panel
On this page
The Terminal panel is a read-only record of what she did. It is not a shell.
Screenshot placeholder: the Terminal panel in the left rail — three step cards, each with a coloured type chip (
BASH,PYTHON,MCP), a monospace command line, a status disc on the right, and one card expanded to show a dark console block with a "Hide full output" pill under it.
There is nothing to type into
The panel renders a list of step cards and nothing else. It has no input, no prompt and no command
box (components/panels/TerminalPanel.tsx:115-149). You cannot run a command from the browser.
Everything on it is something she ran, and everything she runs goes through the approval gate before it runs. That gate is the approval card described in The approval card, not this panel.
The panel opens itself when a work run starts (CompanionExperience.tsx:244), and the terminal button
in the dock pulses while she is working with the panel shut.
What a card shows
Each card is one tool call (TerminalPanel.tsx:70-113):
- A type chip. Eight kinds, each with its own colour and icon (
TerminalPanel.tsx:19-29):bash,python,web,file,mcp,skill,memory,tool. - The action, in monospace, on one line, with the full text as a tooltip.
- A status mark, or a spinner while it is still running.
- A console block with the output, on a dark ground tinted by the outcome.
- Show full output, when there is more than the card is showing.
The seven endings
A tick is the narrowest claim on the panel: the command ran and the process reported success. Every
other way a row can end has its own mark (TerminalPanel.tsx:31-38):
| Mark | Meaning | Tooltip |
|---|---|---|
| spinner | still running | — |
✓ green | ran and finished cleanly | ran and finished cleanly |
× red | ran and failed | ran and failed |
⊘ grey | never ran — the reason is below | never ran — the reason is below |
■ grey | stopped while it was running | stopped while it was running |
… yellow | waiting for your approval — it hasn't run | waiting for your approval — it hasn't run |
? grey | it ended, but nothing said how | it ended, but nothing said how |
A refusal and an interruption are deliberately grey. Neither is a fault, and painting your own "No"
red would report your decision as a malfunction (TerminalPanel.tsx:1-10).
The ending is told, never inferred (lib/store.ts:60-71). A non-zero exit, a command killed at its
timeout and an action you refused all return non-empty text, so reading "did it return anything" once
gave all three a green tick. An outcome this build has never heard of is unknown, and never ok —
a mark nobody chose must look like one.
That rule is pinned by a test that drives the real store through all of it, including the case where a
deferred command is completed minutes later from outside the turn
(tests/terminal-status.test.mjs).
Show full output
The card's summary line is the backend's own, unwidened. When the tool returned more than that, a
Show full output pill appears and opens the rest in the same console block
(TerminalPanel.tsx:63-68, 100-110).
This exists because a 23-line directory listing reached the card as one line of 18 characters, and
nothing on screen could tell a right answer from a confident wrong one
(tests/terminal-full-output.test.mjs:1-9). The control appears only when there is genuinely more to
show — the comparison is made after the same tidying the summary gets, so exit=0 framing alone does
not count as "more".
Tool output reaches the DOM as a text child and never as markup. There is no dangerouslySetInnerHTML
anywhere in the panel, and a test asserts it (tests/terminal-full-output.test.mjs:56-57).
What the panel keeps
The last 200 rows (lib/store.ts:226). Older rows are dropped.
Everything is cleared when the call ends (lib/store.ts:293-296). The panel is a live record of the
current call, not an archive. If you need what a command produced after the fact, the artefact it
wrote is in Files.
