Skip to content

feat(tui): violet chrome lock — reset background, zero rounded frames, macOS composites - #8

Open
echobt wants to merge 16 commits into
mainfrom
cursor/tui-violet-chrome-lock-a30a
Open

feat(tui): violet chrome lock — reset background, zero rounded frames, macOS composites#8
echobt wants to merge 16 commits into
mainfrom
cursor/tui-violet-chrome-lock-a30a

Conversation

@echobt

@echobt echobt commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

New chrome lock replacing the mint/#1A3330 chrome from #7, on top of current main (752666c). Do not merge — Mathis validates every state first.

Chrome (matches the designer boards)

  • Background = Color::Reset. Nothing paints a navy/VOID wash anywhere — the host terminal (black by default) shows through. VOID is now Color::Reset and the explicit bg(VOID) washes in the lock renderer, login screen, demo renderer and input widget are gone.
  • Zero rounded frames. The wide slash popup's ╭╮ box, the inline-form ROUNDED_BORDER, the overlay widgets' rounded border sets and the rasteriser's rounded canvas frame are all removed; the TUI bleeds to the terminal edges. A lock proof asserts no capture contains ╭╮╰╯. The square ┌ Ask — read-only ┐ and ┌ Bash mode ┐ mode chips are kept (they are chips, not frames) and pinned by mode_chips_are_kept.
  • Accent #A78BFA violet on the > prompt, selection carets, tile dots and checks (SUCCESS/ACCENT constants).
  • Selection bar #221A38 with white labels, never inverted. Only the > caret is violet on a selected row. All legacy inverted selections (model picker, approval overlay, selection list, command palette, sessions/models/commands/providers/theme modals, interactive tabs, help browser) now use light-on-SELECTION_BG.
  • Green only on +diff — and every +diff is green. DIFF_ADD (#4ADE80) is used by every +N of an Edit / Write / commit: state 10 Edit +9, state 24 queued Edit +58, state 30 MAX footer +214, state 39 Write +84, state 49 /diff plus column; -N stays dim. The queued Edit line (24) is the Edit tile's own format, ● Edit <path> +58 -0. The live view follows the same rule — tool-result summaries and approval-overlay change summaries colour only their +N tokens green (diff_stat_spans). The GREEN alias points at DIFF_ADD; all other former greens moved to the violet accent or neutral text.
  • Bans enforced by tests: #00F5D4, #1A3330, #00FFA3 and the #0A1628 navy wash are asserted absent from every scene at both sizes, green is asserted to appear only on +/digits, every_edit_plus_count_is_green scans every scene for +N tokens on Edit / Write / commit lines and requires the diff green, violet only on the marker set, and no inverted accent bar exists anywhere.

Model display names (TUI only, never slugs)

model_display_name() maps served ids to English product names at every render site — footer (KeyHints::with_model), /model pickers (widget + modal), /settings hub, /config, session lists, splash and all lock boards: cortex-1-miniCortex Mini 1, cortex-1Cortex 1, cortex-1-maxCortex Max 1. Served/API ids stay hyphenated internally (AppState::model, DEFAULT_MODEL, session meta). Lock proofs: model_slugs_never_shown bans cortex-1* in every scene; footer_shows_product_model_everywhere requires Cortex Mini 1 in the footer of every footered scene at both sizes (only the three login sub-states have no footer), and Cortex Mini 1 · MAX on the footer_max and /config boards at 40 columns (the context suffix and git branch drop first, never the model).

State 05 — full picker at 40 columns

model_full at 40×12 rendered the compact list, so its PNG was byte-identical to model_compact. The full picker is now the full picker at every size: a description under each of Cortex Mini 1 / Cortex 1 / Cortex Max 1 plus the ○ Low ● Medium ○ High Effort radios; at 40 columns the blank row under the prompt gives way so everything fits above the hints, and the MAX description uses its short form (Longest context — token billing.). Compact stays the short list. Lock proofs: model_full_is_the_full_picker_at_every_size (content + full ≠ compact at both sizes) and distinct_states_render_distinct_frames (every state is its own frame except the documented alias pairs clear/clear_confirm, compact/compacted, grep/tool_tiles, interrupt/stopped, login/login_select). palette.png was already a distinct slash palette at both sizes.

Copy audit — every 40×12 and 120×40 fixture

Root cause of the "one fragment / smashed words" screens: first_fitting_line/wrap_or_drop collapse whitespace and keep only the first wrapped line. Fixes:

  • New helpers fit_line (keeps column gaps and indentation, cuts only at a word boundary), wrap_keep_indent (code excerpts keep nesting), trim_dangling_separator, plus board helpers marker_lines / gutter_lines / ellipsis_fit_line.
  • Ask / streaming / mcp_call — code spans carry their own trailing space: estimateTokens(prompt) counts, usage.completion_tokens arrives, reconcileUsage() corrects, rateLimit() checks, ZADD records; ┐ Cortex will not…; API-184 Rate limit 429 body In Progress you. Lock proof no_smashed_tokens_anywhere scans every scene for ) glued to a letter.
  • 40 columns — bodies wrap at word boundaries instead of stopping at a fragment (working, plan, thinking, shell, sudo, cloud, quota, sandbox, mcp, resume, streaming, compacted, diagnostics, question, mode, permissions, footer_max, bash, config, first_run, help, queue, jobs, skills, btw, write, edit, grep/read/glob, task, todos). Permission option 2 still wraps …in this / project / Edit command; @files keeps full rateLimit.ts / rateLimits.json; todos/list stay camelCase rateLimit; 37 interrupt keeps the Read tiles then ✗ Stopped + 12s · 4.1k tokens · ctrl+c; 38 compact shows > /compact, Thread compacted, 86% → 12%, Summary kept; 40 clear is Start a new thread? · ● Clear thread / ○ Cancel; 48 diagnostics keeps error red / warn amber with gray message and path; 50 settings hub lists Model, Mode, Permissions, Sandbox, MCP, Config, Usage.
  • settings_empty — a real empty state: title, Search: zzzz-no-such-setting_, No settings match “…” — esc clears the search (two rows at 40 cols), the panel hints and the session footer (the footer now renders in interactive mode too).
  • session_empty / session_loading / session_error / palette_empty — chrome stays complete at both sizes: Cortex CLI v1.0.0, keystroke hints (also at 40 cols), composer, cwd + model footer; the transcript no longer disappears when the slash popup is open. A live run reads ⠇ Working · 0s · esc to interrupt and the composer ghost becomes Add a follow-up ↵ to queue. session_error is two lines — the product error, then Try again in a moment — your work so far is saved in this session. — emitted by the runtime error path as well as the lock. System notices stack without a blank line so 40×12 never overflows into a scrollbar. Lock proof live_states_keep_chrome_complete pins all of this.

