fix(tui): scrollable inspect screen, masked secrets, working mouse wheel - #84
Merged
Conversation
Ink has no scroll offset, so a viewport can only draw a slice of a flat list and a tree cannot be sliced. Inspect built its context as a nested tree, so everything past the fold was unreachable and the screen's own footer was what got pushed off to make room. All four views — summary, expanded shapes, rendered SQL, render error — are now one element per visual line behind `ScrollPane`. One row must stay one row or the window arithmetic is wrong by the difference. `wrap="truncate"` bounds a cell's width but not its height, so `oneLine` flattens line breaks where text enters a one-row cell: nothing here controls what it displays, and a secret can be a PEM key, an environment variable can hold anything, and a helper's error message can be a multi-line diagnostic. The screen opens one focus scope with `skip` rather than one per phase. React runs a child's effects before its parent's, so a screen-level push lands above its own `SearchableList` and takes the keys the picker was mounted to receive. `$.secrets` reported a key count, which cannot answer what the screen is opened to ask: a stale password and a fresh one are both `Object (7 keys)`. It shows a partial reveal instead, narrowing as the value shortens, with the length beside it as a number rather than encoded in the mask width. Banding counts code points, so a non-BMP character is never sliced through a surrogate pair. `$.env` gets the same treatment — it is the whole of `process.env` and nothing here can tell which keys are credentials. The mouse wheel now scrolls every viewport. It reached only `SelectList` and `ResultTable`, the two `useRowMouse` callers, so the explore detail view, the full-text overlay and the row viewer ignored it. That is worse than unhandled: the TUI runs in the alternate screen, which has no scrollback, and mouse tracking takes the notches a terminal would otherwise translate into arrow keys — turning the mouse on is what removed the only wheel behaviour those panes had. `useWheelScroll` is the wheel-only half of `useRowMouse`, which needs row refs a viewport has none of. Also fixes an error branch that could never render: a helper that failed to load set the error phase with a file selected, which required `!selectedFile`, so the likeliest failure showed as "Unknown phase". Claude-Session: https://claude.ai/code/session_01JGZ8ocdNed7TFFEbccQsW2
damusix
force-pushed
the
fix/inspect-scroll-masked-secrets
branch
from
September 4, 2026 20:15
eb5efa7 to
353f076
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Inspect built its context as a nested tree. Ink has no scroll offset, so a viewport can only draw a slice of a flat list — a tree cannot be sliced, and everything past the fold was unreachable while the screen's own footer got pushed off to make room. All four of its views (summary, expanded shapes, rendered SQL, render error) are now one element per visual line behind the same viewport the explore and SQL screens use.
Two non-obvious consequences: one row must stay one row, so cells truncate and free text is wrapped before Ink sees it; and the screen opens a single focus scope with
skiprather than one per phase, because React runs a child's effects before its parent's, so a screen-level push lands above its ownSearchableListand takes the keys the picker was mounted to receive.$.secretsreported a key count, which cannot tell a stale password from a fresh one. Both secret tiers now show a partial reveal that narrows as the value shortens, with the length beside it as a number rather than encoded in the mask width.$.envgets the same treatment — it is all ofprocess.envand nothing in the screen can tell which of its keys are credentials.Second commit fixes mouse-wheel scrolling, which never worked in any viewport. Only
SelectListandResultTableconsumed wheel notches, so the explore detail view, the full-text overlay and the row viewer ignored them too. Because the TUI runs in the alternate screen (no scrollback) and mouse tracking intercepts the notches a terminal would otherwise translate into arrow keys, enabling the mouse had actively removed the only wheel behaviour those panes had.useWheelScrollsplits the wheel-only half out ofuseRowMouse, which needs row refs a viewport does not have.Also fixes an error branch that could never render: a helper that failed to load showed as "Unknown phase".
Keyboard scrolling was verified working before any of this, so the wheel was the actual gap. The wheel test was confirmed non-vacuous by mutation.
https://claude.ai/code/session_01JGZ8ocdNed7TFFEbccQsW2