--- date: 2026-10-19 pr: pending feature: Terminal CYBER theme, Nerd Font fallback, and bounded reconnect impact: The chat tool panel's Terminal tab now paints from the CYBER token set instead of a hardcoded One Dark palette, resolves its font through a Nerd Font stack so shell prompts stop rendering as tofu boxes, and stops reconnecting after three failed attempts with an inline retry instead of looping forever. No WebSocket message names, payload shapes, or session lifecycle behavior changed. --- # Terminal brought onto the CYBER token set The terminal was the last surface in the chat tool panel still wearing someone else's design system. Three defects, in order of how visible they were. ## Tofu boxes in the prompt The font stack was `Menlo, Monaco, "Courier New", monospace`. A default zsh prompt (powerlevel10k, oh-my-zsh) draws its separators, arrows and branch marks from the Unicode private use area — `U+E0A0` through `U+E0D4`. None of those fonts carry those glyphs, so the browser fell back to drawing notdef boxes for the entire prompt line. The `~` and the path after it rendered fine, which is what made it read as a font bug rather than a missing-glyph bug. The stack now names Nerd Font variants explicitly, in `variables.scss` as `--font-mono`. It is a CSS custom property rather than only an SCSS variable because xterm reads it from JS at `Terminal` construction time. ## Colors came from a different product Both terminal components carried their own copy of the palette — four themes in `TerminalPanel.vue`, fifteen in `TerminalView.vue`, drifting from each other, all of them third-party themes with a `#1a1a2e` default that appears nowhere in the token set. Changing `--code-bg` did nothing to the terminal, because the terminal never read a token. Both now import `utils/hermes/terminal-theme.ts`, which holds a CYBER theme built from the tokens plus two user-selectable alternates. The mapping is recorded in that file: `--bg-input` for the background, `--text-secondary` for foreground, `--accent-primary` for the cursor, and `--error` / `--success` / `--warning` / `--accent-info` mapped onto red / green / yellow / blue so an error in the terminal is the same red as an error anywhere else. xterm's `ITheme` only accepts hex, so the OKLCH values were converted rather than interpolated. The conversion is documented per-color; changing a token means updating that file too, which is a real coupling and the reason the comment says so. Note the tradeoff on ANSI `cyan`: it is deliberately *not* the accent cyan. `--accent-primary` at full strength reads as UI chrome, and a terminal where every cyan prompt fragment glows competes with the actual UI. The accent is spent on the cursor, and `brightCyan` carries it for text. ## Reconnect looped forever `TerminalView.vue` reconnected on a bare `setTimeout` with no attempt cap and no error surface, so an unreachable backend produced an invisible retry every three seconds indefinitely. `TerminalPanel.vue` already capped at three attempts and rendered a retry affordance; `TerminalView.vue` now does the same, sharing the same cap and the same `connectionFailed` / `connectionClosed` / `connectionError` strings. The counter resets when a session is successfully created, so a transient blip does not permanently exhaust the budget. Two smaller items came out of the same pass: `ws.onopen` was assigned twice in `TerminalView.vue` with the first assignment dead, and the header used a `21px` vertical padding that was on no spacing scale. Both are gone. ## Not changed The session list, theme picker, and new-terminal button stay. The static prototype has no equivalent of any of them, and deleting working features to match a mock is the inverse of the problem worth solving. ## Verification `npm run harness:check`, `npm run test` and `npm run build` pass. The existing `tests/e2e/terminal.spec.ts` still passes unchanged — it asserts the WebSocket URL carries the token, that `create` is sent, that keyboard input is forwarded, and that a `resize` with non-zero cols/rows arrives. Those four are exactly the behaviors this change had to preserve.