Interactive TUI (not a frozen session)

  • cortex with no subcommand opens the TUI (main.rs TUI mode dispatch — unchanged).
  • stdin stays alive during a run: submitted text while streaming is queued (AppState::queue_message, event_loop/actions.rs), ESC clears the queue before interrupting. Lock proof session_stays_interactive_while_running renders a streaming session, queues a follow-up and asserts the composer plus the [1 pending] badge stay on screen.

Recaptures (committed binaries)

  • docs/media/tui-lock/{40x12,120x40}/*.png — all 64 scene captures (the 50 designer states plus locked aliases/login sub-states) re-rendered on the violet chrome with product model names and whole copy. The pipeline is deterministic, so a full recapture only changes bytes for states whose rendering changed; the latest round changed queue.png at both sizes (Edit-tile format).
  • docs/media/tui-lock/macos/{40x12,120x40}/*.png — every raw capture composited into the designer macOS chrome template: Sequoia ray-burst wallpaper, dark menu bar (Apple mark, Terminal menus, status icons, Fri May 10 14:32), Terminal.app window with traffic lights, cortex-api — cortex — 120×40 / 40×12 proxy-icon title, black content rect, rounded chrome on the macOS window only, native shadow. TUI pixels are never resampled: the chrome renders at 2.5× (2560×1708) so a 120×40 capture is pasted 1:1 into the content rect, and 40×12 captures are blown up by an integer 2× with nearest-neighbour sampling into a smaller content rect — every locked colour lands on the photo exactly (+58, +9, +214, +84 all sample #4ADE80 = (74,222,128); violet > and sample #A78BFA). Nothing is re-typed (scripts/compose-macos-terminal.py, wired into ./scripts/render-tui-lock.sh).

Spot-checks (raw / macOS):

State Raw macOS
01 splash splash raw splash macos
03 slash slash raw slash macos
04 /model compact model raw model macos
05 /model full model full raw model full macos
10 edit edit raw edit macos
12 permission permission raw permission macos
22 ask (mode chip kept) ask raw ask macos
24 queue (green +58) queue raw queue macos
24 queue 120×40 queue wide raw queue wide macos
30 footer_max footer max raw footer max macos
31 login login raw login macos
session_error error raw error macos
settings_empty settings empty raw settings empty macos
120×40 streaming streaming raw streaming macos

Layout of the 50 states is otherwise unchanged (20 slash rows, 2 login radios, 7-line settings hub) — the existing product-copy tests still pass.

Test plan

  • cargo fmt --all -- --check
  • ./scripts/clippy.sh
  • cargo test --workspace — 6,060 passed, 0 failed
  • TUI / snapshot tests for every surface this PR touches — 28 lock proofs incl. every_edit_plus_count_is_green, model_full_is_the_full_picker_at_every_size, distinct_states_render_distinct_frames, model_slugs_never_shown, footer_shows_product_model_everywhere, mode_chips_are_kept, no_smashed_tokens_anywhere, live_states_keep_chrome_complete, banned_colors_never_painted, green_is_reserved_for_diff_additions_everywhere, no_rounded_frame_glyphs_anywhere, session_stays_interactive_while_running; unit tests for diff_stat_spans, model_display_name, fit_line, wrap_keep_indent, trim_dangling_separator
  • cargo audit (clean)
  • ./scripts/check-cli-version.sh
  • Composite pixel audit: exact #4ADE80 counts on the macOS photos equal the raw counts (×4 for the 2× blow-up) for queue, edit, footer_max, write and multi_diff; zero #00F5D4 anywhere

Attestation (required)

I attest that:

  • Security reviewed — rendering/copy-only change; no auth, exec, sandbox, network or secret paths touched. No secrets, tokens, or keyring dumps are in the change.
  • Product-facing errorsThe coding service is temporarily unavailable now always comes with a product-facing next step; no raw provider, SDK, or transport names.
  • TUI verified — all touched surfaces exercised through the headless MockTerminal lock proofs and the recaptured PNGs at both sizes; every fixture audited as plain text for fragments, smashed tokens and model slugs, every +N checked for the diff green on raw and composite, and every state checked to be a distinct frame.
  • Tests added — new lock proofs and helper unit tests; existing snapshot/product-copy tests pass unmodified. No mocks that report success.
  • No secrets — none included.

Risk

Visual/copy-only re-theme plus committed media. No API-contract, exec-policy or release impact. The VOID → Color::Reset change means any future widget relying on a painted navy background will show the terminal's own background instead — that is the intended contract of this lock.

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

cursoragent and others added 16 commits September 1, 2026 19:47
Replace the mint/#1A3330 chrome: the TUI never paints its own background
(Color::Reset — host terminal black shows through), the accent is #A78BFA
violet on > prompts, selection carets, tile dots and checks, selection bars
are light text on #221A38 (never inverted), and green #4ADE80 is reserved
for + diff additions. #00F5D4, #00FFA3 and the navy wash are banned and
asserted against in the lock proofs. The wide slash popup, inline forms and
overlay widgets drop their rounded borders. The rasteriser stops drawing
the rounded canvas frame. Adds a macOS Terminal.app compositor script and
a lock proof that the session stays interactive (follow-ups queue) during
a run.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
All lock boards re-rendered at 40×12 and 120×40 on the new chrome: native
black background (Color::Reset), violet #A78BFA markers, #221A38 selection
bars, diff additions as the only green, and no rounded frame around any
capture. Layout, copy, wrap rules, the 20 slash rows, the 2 login radios,
the 7-line settings hub, the permission project wrap, camelCase rateLimit
and the red/amber diagnostics severities are unchanged.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Each raw capture is composited 1:1 into a photorealistic macOS
Terminal.app window — traffic lights, centered cortex-api — cortex — W×H
title, dark title bar, rounded window chrome (macOS window only, never the
TUI), native drop shadow — on a generated macOS desktop wallpaper. Both
sizes of all lock states, under docs/media/tui-lock/macos/{40x12,120x40}.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Rebuild the macOS set on the designer chrome template: Sequoia ray-burst
wallpaper, dark menu bar (Apple mark, Terminal menus, status icons, clock),
and the template's Terminal.app window with traffic lights and the
cortex-api — cortex — W×H proxy-icon title over a black content rect.
Every REAL capture is scaled uniformly into that rect — 120×40 fits the
rect height, 40×12 keeps the same chrome with a smaller content rect and
a 40×12 title. No TUI text is invented and the rounded corners stay on
the macOS window only. Rendered at 2x (2048×1366) retina scale.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Co-authored-by: Mathis <echobt@users.noreply.github.com>
Models render as English product names everywhere the user sees one —
Cortex Mini 1, Cortex 1, Cortex Max 1 — via model_display_name() in the
footer, /model pickers, /settings, /config, session lists and the lock
boards; served ids stay hyphenated internally. A lock proof bans slugs in
every scene.

Copy audit of all 40×12 and 120×40 fixtures: bodies wrap at word
boundaries instead of stopping at a fragment (fit_line keeps column gaps,
wrap_keep_indent keeps code nesting); code spans carry a trailing space so
estimateTokens(prompt) counts / rateLimit() checks never smash; list rows
end in an ellipsis; dangling separators are trimmed. Live session states
keep their chrome complete (version, hints, composer, footer — also in
interactive mode), a live run reads Working · 0s · esc to interrupt with an
Add a follow-up ↵ to queue ghost, the settings panel has a real empty
state, and the service-unavailable error is followed by what to do next
(runtime and lock). New lock proofs cover smashed tokens and live chrome.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
All raw 40×12 and 120×40 captures re-rendered: Cortex Mini 1 in every
footer and picker, wrapped bodies instead of fragments, spaced code spans,
indented excerpts, complete live-state chrome.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Co-authored-by: Mathis <echobt@users.noreply.github.com>
footer_max and /config share paint_max_footer: the right side is always
Cortex Mini 1 · MAX; when the context suffix or the git branch cannot fit
at 40 columns they drop first, never the model. Lock proofs pin the rule
(every footered scene names Cortex Mini 1 at both sizes) and keep the
square ┌ Ask — read-only ┐ / ┌ Bash mode ┐ mode chips, which are not
frames.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Full recapture of all states at 40×12 and 120×40, raw and macOS. Every
footer names Cortex Mini 1; only the footer_max and /config boards changed
bytes at 40×12 — the other states were already on the product name and
rasterise byte-identically.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
State 24 painted the in-progress Edit's +58 as plain text. The queue board
now uses the same DIFF_ADD green as the Edit tile (+9) and the MAX footer
(+214), with -0 dim. The live view gets the same rule: tool-result
summaries and approval-overlay change summaries colour only their +N
tokens green (never the -N beside them). A lock proof scans every scene
for +N tokens on Edit / Write / commit lines and requires the diff green.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Full recapture at 40×12 and 120×40, raw and macOS; only queue.png changed
bytes — every other state rasterises byte-identically.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
State 05 model_full rendered the compact list at 40×12, so its PNG was
byte-identical to model_compact. The full picker now keeps a description
under each model plus the Effort radios at every size — at 40 columns the
blank row under the prompt gives way and the MAX description uses its
short form. Lock proofs pin model_full ≠ model_compact with the full
content at both sizes, and require every state to render a distinct frame
except the documented alias pairs.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
Full recapture at 40×12 and 120×40, raw and macOS; only model_full.png at
40×12 changed bytes (raw + macOS) — 120×40 model_full and palette.png were
already correct and rasterise byte-identically.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
…e format

The macOS compositor resampled every capture (LANCZOS 0.81x / 1.5x), so a
thin +58 blended with black and sampled grayish even though the raw TTY
painted it DIFF_ADD. TUI pixels are no longer resampled: the chrome renders
at 2.5x so a 120x40 capture is pasted 1:1, and 40x12 captures are blown up
by an integer 2x with nearest-neighbour sampling. Every locked colour now
lands on the composite exactly — +58, +9, +214, +84 all read #4ADE80.

State 24's queued Edit line is now the Edit tile's own format,
● Edit <path> +58 -0 (no separator), with +58 in the diff green and -0 dim;
a lock proof pins the format at both sizes.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
queue.png changes bytes at 40x12 and 120x40 (raw + macOS); every macOS
composite is regenerated pixel-exact at 2.5x. No other raw state changed.

Co-authored-by: Mathis <echobt@users.noreply.github.com>
@echobt
echobt marked this pull request as ready for review September 1, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants