Skip to content

Release v4.3.0 - #24

Merged
countzero merged 4 commits into
mainfrom
develop
Sep 21, 2026
Merged

countzero merged 4 commits into
mainfrom
develop

Conversation

@countzero

Copy link
Copy Markdown
Owner

Two changes to how the watch frame sits in the terminal window, plus a changelog cleanup. sca monitor and sca usage -Watch left a dark strip along the window's right and bottom edges under a named SCA_THEME: the pixel remainder of window_size % cell_size, which the terminal paints from its own default background and which per-cell SGR cannot reach at all. The same frame also sat flush against the window on every side, the alternate screen having no prompt or margin of its own to lift it off.

Upgrading is otherwise replacing the one file, with one thing worth knowing: under a named SCA_THEME the watch now sets the terminal's own background color with OSC 11 and resets it with OSC 111 on exit. That is state outside the alternate screen buffer. The default theme and -NoColor / NO_COLOR never touch it.

4.3.0

  • Set the terminal's default background to the theme's base00 for the duration of a watch, so the unreachable pixel gutter matches the canvas instead of seaming against it.
  • Reset that background on exit, and only where the entry actually set one, so a background the user set on their own terminal is never discarded.
  • Inset the watch frame one row and two columns from the window edge, the table body's own indent unchanged so the header-to-row relationship is preserved.
  • Added Get-RenderWidth, splitting "what may I lay out in" from Get-ConsoleWidth's "how wide is the terminal", so right-aligned content stays inside the inset instead of wrapping.
  • Dropped the "Upgrading is replacing one file" opener from the changelog notices, and recorded in docs/conventions.md the two Common Changelog §2.3 limits it was breaking.

Not breaking. Minor rather than patch because the inset moves where existing output lands and the OSC 11 reaches state the tool has never touched before.

Why OSC 11 at all

Terminals render on a character grid and a window is rarely a whole number of cells. ESC[K and ESC[0J fill with the current background but address cells, so the remainder strip is unreachable by construction, no matter how the frame is painted. Moving the terminal's default is the only lever an application has. Windows Terminal declined to paint the gutter from the adjacent cells (microsoft/terminal#19860, closed as not-planned), so this is not a stopgap waiting on an upstream fix.

Shortcomings

  • OSC 11 outlives a hard kill. Exit-WatchTerminal restores it in a finally, which covers Ctrl-C and a throw, but a taskkill or a closed pty leaves the tab tinted until it is closed. The alt buffer has always had the same exposure; a tinted tab is arguably the less obvious of the two to recover from.
  • One color for the whole gutter. OSC 11 sets a single value. Today the frame has one background so it matches exactly, but any future second surface color would leave one of the two seaming again.
  • No capability probe, deliberately, matching the existing truecolor decision. PuTTY and Zellij ignore OSC 11 silently, so their users keep the seam. No regression, but no fix either.
  • The inset is a fixed 2/1 with no knob. It costs four columns of table width, which matters only on a terminal already too narrow for the table.
  • $Script:FramePadColumns / FramePadRows are ambient. Write-WatchFrame is the sole owner and the sole frame painter, so this is currently sound, but a future renderer that paints a frame without going through it would silently get 0 rather than fail.
  • One defensive branch in Get-WatchBackgroundOsc is unreachable while the suite pins BackgroundRgb to Background. It is kept because without it a hand-written palette missing BackgroundRgb would emit rgb:00/00/00 and tint the terminal black rather than do nothing. It shows up in the coverage residue.

Feedback wanted

  • Sanity-check the OSC 111 ordering. It is written before ESC[?1049l, on the reasoning that the alt screen's cells all carry chrome so the reset shows for one frame in the gutter alone, whereas after the leave it would flash the theme background across the restored scrollback. That is reasoned, not measured.
  • Argue with the ambient pad pair. The alternative was threading an inset parameter through Format-UsageFrame → Format-UsageTable → Write-UsageTableHeader, all of which also serve non-watch callers that would pass 0. I think ambient is right here and would like it challenged.
  • The 4.2.0 notice was deleted, not edited. That rewrites a published entry, and §2.2 wants the changelog entry and the GitHub release to carry the same content. Common Changelog §6.5 permits the rewrite; confirm you want the published 4.2.0 release notes left as they are.

What is not done

  • Not verified against a live sca monitor. Every action here writes the real ~/.claude, so the suite proves the byte sequences and nothing proves the strips are actually gone on screen. That check is yours to make. If they persist, the remaining suspect is the Windows Terminal padding profile setting rather than the sub-cell gutter, which is a settings.json fix and not a code one.
  • tests/Invoke-WatchPtyProbe.ps1 was not extended. It would be the one real end-to-end proof, but it runs themeless, so an OSC 11 marker would simply MISS; proving anything needs SCA_THEME plumbed into the probe's inner run first.
  • docs/images/ was not re-rendered. The README scenes are hand-authored literals in tools/Render-ReadmeImages.ps1, not captures, and freeze already draws its own canvas margin, so adding the inset there would read as double padding.
  • The full suite passes on Windows with coverage at 98.7% against the 97% gate. Linux and macOS are CI's to confirm.

A terminal renders on a character grid, so a window whose pixel width or
height is not a whole multiple of the cell size keeps the remainder as an
unpainted strip along its right and bottom edges. The chrome cannot reach
it: SGR and back_color_erase address cells, so neither the per-line ESC[K
nor the trailing ESC[0J touches that strip, and the terminal fills it from
its own default background instead. Against a themed canvas the seam is
plainly visible, and worst when the window is maximized or snapped, where
snapping the window to the character grid is not an option.

OSC 11 moves the terminal's default background to the theme's base00, which
is the only lever an application has here. Windows Terminal declined to
paint the gutter from the adjacent cells (microsoft/terminal#19860, closed
as not-planned), so this is not a stopgap awaiting an upstream fix.

Three properties are load-bearing. The guard derives from Get-WatchChrome
rather than restating its conditions, because the gutter and the canvas have
to agree in every case and one predicate is the only way to guarantee that.
The OSC 111 reset is conditional on the entry having emitted an OSC 11:
under the default theme sca never moves the background, so resetting anyway
would discard one the user set on their own terminal before launching. And
the reset is written before ESC[?1049l, where it shows for one frame in the
gutter alone; after the alt-buffer leave it would instead flash the theme
background across the restored scrollback.
The alternate screen has no prompt or margin of its own, so the frame sat
flush against the window on every side. Two columns and one row lift it off,
which is enough to read as a deliberate canvas and small enough that the
table still fits the 80-column terminal its column widths are measured
against. Only the top and left are written: the right edge is already
reached by each line's ESC[K and the bottom by the trailing ESC[0J, both of
which fill with chrome.

The inset cannot be a pure post-transform. Write-UsageTableHeader and the
aggregate-bar clamp right-align against the terminal width and reserve a
single column, so indenting a frame laid out against the raw width would
push the -Auto indicator two columns past the right edge and wrap it.
Get-RenderWidth answers what a renderer may lay out in, leaving
Get-ConsoleWidth honest about the terminal; both existing call sites move
over, and an unknown width (0) still propagates unchanged.

The value is ambient rather than a parameter because its two consumers sit
at opposite ends of the render: the transform, which applies it, and layout
code several frames deep inside the renderer. Threading it would put a
presentation argument on Format-UsageFrame, Format-UsageTable and
Write-UsageTableHeader, all three of which are also reached from non-watch
callers that would have to pass 0. Write-WatchFrame owns the window,
raising the pair for one paint and dropping it in a finally, so every
scrollback renderer still sees 0 and `sca list` / `sca save` / one-shot
`sca usage` stay flush left, where an indent would be noise and would break
copy-paste.
The italic line under a version heading is Common Changelog's notice (2.3),
and three releases opened theirs with "Upgrading is replacing one file".
That is not a property of any release: it is what upgrading always is for a
single-file tool, and README.md -> Download plus the zero-dependencies bullet
already say so. Repeating it spent the one position a reader looks at first
on a constant, and pushed each notice to two sentences where 2.3 asks for
one.

Removing it leaves 4.1.0 and 4.0.0 stating only their real prerequisite, both
now a single sentence. For 4.2.0 nothing was left: the remainder restated the
three Changed entries directly beneath it, which the categories already sort
by impact, so the notice goes entirely. The four notices that lead with a
genuine delta are untouched.

conventions.md carried the rule that permits the line but not the two limits
that were being broken, so it now names 2.3, says one sentence, and says what
stays out: the baseline install mechanics, and a summary of the entries below
it. A reader who skips a notice must lose nothing.
Minor rather than patch: the gutter fix is a bug fix, but the frame inset
changes where existing output lands on screen, and a named SCA_THEME now
reaches the terminal's own background color, which is state outside the
alternate screen buffer and outlives a hard kill.

The notice names only the background, not the inset. The inset is cosmetic
and its Changed entry carries it; the background is the one thing in this
release a reader would otherwise meet by surprise.
@countzero
countzero merged commit df51044 into main Sep 21, 2026
3 checks passed
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.

1 participant